diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index f6d703fd9b..becef49564 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -47,7 +47,7 @@ use hir_def::{ AttrDefId, ConstId, ConstParamId, EnumId, FunctionId, GenericDefId, HasModule, LifetimeParamId, LocalEnumVariantId, LocalFieldId, StaticId, StructId, TypeAliasId, TypeParamId, UnionId, }; -use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind}; +use hir_expand::{name::name, MacroCallKind, MacroDefKind}; use hir_ty::{ autoderef, consteval::ConstExt, @@ -126,7 +126,7 @@ pub use { }, hir_expand::{ name::{known, Name}, - ExpandResult, HirFileId, InFile, MacroFile, Origin, + ExpandResult, HirFileId, InFile, MacroDefId, MacroFile, Origin, }, hir_ty::display::HirDisplay, }; diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 0a2a6719ed..8b5984bf12 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs @@ -44,6 +44,8 @@ pub struct ItemScope { /// The defs declared in this scope. Each def has a single scope where it is /// declared. declarations: Vec, + macro_declarations: Vec, + impls: Vec, unnamed_consts: Vec, /// Traits imported via `use Trait as _;`. @@ -101,6 +103,10 @@ impl ItemScope { self.declarations.iter().copied() } + pub fn macro_declarations(&self) -> impl Iterator + '_ { + self.macro_declarations.iter().copied() + } + pub fn impls(&self) -> impl Iterator + ExactSizeIterator + '_ { self.impls.iter().copied() } @@ -121,7 +127,7 @@ impl ItemScope { } /// Iterate over all legacy textual scoped macros visible at the end of the module - pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator + 'a { + pub fn legacy_macros<'a>(&'a self) -> impl Iterator + 'a { self.legacy_macros.iter().map(|(name, def)| (name, *def)) } @@ -163,6 +169,10 @@ impl ItemScope { self.declarations.push(def) } + pub(crate) fn declare_macro(&mut self, def: MacroDefId) { + self.macro_declarations.push(def); + } + pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option { self.legacy_macros.get(name).copied() } @@ -336,7 +346,8 @@ impl ItemScope { values, macros, unresolved, - declarations: defs, + declarations, + macro_declarations, impls, unnamed_consts, unnamed_trait_imports, @@ -348,7 +359,8 @@ impl ItemScope { values.shrink_to_fit(); macros.shrink_to_fit(); unresolved.shrink_to_fit(); - defs.shrink_to_fit(); + declarations.shrink_to_fit(); + macro_declarations.shrink_to_fit(); impls.shrink_to_fit(); unnamed_consts.shrink_to_fit(); unnamed_trait_imports.shrink_to_fit(); diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index a0210bc503..49d2a7866a 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -632,6 +632,7 @@ impl DefCollector<'_> { ) { let vis = self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); + self.def_map.modules[module_id].scope.declare_macro(macro_); self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named); } @@ -640,6 +641,7 @@ impl DefCollector<'_> { /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. /// And unconditionally exported. fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { + self.def_map.modules[self.def_map.root].scope.declare_macro(macro_); self.update( self.def_map.root, &[(Some(name), PerNs::macros(macro_, Visibility::Public))], diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 3a0dfd066c..53fa3f0881 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs @@ -32,10 +32,12 @@ use base_db::{ salsa::{self, ParallelDatabase}, CrateId, FileId, FileRange, SourceDatabaseExt, SourceRootId, Upcast, }; +use either::Either; use fst::{self, Streamer}; use hir::{ - db::DefDatabase, AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, - DefWithBodyId, HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, ModuleDefId, ModuleId, + db::{DefDatabase, HirDatabase}, + AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, + HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, ModuleDefId, ModuleId, Semantics, TraitId, }; use rayon::prelude::*; @@ -94,7 +96,7 @@ impl Query { } #[salsa::query_group(SymbolsDatabaseStorage)] -pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt { +pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast { fn module_symbols(&self, module_id: ModuleId) -> Arc; fn library_symbols(&self) -> Arc>; /// The set of "local" (that is, from the current workspace) roots. @@ -129,7 +131,7 @@ fn library_symbols(db: &dyn SymbolsDatabase) -> Arc Arc { - let symbols = SymbolCollector::collect(db.upcast(), module_id); + let symbols = SymbolCollector::collect(db, module_id); Arc::new(SymbolIndex::new(symbols)) } @@ -205,10 +207,6 @@ pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec>(); query.search(&buf) } @@ -446,14 +444,16 @@ enum SymbolCollectorWorkItem { } struct SymbolCollector<'a> { - db: &'a dyn DefDatabase, + db: &'a dyn SymbolsDatabase, symbols: Vec, work: Vec, container_name_stack: Vec, } +/// Given a [`ModuleId`] and a [`SymbolsDatabase`], use the DefMap for the module's crate to collect all symbols that should be +/// indexed for the given module. impl<'a> SymbolCollector<'a> { - fn collect(db: &dyn DefDatabase, module_id: ModuleId) -> Vec { + fn collect(db: &dyn SymbolsDatabase, module_id: ModuleId) -> Vec { let mut symbol_collector = SymbolCollector { db, symbols: Default::default(), @@ -486,10 +486,12 @@ impl<'a> SymbolCollector<'a> { } fn collect_from_module(&mut self, module_id: ModuleId) { - let def_map = module_id.def_map(self.db); + let def_map = module_id.def_map(self.db.upcast()); let module_data = &def_map[module_id.local_id]; let scope = &module_data.scope; + dbg!(scope); + for module_def_id in scope.declarations() { match module_def_id { ModuleDefId::ModuleId(id) => self.push_module(id), @@ -531,14 +533,23 @@ impl<'a> SymbolCollector<'a> { self.work.push(SymbolCollectorWorkItem::Body { body: const_id.into() }) } - // todo: collect macros. + // Collect legacy macros from the root module only: + if module_data.parent.is_none() { + for (_, macro_def_id) in scope.legacy_macros() { + self.push_decl_macro(macro_def_id.into()); + } + } + + for macro_def_id in scope.macro_declarations() { + self.push_decl_macro(macro_def_id.into()); + } } fn collect_from_body(&mut self, body_id: DefWithBodyId) { let body = self.db.body(body_id); // Descend into the blocks and enqueue collection of all modules within. - for (_, def_map) in body.blocks(self.db) { + for (_, def_map) in body.blocks(self.db.upcast()) { for (id, _) in def_map.modules() { self.work.push(SymbolCollectorWorkItem::Module { module_id: def_map.module_id(id), @@ -578,15 +589,15 @@ impl<'a> SymbolCollector<'a> { fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option { match body_id { - DefWithBodyId::FunctionId(id) => { - Some(id.lookup(self.db).source(self.db).value.name()?.text().into()) - } - DefWithBodyId::StaticId(id) => { - Some(id.lookup(self.db).source(self.db).value.name()?.text().into()) - } - DefWithBodyId::ConstId(id) => { - Some(id.lookup(self.db).source(self.db).value.name()?.text().into()) - } + DefWithBodyId::FunctionId(id) => Some( + id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), + ), + DefWithBodyId::StaticId(id) => Some( + id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), + ), + DefWithBodyId::ConstId(id) => Some( + id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(), + ), } } @@ -624,11 +635,11 @@ impl<'a> SymbolCollector<'a> { } self.push_file_symbol(|s| { - let loc = id.lookup(s.db); - let source = loc.source(s.db); + let loc = id.lookup(s.db.upcast()); + let source = loc.source(s.db.upcast()); let name_node = source.value.name()?; let container_name = - container_name(s.db, loc.container).or_else(|| s.current_container_name()); + container_name(s.db.upcast(), loc.container).or_else(|| s.current_container_name()); Some(FileSymbol { name: name_node.text().into(), @@ -650,8 +661,8 @@ impl<'a> SymbolCollector<'a> { ::Source: HasName, { self.push_file_symbol(|s| { - let loc = id.lookup(s.db); - let source = loc.source(s.db); + let loc = id.lookup(s.db.upcast()); + let source = loc.source(s.db.upcast()); let name_node = source.value.name()?; Some(FileSymbol { @@ -669,7 +680,7 @@ impl<'a> SymbolCollector<'a> { fn push_module(&mut self, module_id: ModuleId) { self.push_file_symbol(|s| { - let def_map = module_id.def_map(s.db); + let def_map = module_id.def_map(s.db.upcast()); let module_data = &def_map[module_id.local_id]; let declaration = module_data.origin.declaration()?; let module = declaration.to_node(s.db.upcast()); @@ -688,6 +699,29 @@ impl<'a> SymbolCollector<'a> { }) } + pub(crate) fn push_decl_macro(&mut self, macro_def: MacroDef) { + self.push_file_symbol(|s| { + let name = macro_def.name(s.db.upcast())?.as_text()?; + let source = macro_def.source(s.db.upcast())?; + + let (ptr, name_ptr) = match source.value { + Either::Left(m) => { + (SyntaxNodePtr::new(m.syntax()), SyntaxNodePtr::new(m.name()?.syntax())) + } + Either::Right(f) => { + (SyntaxNodePtr::new(f.syntax()), SyntaxNodePtr::new(f.name()?.syntax())) + } + }; + + Some(FileSymbol { + name, + kind: FileSymbolKind::Macro, + container_name: s.current_container_name(), + loc: DeclarationLocation { hir_file_id: source.file_id, name_ptr, ptr }, + }) + }) + } + fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option) { if let Some(file_symbol) = f(self) { self.symbols.push(file_symbol);