diff options
author | Aleksey Kladov <[email protected]> | 2019-01-13 15:56:57 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-13 15:56:57 +0000 |
commit | eedc08300c427b854db56f8fe1f1866ed398d5ee (patch) | |
tree | 98a579f8c0fd7a0738862937ec32a7dc62172e1a /crates/ra_ide_api/src/goto_definition.rs | |
parent | 884ce4a4207ca68a5299b3a2e4e33b8f1f158001 (diff) |
goto defenition works for type-inferred methods
Diffstat (limited to 'crates/ra_ide_api/src/goto_definition.rs')
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 51 |
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 | } |