diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 2327cb1e71b..7d694e1f6e4 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs @@ -1,25 +1,28 @@ //! FIXME: write short doc here -use ra_db::SourceDatabase; +use hir::db::AstDatabase; use ra_syntax::{ast, AstNode}; -use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo}; +use crate::{ + db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget, + RangeInfo, +}; pub(crate) fn goto_type_definition( db: &RootDatabase, position: FilePosition, ) -> Option>> { - let parse = db.parse(position.file_id); + let file = db.parse_or_expand(position.file_id.into())?; + let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; + let token = descend_into_macros(db, position.file_id, token); - let node = parse.tree().syntax().token_at_offset(position.offset).find_map(|token| { + let node = token.ast.ancestors().find_map(|token| { token - .parent() .ancestors() .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some()) })?; - let analyzer = - hir::SourceAnalyzer::new(db, hir::Source::new(position.file_id.into(), &node), None); + let analyzer = hir::SourceAnalyzer::new(db, token.with_ast(&node), None); let ty: hir::Ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) @@ -80,4 +83,23 @@ fn foo() { "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", ); } + + #[test] + fn goto_type_definition_works_through_macro() { + check_goto( + " + //- /lib.rs + macro_rules! id { + ($($tt:tt)*) => { $($tt)* } + } + struct Foo {} + id! { + fn bar() { + let f<|> = Foo {}; + } + } + ", + "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)", + ); + } }