diff options
Diffstat (limited to 'crates/ra_ide/src/goto_definition.rs')
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index cfe62037f..27052d72b 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -3,7 +3,9 @@ | |||
3 | use hir::{db::AstDatabase, InFile}; | 3 | use hir::{db::AstDatabase, InFile}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, DocCommentsOwner}, | 5 | ast::{self, DocCommentsOwner}, |
6 | match_ast, AstNode, SyntaxNode, | 6 | match_ast, AstNode, |
7 | SyntaxKind::*, | ||
8 | SyntaxNode, SyntaxToken, TokenAtOffset, | ||
7 | }; | 9 | }; |
8 | 10 | ||
9 | use crate::{ | 11 | use crate::{ |
@@ -19,8 +21,7 @@ pub(crate) fn goto_definition( | |||
19 | position: FilePosition, | 21 | position: FilePosition, |
20 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | 22 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { |
21 | let file = db.parse_or_expand(position.file_id.into())?; | 23 | let file = db.parse_or_expand(position.file_id.into())?; |
22 | let original_token = | 24 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
23 | file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; | ||
24 | let token = descend_into_macros(db, position.file_id, original_token.clone()); | 25 | let token = descend_into_macros(db, position.file_id, original_token.clone()); |
25 | 26 | ||
26 | let nav_targets = match_ast! { | 27 | let nav_targets = match_ast! { |
@@ -38,6 +39,17 @@ pub(crate) fn goto_definition( | |||
38 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) | 39 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) |
39 | } | 40 | } |
40 | 41 | ||
42 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | ||
43 | return tokens.max_by_key(priority); | ||
44 | fn priority(n: &SyntaxToken) -> usize { | ||
45 | match n.kind() { | ||
46 | IDENT | INT_NUMBER => 2, | ||
47 | kind if kind.is_trivia() => 0, | ||
48 | _ => 1, | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
41 | #[derive(Debug)] | 53 | #[derive(Debug)] |
42 | pub(crate) enum ReferenceResult { | 54 | pub(crate) enum ReferenceResult { |
43 | Exact(NavigationTarget), | 55 | Exact(NavigationTarget), |
@@ -235,6 +247,18 @@ mod tests { | |||
235 | } | 247 | } |
236 | 248 | ||
237 | #[test] | 249 | #[test] |
250 | fn goto_definition_works_at_start_of_item() { | ||
251 | check_goto( | ||
252 | " | ||
253 | //- /lib.rs | ||
254 | struct Foo; | ||
255 | enum E { X(<|>Foo) } | ||
256 | ", | ||
257 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
258 | ); | ||
259 | } | ||
260 | |||
261 | #[test] | ||
238 | fn goto_definition_resolves_correct_name() { | 262 | fn goto_definition_resolves_correct_name() { |
239 | check_goto( | 263 | check_goto( |
240 | " | 264 | " |
@@ -435,6 +459,22 @@ mod tests { | |||
435 | } | 459 | } |
436 | 460 | ||
437 | #[test] | 461 | #[test] |
462 | fn goto_for_tuple_fields() { | ||
463 | check_goto( | ||
464 | " | ||
465 | //- /lib.rs | ||
466 | struct Foo(u32); | ||
467 | |||
468 | fn bar() { | ||
469 | let foo = Foo(0); | ||
470 | foo.<|>0; | ||
471 | } | ||
472 | ", | ||
473 | "TUPLE_FIELD_DEF FileId(1) [11; 14)", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
438 | fn goto_definition_works_for_ufcs_inherent_methods() { | 478 | fn goto_definition_works_for_ufcs_inherent_methods() { |
439 | check_goto( | 479 | check_goto( |
440 | " | 480 | " |