aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-13 15:56:57 +0000
committerAleksey Kladov <[email protected]>2019-01-13 15:56:57 +0000
commiteedc08300c427b854db56f8fe1f1866ed398d5ee (patch)
tree98a579f8c0fd7a0738862937ec32a7dc62172e1a /crates/ra_ide_api
parent884ce4a4207ca68a5299b3a2e4e33b8f1f158001 (diff)
goto defenition works for type-inferred methods
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs51
1 files changed, 49 insertions, 2 deletions
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index e2537758d..332a2fb8d 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -47,15 +47,34 @@ pub(crate) fn reference_definition(
47 name_ref: &ast::NameRef, 47 name_ref: &ast::NameRef,
48) -> Cancelable<ReferenceResult> { 48) -> Cancelable<ReferenceResult> {
49 use self::ReferenceResult::*; 49 use self::ReferenceResult::*;
50 if let Some(fn_descr) = 50 if let Some(function) =
51 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())? 51 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
52 { 52 {
53 let scope = fn_descr.scopes(db)?; 53 let scope = function.scopes(db)?;
54 // First try to resolve the symbol locally 54 // First try to resolve the symbol locally
55 if let Some(entry) = scope.resolve_local_name(name_ref) { 55 if let Some(entry) = scope.resolve_local_name(name_ref) {
56 let nav = NavigationTarget::from_scope_entry(file_id, &entry); 56 let nav = NavigationTarget::from_scope_entry(file_id, &entry);
57 return Ok(Exact(nav)); 57 return Ok(Exact(nav));
58 }; 58 };
59
60 // Next check if it is a method
61 if let Some(method_call) = name_ref
62 .syntax()
63 .parent()
64 .and_then(ast::MethodCallExpr::cast)
65 {
66 let infer_result = function.infer(db)?;
67 let syntax_mapping = function.body_syntax_mapping(db)?;
68 let expr = ast::Expr::cast(method_call.syntax()).unwrap();
69 if let Some(def_id) = syntax_mapping
70 .node_expr(expr)
71 .and_then(|it| infer_result.method_resolution(it))
72 {
73 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)?)? {
74 return Ok(Exact(target));
75 }
76 };
77 }
59 } 78 }
60 // Then try module name resolution 79 // Then try module name resolution
61 if let Some(module) = 80 if let Some(module) =
@@ -167,4 +186,32 @@ mod tests {
167 "foo SOURCE_FILE FileId(2) [0; 10)", 186 "foo SOURCE_FILE FileId(2) [0; 10)",
168 ); 187 );
169 } 188 }
189
190 #[test]
191 fn goto_definition_works_for_methods() {
192 check_goto(
193 "
194 //- /lib.rs
195 struct Foo;
196 impl Foo {
197 fn frobnicate(&self) { }
198 }
199
200 fn bar(foo: &Foo) {
201 foo.frobnicate<|>();
202 }
203 ",
204 "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)",
205 );
206
207 check_goto(
208 "
209 //- /lib.rs
210 mod <|>foo;
211 //- /foo/mod.rs
212 // empty
213 ",
214 "foo SOURCE_FILE FileId(2) [0; 10)",
215 );
216 }
170} 217}