]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs
Rollup merge of #102913 - SparrowLii:import-candidate, r=compiler-errors
[rust.git] / src / tools / rust-analyzer / crates / ide-db / src / active_parameter.rs
1 //! This module provides functionality for querying callable information about a token.
2
3 use either::Either;
4 use hir::{Semantics, Type};
5 use syntax::{
6     ast::{self, HasArgList, HasName},
7     AstNode, SyntaxToken,
8 };
9
10 use crate::RootDatabase;
11
12 #[derive(Debug)]
13 pub struct ActiveParameter {
14     pub ty: Type,
15     pub pat: Option<Either<ast::SelfParam, ast::Pat>>,
16 }
17
18 impl ActiveParameter {
19     /// Returns information about the call argument this token is part of.
20     pub fn at_token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Self> {
21         let (signature, active_parameter) = callable_for_token(sema, token)?;
22
23         let idx = active_parameter?;
24         let mut params = signature.params(sema.db);
25         if !(idx < params.len()) {
26             cov_mark::hit!(too_many_arguments);
27             return None;
28         }
29         let (pat, ty) = params.swap_remove(idx);
30         Some(ActiveParameter { ty, pat })
31     }
32
33     pub fn ident(&self) -> Option<ast::Name> {
34         self.pat.as_ref().and_then(|param| match param {
35             Either::Right(ast::Pat::IdentPat(ident)) => ident.name(),
36             _ => None,
37         })
38     }
39 }
40
41 /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable.
42 pub fn callable_for_token(
43     sema: &Semantics<'_, RootDatabase>,
44     token: SyntaxToken,
45 ) -> Option<(hir::Callable, Option<usize>)> {
46     // Find the calling expression and its NameRef
47     let parent = token.parent()?;
48     let calling_node = parent.ancestors().filter_map(ast::CallableExpr::cast).find(|it| {
49         it.arg_list()
50             .map_or(false, |it| it.syntax().text_range().contains(token.text_range().start()))
51     })?;
52
53     callable_for_node(sema, &calling_node, &token)
54 }
55
56 pub fn callable_for_node(
57     sema: &Semantics<'_, RootDatabase>,
58     calling_node: &ast::CallableExpr,
59     token: &SyntaxToken,
60 ) -> Option<(hir::Callable, Option<usize>)> {
61     let callable = match &calling_node {
62         ast::CallableExpr::Call(call) => {
63             let expr = call.expr()?;
64             sema.type_of_expr(&expr)?.adjusted().as_callable(sema.db)
65         }
66         ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
67     }?;
68     let active_param = if let Some(arg_list) = calling_node.arg_list() {
69         let param = arg_list
70             .args()
71             .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
72             .count();
73         Some(param)
74     } else {
75         None
76     };
77     Some((callable, active_param))
78 }