From 2eaa8c94a8a6b5cd86139c5e010ae95268b28658 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 16 Nov 2019 16:49:26 +0300 Subject: Goto definition works inside macros --- crates/ra_ide_api/src/goto_definition.rs | 50 +++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 10 deletions(-) (limited to 'crates/ra_ide_api') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 821796e5f..4b1581499 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -1,11 +1,10 @@ //! FIXME: write short doc here -use hir::Source; -use ra_db::SourceDatabase; +use hir::{db::AstDatabase, Source}; use ra_syntax::{ algo::find_node_at_offset, ast::{self, DocCommentsOwner}, - match_ast, AstNode, SyntaxNode, + match_ast, AstNode, SyntaxNode, TextUnit, }; use crate::{ @@ -19,17 +18,29 @@ pub(crate) fn goto_definition( db: &RootDatabase, position: FilePosition, ) -> Option>> { - let parse = db.parse(position.file_id); - let syntax = parse.tree().syntax().clone(); - if let Some(name_ref) = find_node_at_offset::(&syntax, position.offset) { - let navs = - reference_definition(db, Source::new(position.file_id.into(), &name_ref)).to_vec(); + go(db, Source::new(position.file_id.into(), position.offset)) +} + +fn go(db: &RootDatabase, offset: Source) -> Option>> { + let syntax = db.parse_or_expand(offset.file_id)?; + + if let Some(name_ref) = find_node_at_offset::(&syntax, offset.ast) { + let navs = reference_definition(db, offset.with_ast(&name_ref)).to_vec(); return Some(RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())); } - if let Some(name) = find_node_at_offset::(&syntax, position.offset) { - let navs = name_definition(db, Source::new(position.file_id.into(), &name))?; + if let Some(name) = find_node_at_offset::(&syntax, offset.ast) { + let navs = name_definition(db, offset.with_ast(&name))?; return Some(RangeInfo::new(name.syntax().text_range(), navs)); } + if let Some(macro_call) = find_node_at_offset::(&syntax, offset.ast) { + let source_analyzer = + hir::SourceAnalyzer::new(db, offset.with_ast(macro_call.syntax()), None); + if let Some(exp) = source_analyzer.expand(db, ¯o_call) { + if let Some(offset) = exp.translate_offset(db, offset.ast) { + return go(db, Source::new(exp.file_id(), offset)); + } + } + } None } @@ -677,4 +688,23 @@ mod tests { "bar MODULE FileId(1) [0; 11) [4; 7)", ); } + + #[test] + fn goto_from_macro() { + check_goto( + " + //- /lib.rs + macro_rules! id { + ($($tt:tt)*) => { $($tt)* } + } + fn foo() {} + id! { + fn bar() { + fo<|>o(); + } + } + ", + "foo FN_DEF FileId(1) [52; 63) [55; 58)", + ); + } } -- cgit v1.2.3