diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 70baa294f..b693a4c31 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -4,9 +4,8 @@ use std::iter::successors; | |||
4 | 4 | ||
5 | use hir::{db::AstDatabase, Source}; | 5 | use hir::{db::AstDatabase, Source}; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::find_node_at_offset, | ||
8 | ast::{self, DocCommentsOwner}, | 7 | ast::{self, DocCommentsOwner}, |
9 | match_ast, AstNode, SyntaxNode, TextUnit, | 8 | match_ast, AstNode, SyntaxNode, SyntaxToken, |
10 | }; | 9 | }; |
11 | 10 | ||
12 | use crate::{ | 11 | use crate::{ |
@@ -20,37 +19,42 @@ pub(crate) fn goto_definition( | |||
20 | db: &RootDatabase, | 19 | db: &RootDatabase, |
21 | position: FilePosition, | 20 | position: FilePosition, |
22 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | 21 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { |
23 | let offset = descend_into_macros(db, position); | 22 | let token = descend_into_macros(db, position)?; |
24 | 23 | ||
25 | let syntax = db.parse_or_expand(offset.file_id)?; | 24 | let res = match_ast! { |
25 | match (token.ast.parent()) { | ||
26 | ast::NameRef(name_ref) => { | ||
27 | let navs = reference_definition(db, token.with_ast(&name_ref)).to_vec(); | ||
28 | RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec()) | ||
29 | }, | ||
30 | ast::Name(name) => { | ||
31 | let navs = name_definition(db, token.with_ast(&name))?; | ||
32 | RangeInfo::new(name.syntax().text_range(), navs) | ||
26 | 33 | ||
27 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&syntax, offset.ast) { | 34 | }, |
28 | let navs = reference_definition(db, offset.with_ast(&name_ref)).to_vec(); | 35 | _ => return None, |
29 | return Some(RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())); | 36 | } |
30 | } | 37 | }; |
31 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, offset.ast) { | 38 | |
32 | let navs = name_definition(db, offset.with_ast(&name))?; | 39 | Some(res) |
33 | return Some(RangeInfo::new(name.syntax().text_range(), navs)); | ||
34 | } | ||
35 | None | ||
36 | } | 40 | } |
37 | 41 | ||
38 | fn descend_into_macros(db: &RootDatabase, position: FilePosition) -> Source<TextUnit> { | 42 | fn descend_into_macros(db: &RootDatabase, position: FilePosition) -> Option<Source<SyntaxToken>> { |
39 | successors(Some(Source::new(position.file_id.into(), position.offset)), |offset| { | 43 | let file = db.parse_or_expand(position.file_id.into())?; |
40 | let syntax = db.parse_or_expand(offset.file_id)?; | 44 | let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; |
41 | let macro_call = find_node_at_offset::<ast::MacroCall>(&syntax, offset.ast)?; | 45 | |
46 | successors(Some(Source::new(position.file_id.into(), token)), |token| { | ||
47 | let macro_call = token.ast.ancestors().find_map(ast::MacroCall::cast)?; | ||
42 | let tt = macro_call.token_tree()?; | 48 | let tt = macro_call.token_tree()?; |
43 | if !tt.syntax().text_range().contains(offset.ast) { | 49 | if !token.ast.text_range().is_subrange(&tt.syntax().text_range()) { |
44 | return None; | 50 | return None; |
45 | } | 51 | } |
46 | let source_analyzer = | 52 | let source_analyzer = |
47 | hir::SourceAnalyzer::new(db, offset.with_ast(macro_call.syntax()), None); | 53 | hir::SourceAnalyzer::new(db, token.with_ast(token.ast.parent()).as_ref(), None); |
48 | let exp = source_analyzer.expand(db, ¯o_call)?; | 54 | let exp = source_analyzer.expand(db, ¯o_call)?; |
49 | let next_offset = exp.translate_offset(db, offset.ast)?; | 55 | exp.map_token_down(db, token.as_ref()) |
50 | Some(Source::new(exp.file_id(), next_offset)) | ||
51 | }) | 56 | }) |
52 | .last() | 57 | .last() |
53 | .unwrap() | ||
54 | } | 58 | } |
55 | 59 | ||
56 | #[derive(Debug)] | 60 | #[derive(Debug)] |