Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/nameres.rs')
| -rw-r--r-- | crates/hir-def/src/nameres.rs | 170 |
1 files changed, 111 insertions, 59 deletions
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 3b6e3c5916..fc66d8e28d 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -47,6 +47,7 @@ //! path and, upon success, we run macro expansion and "collect module" phase on //! the result +pub mod assoc; pub mod attr_resolution; mod collector; pub mod diagnostics; @@ -59,30 +60,30 @@ mod tests; use std::ops::Deref; -use base_db::CrateId; +use base_db::Crate; use hir_expand::{ - name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, + EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath, + name::Name, proc_macro::ProcMacroKind, }; use intern::Symbol; use itertools::Itertools; use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID}; +use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID}; use stdx::format_to; -use syntax::{ast, AstNode, SmolStr, SyntaxNode}; +use syntax::{AstNode, SmolStr, SyntaxNode, ToSmolStr, ast}; use triomphe::Arc; use tt::TextRange; use crate::{ + AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap, + LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, db::DefDatabase, item_scope::{BuiltinShadowMode, ItemScope}, item_tree::{ItemTreeId, Mod, TreeId}, nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, - path::ModPath, per_ns::PerNs, visibility::{Visibility, VisibilityExplicitness}, - AstId, BlockId, BlockLoc, CrateRootModuleId, EnumId, EnumVariantId, ExternCrateId, FunctionId, - FxIndexMap, LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId, }; pub use self::path_resolution::ResolvePathResultPrefixInfo; @@ -95,6 +96,39 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[ SmolStr::new_static("rust_analyzer"), ]; +/// Parts of the def map that are only needed when analyzing code in the same crate. +/// +/// There are some data in the def map (e.g. extern prelude) that is only needed when analyzing +/// things in the same crate (and maybe in the IDE layer), e.g. the extern prelude. If we put +/// it in the DefMap dependant DefMaps will be invalidated when they change (e.g. when we add +/// a dependency to the crate). Instead we split them out of the DefMap into a LocalDefMap struct. +/// `crate_local_def_map()` returns both, and `crate_def_map()` returns only the external-relevant +/// DefMap. +#[derive(Debug, PartialEq, Eq, Default)] +pub struct LocalDefMap { + // FIXME: There are probably some other things that could be here, but this is less severe and you + // need to be careful with things that block def maps also have. + /// The extern prelude which contains all root modules of external crates that are in scope. + extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>, +} + +impl LocalDefMap { + pub(crate) const EMPTY: &Self = + &Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) }; + + fn shrink_to_fit(&mut self) { + let Self { extern_prelude } = self; + extern_prelude.shrink_to_fit(); + } + + pub(crate) fn extern_prelude( + &self, + ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ + { + self.extern_prelude.iter().map(|(name, &def)| (name, def)) + } +} + /// Contains the results of (early) name resolution. /// /// A `DefMap` stores the module tree and the definitions that are in scope in every module after @@ -107,7 +141,7 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[ #[derive(Debug, PartialEq, Eq)] pub struct DefMap { /// The crate this `DefMap` belongs to. - krate: CrateId, + krate: Crate, /// When this is a block def map, this will hold the block id of the block and module that /// contains this block. block: Option<BlockInfo>, @@ -124,12 +158,15 @@ pub struct DefMap { /// this contains all kinds of macro, not just `macro_rules!` macro. /// ExternCrateId being None implies it being imported from the general prelude import. macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>, - pub(crate) enum_definitions: FxHashMap<EnumId, Box<[EnumVariantId]>>, + // FIXME: AstId's are fairly unstable /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// attributes. // FIXME: Figure out a better way for the IDE layer to resolve these? derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>, + // FIXME: AstId's are fairly unstable + /// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`]. + pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>, /// The diagnostics that need to be emitted for this crate. diagnostics: Vec<DefDiagnostic>, @@ -141,9 +178,6 @@ pub struct DefMap { /// Data that belongs to a crate which is shared between a crate's def map and all its block def maps. #[derive(Clone, Debug, PartialEq, Eq)] struct DefMapCrateData { - /// The extern prelude which contains all root modules of external crates that are in scope. - extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>, - /// Side table for resolving derive helpers. exported_derives: FxHashMap<MacroDefId, Box<[Name]>>, fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>, @@ -166,7 +200,6 @@ struct DefMapCrateData { impl DefMapCrateData { fn new(edition: Edition) -> Self { Self { - extern_prelude: FxIndexMap::default(), exported_derives: FxHashMap::default(), fn_proc_macro_mapping: FxHashMap::default(), registered_attrs: Vec::new(), @@ -182,7 +215,6 @@ impl DefMapCrateData { fn shrink_to_fit(&mut self) { let Self { - extern_prelude, exported_derives, fn_proc_macro_mapping, registered_attrs, @@ -194,7 +226,6 @@ impl DefMapCrateData { edition: _, recursion_limit: _, } = self; - extern_prelude.shrink_to_fit(); exported_derives.shrink_to_fit(); fn_proc_macro_mapping.shrink_to_fit(); registered_attrs.shrink_to_fit(); @@ -219,11 +250,11 @@ struct BlockRelativeModuleId { } impl BlockRelativeModuleId { - fn def_map(self, db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { + fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> { self.into_module(krate).def_map(db) } - fn into_module(self, krate: CrateId) -> ModuleId { + fn into_module(self, krate: Crate) -> ModuleId { ModuleId { krate, block: self.block, local_id: self.local_id } } @@ -295,18 +326,19 @@ impl ModuleOrigin { /// That is, a file or a `mod foo {}` with items. pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> { match self { - &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => { - let sf = db.parse(definition).tree(); - InFile::new(definition.into(), ModuleSource::SourceFile(sf)) + &ModuleOrigin::File { definition: editioned_file_id, .. } + | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => { + let sf = db.parse(editioned_file_id).tree(); + InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf)) } &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( definition_tree_id.file_id(), ModuleSource::Module( - AstId::new(definition_tree_id.file_id(), definition).to_node(db.upcast()), + AstId::new(definition_tree_id.file_id(), definition).to_node(db), ), ), ModuleOrigin::BlockExpr { block, .. } => { - InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast()))) + InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db))) } } } @@ -334,14 +366,28 @@ impl DefMap { self.data.edition } - pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> { - let crate_graph = db.crate_graph(); - let krate = &crate_graph[crate_id]; - let name = krate.display_name.as_deref().map(Symbol::as_str).unwrap_or_default(); - let _p = tracing::info_span!("crate_def_map_query", ?name).entered(); + pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> { + db.crate_local_def_map(crate_id).0 + } + + pub(crate) fn crate_local_def_map_query( + db: &dyn DefDatabase, + crate_id: Crate, + ) -> (Arc<DefMap>, Arc<LocalDefMap>) { + let krate = crate_id.data(db); + let _p = tracing::info_span!( + "crate_def_map_query", + name=?crate_id + .extra_data(db) + .display_name + .as_ref() + .map(|it| it.crate_name().to_smolstr()) + .unwrap_or_default() + ) + .entered(); let module_data = ModuleData::new( - ModuleOrigin::CrateRoot { definition: krate.root_file_id() }, + ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) }, Visibility::Public, ); @@ -351,10 +397,14 @@ impl DefMap { module_data, None, ); - let def_map = - collector::collect_defs(db, def_map, TreeId::new(krate.root_file_id().into(), None)); + let (def_map, local_def_map) = collector::collect_defs( + db, + def_map, + TreeId::new(krate.root_file_id(db).into(), None), + None, + ); - Arc::new(def_map) + (Arc::new(def_map), Arc::new(local_def_map)) } pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> { @@ -367,10 +417,10 @@ impl DefMap { let module_data = ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility); - let parent_map = module.def_map(db); + let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate); let def_map = DefMap::empty( module.krate, - parent_map.data.clone(), + crate_map.data.clone(), module_data, Some(BlockInfo { block: block_id, @@ -378,13 +428,17 @@ impl DefMap { }), ); - let def_map = - collector::collect_defs(db, def_map, TreeId::new(ast_id.file_id, Some(block_id))); + let (def_map, _) = collector::collect_defs( + db, + def_map, + TreeId::new(ast_id.file_id, Some(block_id)), + Some(crate_local_map), + ); Arc::new(def_map) } fn empty( - krate: CrateId, + krate: Crate, crate_data: Arc<DefMapCrateData>, module_data: ModuleData, block: Option<BlockInfo>, @@ -401,8 +455,8 @@ impl DefMap { macro_use_prelude: FxHashMap::default(), derive_helpers_in_scope: FxHashMap::default(), diagnostics: Vec::new(), - enum_definitions: FxHashMap::default(), data: crate_data, + macro_def_to_macro_id: FxHashMap::default(), } } fn shrink_to_fit(&mut self) { @@ -416,14 +470,14 @@ impl DefMap { krate: _, prelude: _, data: _, - enum_definitions, + macro_def_to_macro_id, } = self; + macro_def_to_macro_id.shrink_to_fit(); macro_use_prelude.shrink_to_fit(); diagnostics.shrink_to_fit(); modules.shrink_to_fit(); derive_helpers_in_scope.shrink_to_fit(); - enum_definitions.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); @@ -432,11 +486,15 @@ impl DefMap { } impl DefMap { - pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { + pub fn modules_for_file<'a>( + &'a self, + db: &'a dyn DefDatabase, + file_id: FileId, + ) -> impl Iterator<Item = LocalModuleId> + 'a { self.modules .iter() .filter(move |(_id, data)| { - data.origin.file_id().map(EditionedFileId::file_id) == Some(file_id) + data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id) }) .map(|(id, _data)| id) } @@ -476,7 +534,7 @@ impl DefMap { self.data.fn_proc_macro_mapping.get(&id).copied() } - pub fn krate(&self) -> CrateId { + pub fn krate(&self) -> Crate { self.krate } @@ -551,12 +609,12 @@ impl DefMap { ) { format_to!(buf, "{}\n", path); - map.modules[module].scope.dump(db.upcast(), buf); + map.modules[module].scope.dump(db, buf); for (name, child) in map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) { - let path = format!("{path}::{}", name.display(db.upcast(), Edition::LATEST)); + let path = format!("{path}::{}", name.display(db, Edition::LATEST)); buf.push('\n'); go(buf, db, map, &path, *child); } @@ -587,19 +645,13 @@ impl DefMap { self.prelude } - pub(crate) fn extern_prelude( - &self, - ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ - { - self.data.extern_prelude.iter().map(|(name, &def)| (name, def)) - } - pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> { &self.macro_use_prelude } pub(crate) fn resolve_path( &self, + local_def_map: &LocalDefMap, db: &dyn DefDatabase, original_module: LocalModuleId, path: &ModPath, @@ -607,6 +659,7 @@ impl DefMap { expected_macro_subns: Option<MacroSubNs>, ) -> (PerNs, Option<usize>) { let res = self.resolve_path_fp_with_macro( + local_def_map, db, ResolveMode::Other, original_module, @@ -621,12 +674,14 @@ impl DefMap { /// points at the unresolved segments. pub(crate) fn resolve_path_locally( &self, + local_def_map: &LocalDefMap, db: &dyn DefDatabase, original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, ) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) { let res = self.resolve_path_fp_with_macro_single( + local_def_map, db, ResolveMode::Other, original_module, @@ -695,17 +750,14 @@ impl ModuleData { &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => { InFile::new( definition.into(), - ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID) - .to_range(db.upcast()), + ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db), ) } &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new( definition_tree_id.file_id(), - AstId::new(definition_tree_id.file_id(), definition).to_range(db.upcast()), + AstId::new(definition_tree_id.file_id(), definition).to_range(db), ), - ModuleOrigin::BlockExpr { block, .. } => { - InFile::new(block.file_id, block.to_range(db.upcast())) - } + ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)), } } @@ -713,7 +765,7 @@ impl ModuleData { /// `None` for the crate root or block. pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> { let decl = self.origin.declaration()?; - let value = decl.to_node(db.upcast()); + let value = decl.to_node(db); Some(InFile { file_id: decl.file_id, value }) } @@ -721,7 +773,7 @@ impl ModuleData { /// `None` for the crate root or block. pub fn declaration_source_range(&self, db: &dyn DefDatabase) -> Option<InFile<TextRange>> { let decl = self.origin.declaration()?; - Some(InFile { file_id: decl.file_id, value: decl.to_range(db.upcast()) }) + Some(InFile { file_id: decl.file_id, value: decl.to_range(db) }) } } |