diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 22b9c2b4e37e..3751b9b21f2e 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -1425,7 +1425,20 @@ impl DefCollector<'_> { tracing::warn!("macro expansion is too deep"); return; } - let file_id = macro_call_id.as_file(); + + let loc = macro_call_id.lookup(self.db.upcast()); + let file_id = if loc.def.is_include() { + // If the given macro is an builtin `include!` macro, we expand into the included file. + // So we should collect items within it. + if let Some(it) = loc.include_file_id(self.db.upcast(), macro_call_id) { + it.into() + } else { + // This case the file is not exist. Do not collect items + return; + } + } else { + macro_call_id.as_file() + }; let item_tree = self.db.file_item_tree(file_id); diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index fd6d52d6c9df..0071b129a487 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -104,7 +104,7 @@ use hir_expand::{ }; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{FileId, MacroFileId}; +use span::{EditionedFileId, FileId, MacroFileId}; use stdx::impl_from; use syntax::{ ast::{self, HasName}, @@ -118,6 +118,7 @@ pub(super) struct SourceToDefCache { pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>, expansion_info_cache: FxHashMap, pub(super) file_to_def_cache: FxHashMap>, + included_file_cache: FxHashMap, } impl SourceToDefCache { @@ -163,7 +164,11 @@ impl SourceToDefCtx<'_, '_> { .include_macro_invoc(crate_id) .iter() .filter(|&&(_, file_id)| file_id == file) - .flat_map(|(call, _)| { + .flat_map(|(call, file_id)| { + self.cache + .included_file_cache + .insert(*file_id, MacroFileId { macro_call_id: *call }); + modules( call.lookup(self.db.upcast()) .kind @@ -499,7 +504,12 @@ impl SourceToDefCtx<'_, '_> { let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), None => { - let macro_file = node.file_id.macro_file()?; + let macro_file = if let Some(macro_file) = node.file_id.macro_file() { + macro_file + } else { + let file_id = node.file_id.file_id()?; + *this.cache.included_file_cache.get(&file_id)? + }; let expansion_info = this .cache diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index c61b2ba84f2e..ea7ebaf8566c 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -497,6 +497,49 @@ fn func_in_include() { //^^^^^^^^^^^^^^^ } +fn foo() { + func_in_include$0(); +} +"#, + ); + } + + #[test] + fn goto_def_in_included_file_inside_mod() { + check( + r#" +//- minicore:include +//- /main.rs + +mod a { + include!("b.rs"); +} + +//- /b.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} + +fn foo() { + func_in_include$0(); +} +"#, + ); + + check( + r#" +//- minicore:include +//- /main.rs + +mod a { + include!("a.rs"); +} + +//- /a.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} + fn foo() { func_in_include$0(); } diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 64d717f88ddd..363da51659ee 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -2750,4 +2750,27 @@ impl Foo { "#]], ); } + + #[test] + fn goto_ref_on_included_file() { + check( + r#" +//- minicore:include +//- /lib.rs +include!("foo.rs"); + +fn howdy() { + let _ = FOO; +} + +//- /foo.rs +const FOO$0: i32 = 0; +"#, + expect![[r#" + FOO Const FileId(1) 0..19 6..9 + + FileId(0) 46..49 + "#]], + ); + } }