aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/call_info.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/call_info.rs')
-rw-r--r--crates/ra_ide/src/call_info.rs61
1 files changed, 38 insertions, 23 deletions
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 7c6322cb4..2b35a3803 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,48 +1,55 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use hir::db::AstDatabase; 2use hir::Semantics;
3use ra_ide_db::RootDatabase; 3use ra_ide_db::RootDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, ArgListOwner}, 5 ast::{self, ArgListOwner},
6 match_ast, AstNode, SyntaxNode, 6 match_ast, AstNode, SyntaxNode, SyntaxToken,
7}; 7};
8use test_utils::tested_by; 8use test_utils::tested_by;
9 9
10use crate::{expand::descend_into_macros, CallInfo, FilePosition, FunctionSignature}; 10use crate::{CallInfo, FilePosition, FunctionSignature};
11 11
12/// Computes parameter information for the given call expression. 12/// Computes parameter information for the given call expression.
13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
14 let file = db.parse_or_expand(position.file_id.into())?; 14 let sema = Semantics::new(db);
15 let file = sema.parse(position.file_id);
16 let file = file.syntax();
15 let token = file.token_at_offset(position.offset).next()?; 17 let token = file.token_at_offset(position.offset).next()?;
16 let token = descend_into_macros(db, position.file_id, token); 18 let token = sema.descend_into_macros(token);
19 call_info_for_token(&sema, token)
20}
17 21
22pub(crate) fn call_info_for_token(
23 sema: &Semantics<RootDatabase>,
24 token: SyntaxToken,
25) -> Option<CallInfo> {
18 // Find the calling expression and it's NameRef 26 // Find the calling expression and it's NameRef
19 let calling_node = FnCallNode::with_node(&token.value.parent())?; 27 let calling_node = FnCallNode::with_node(&token.parent())?;
20 let name_ref = calling_node.name_ref()?;
21 let name_ref = token.with_value(name_ref.syntax());
22 28
23 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);
24 let (mut call_info, has_self) = match &calling_node { 29 let (mut call_info, has_self) = match &calling_node {
25 FnCallNode::CallExpr(expr) => { 30 FnCallNode::CallExpr(call) => {
26 //FIXME: Type::as_callable is broken 31 //FIXME: Type::as_callable is broken
27 let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; 32 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?;
28 match callable_def { 33 match callable_def {
29 hir::CallableDef::FunctionId(it) => { 34 hir::CallableDef::FunctionId(it) => {
30 let fn_def = it.into(); 35 let fn_def = it.into();
31 (CallInfo::with_fn(db, fn_def), fn_def.has_self_param(db)) 36 (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db))
37 }
38 hir::CallableDef::StructId(it) => {
39 (CallInfo::with_struct(sema.db, it.into())?, false)
32 } 40 }
33 hir::CallableDef::StructId(it) => (CallInfo::with_struct(db, it.into())?, false),
34 hir::CallableDef::EnumVariantId(it) => { 41 hir::CallableDef::EnumVariantId(it) => {
35 (CallInfo::with_enum_variant(db, it.into())?, false) 42 (CallInfo::with_enum_variant(sema.db, it.into())?, false)
36 } 43 }
37 } 44 }
38 } 45 }
39 FnCallNode::MethodCallExpr(expr) => { 46 FnCallNode::MethodCallExpr(method_call) => {
40 let function = analyzer.resolve_method_call(&expr)?; 47 let function = sema.resolve_method_call(&method_call)?;
41 (CallInfo::with_fn(db, function), function.has_self_param(db)) 48 (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db))
42 } 49 }
43 FnCallNode::MacroCallExpr(expr) => { 50 FnCallNode::MacroCallExpr(macro_call) => {
44 let macro_def = analyzer.resolve_macro_call(db, name_ref.with_value(&expr))?; 51 let macro_def = sema.resolve_macro_call(&macro_call)?;
45 (CallInfo::with_macro(db, macro_def)?, false) 52 (CallInfo::with_macro(sema.db, macro_def)?, false)
46 } 53 }
47 }; 54 };
48 55
@@ -62,7 +69,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
62 let num_args_at_callsite = arg_list.args().count(); 69 let num_args_at_callsite = arg_list.args().count();
63 70
64 let arg_list_range = arg_list.syntax().text_range(); 71 let arg_list_range = arg_list.syntax().text_range();
65 if !arg_list_range.contains_inclusive(position.offset) { 72 if !arg_list_range.contains_inclusive(token.text_range().start()) {
66 tested_by!(call_info_bad_offset); 73 tested_by!(call_info_bad_offset);
67 return None; 74 return None;
68 } 75 }
@@ -71,7 +78,9 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
71 num_args_at_callsite, 78 num_args_at_callsite,
72 arg_list 79 arg_list
73 .args() 80 .args()
74 .take_while(|arg| arg.syntax().text_range().end() < position.offset) 81 .take_while(|arg| {
82 arg.syntax().text_range().end() < token.text_range().start()
83 })
75 .count(), 84 .count(),
76 ); 85 );
77 86
@@ -101,7 +110,13 @@ impl FnCallNode {
101 match_ast! { 110 match_ast! {
102 match node { 111 match node {
103 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, 112 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
104 ast::MethodCallExpr(it) => { Some(FnCallNode::MethodCallExpr(it)) }, 113 ast::MethodCallExpr(it) => {
114 let arg_list = it.arg_list()?;
115 if !syntax.text_range().is_subrange(&arg_list.syntax().text_range()) {
116 return None;
117 }
118 Some(FnCallNode::MethodCallExpr(it))
119 },
105 ast::MacroCall(it) => { Some(FnCallNode::MacroCallExpr(it)) }, 120 ast::MacroCall(it) => { Some(FnCallNode::MacroCallExpr(it)) },
106 _ => { None }, 121 _ => { None },
107 } 122 }