Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/symbols.rs')
-rw-r--r--crates/hir/src/symbols.rs253
1 files changed, 169 insertions, 84 deletions
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index f8416f86bf..a6b8ed70c3 100644
--- a/crates/hir/src/symbols.rs
+++ b/crates/hir/src/symbols.rs
@@ -1,27 +1,34 @@
//! File symbol extraction.
+use either::Either;
use hir_def::{
db::DefDatabase,
- item_scope::ItemInNs,
+ item_scope::{ImportId, ImportOrExternCrate},
+ per_ns::Item,
src::{HasChildSource, HasSource},
- AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId,
- TraitId,
+ visibility::{Visibility, VisibilityExplicitness},
+ AdtId, AssocItemId, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
+ ModuleDefId, ModuleId, TraitId,
};
-use hir_expand::HirFileId;
+use hir_expand::{name::Name, HirFileId};
use hir_ty::{
db::HirDatabase,
display::{hir_display_with_types_map, HirDisplay},
};
+use intern::Symbol;
+use rustc_hash::FxHashMap;
use span::Edition;
use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
use crate::{Module, ModuleDef, Semantics};
+pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
+
/// The actual data that is stored in the index. It should be as compact as
/// possible.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FileSymbol {
- pub name: SmolStr,
+ pub name: Symbol,
pub def: ModuleDef,
pub loc: DeclarationLocation,
pub container_name: Option<SmolStr>,
@@ -37,7 +44,7 @@ pub struct DeclarationLocation {
/// This points to the whole syntax node of the declaration.
pub ptr: SyntaxNodePtr,
/// This points to the [`syntax::ast::Name`] identifier of the declaration.
- pub name_ptr: AstPtr<syntax::ast::Name>,
+ pub name_ptr: AstPtr<Either<syntax::ast::Name, syntax::ast::NameRef>>,
}
impl DeclarationLocation {
@@ -55,7 +62,7 @@ struct SymbolCollectorWork {
pub struct SymbolCollector<'a> {
db: &'a dyn HirDatabase,
- symbols: Vec<FileSymbol>,
+ symbols: FxIndexSet<FileSymbol>,
work: Vec<SymbolCollectorWork>,
current_container_name: Option<SmolStr>,
edition: Edition,
@@ -86,11 +93,11 @@ impl<'a> SymbolCollector<'a> {
}
}
- pub fn finish(self) -> Vec<FileSymbol> {
- self.symbols
+ pub fn finish(self) -> Box<[FileSymbol]> {
+ self.symbols.into_iter().collect()
}
- pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> {
+ pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
let mut symbol_collector = SymbolCollector::new(db);
symbol_collector.collect(module);
symbol_collector.finish()
@@ -104,96 +111,174 @@ impl<'a> SymbolCollector<'a> {
}
fn collect_from_module(&mut self, module_id: ModuleId) {
- let def_map = module_id.def_map(self.db.upcast());
- let scope = &def_map[module_id.local_id].scope;
-
- for module_def_id in scope.declarations() {
- match module_def_id {
- ModuleDefId::ModuleId(id) => self.push_module(id),
+ let push_decl = |this: &mut Self, def, name| {
+ match def {
+ ModuleDefId::ModuleId(id) => this.push_module(id, name),
ModuleDefId::FunctionId(id) => {
- self.push_decl(id, false);
- self.collect_from_body(id);
+ this.push_decl(id, name, false);
+ this.collect_from_body(id);
}
- ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id, false),
- ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, false),
- ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, false),
+ ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
+ ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
+ ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
ModuleDefId::ConstId(id) => {
- self.push_decl(id, false);
- self.collect_from_body(id);
+ this.push_decl(id, name, false);
+ this.collect_from_body(id);
}
ModuleDefId::StaticId(id) => {
- self.push_decl(id, false);
- self.collect_from_body(id);
+ this.push_decl(id, name, false);
+ this.collect_from_body(id);
}
ModuleDefId::TraitId(id) => {
- self.push_decl(id, false);
- self.collect_from_trait(id);
+ this.push_decl(id, name, false);
+ this.collect_from_trait(id);
}
ModuleDefId::TraitAliasId(id) => {
- self.push_decl(id, false);
+ this.push_decl(id, name, false);
}
ModuleDefId::TypeAliasId(id) => {
- self.push_decl(id, false);
+ this.push_decl(id, name, false);
}
ModuleDefId::MacroId(id) => match id {
- MacroId::Macro2Id(id) => self.push_decl(id, false),
- MacroId::MacroRulesId(id) => self.push_decl(id, false),
- MacroId::ProcMacroId(id) => self.push_decl(id, false),
+ MacroId::Macro2Id(id) => this.push_decl(id, name, false),
+ MacroId::MacroRulesId(id) => this.push_decl(id, name, false),
+ MacroId::ProcMacroId(id) => this.push_decl(id, name, false),
},
// Don't index these.
ModuleDefId::BuiltinType(_) => {}
ModuleDefId::EnumVariantId(_) => {}
}
- }
+ };
- for impl_id in scope.impls() {
- self.collect_from_impl(impl_id);
- }
+ // Nested trees are very common, so a cache here will hit a lot.
+ let import_child_source_cache = &mut FxHashMap::default();
+
+ let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| {
+ let source = import_child_source_cache
+ .entry(i.import)
+ .or_insert_with(|| i.import.child_source(this.db.upcast()));
+ let Some(use_tree_src) = source.value.get(i.idx) else { return };
+ let Some(name_ptr) = use_tree_src
+ .rename()
+ .and_then(|rename| rename.name())
+ .map(Either::Left)
+ .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))
+ .map(|it| AstPtr::new(&it))
+ else {
+ return;
+ };
+ let dec_loc = DeclarationLocation {
+ hir_file_id: source.file_id,
+ ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
+ name_ptr,
+ };
+ this.symbols.insert(FileSymbol {
+ name: name.symbol().clone(),
+ def: def.into(),
+ container_name: this.current_container_name.clone(),
+ loc: dec_loc,
+ is_alias: false,
+ is_assoc: false,
+ });
+ };
- // Record renamed imports.
- // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
- // for now.
- for id in scope.imports() {
- let source = id.import.child_source(self.db.upcast());
- let Some(use_tree_src) = source.value.get(id.idx) else { continue };
- let Some(rename) = use_tree_src.rename() else { continue };
- let Some(name) = rename.name() else { continue };
-
- let res = scope.fully_resolve_import(self.db.upcast(), id);
- res.iter_items().for_each(|(item, _)| {
- let def = match item {
- ItemInNs::Types(def) | ItemInNs::Values(def) => def,
- ItemInNs::Macros(def) => ModuleDefId::from(def),
- }
- .into();
+ let push_extern_crate =
+ |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| {
+ let loc = i.lookup(this.db.upcast());
+ let source = loc.source(this.db.upcast());
+ let Some(name_ptr) = source
+ .value
+ .rename()
+ .and_then(|rename| rename.name())
+ .map(Either::Left)
+ .or_else(|| source.value.name_ref().map(Either::Right))
+ .map(|it| AstPtr::new(&it))
+ else {
+ return;
+ };
let dec_loc = DeclarationLocation {
hir_file_id: source.file_id,
- ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
- name_ptr: AstPtr::new(&name),
+ ptr: SyntaxNodePtr::new(source.value.syntax()),
+ name_ptr,
};
-
- self.symbols.push(FileSymbol {
- name: name.text().into(),
- def,
- container_name: self.current_container_name.clone(),
+ this.symbols.insert(FileSymbol {
+ name: name.symbol().clone(),
+ def: def.into(),
+ container_name: this.current_container_name.clone(),
loc: dec_loc,
is_alias: false,
is_assoc: false,
});
- });
+ };
+
+ let is_explicit_import = |vis| {
+ match vis {
+ Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
+ Visibility::Module(_, VisibilityExplicitness::Implicit) => {
+ // consider imports in the crate root explicit, as these are visibly
+ // crate-wide anyways
+ module_id.is_crate_root()
+ }
+ Visibility::Public => true,
+ }
+ };
+
+ let def_map = module_id.def_map(self.db.upcast());
+ let scope = &def_map[module_id.local_id].scope;
+
+ for impl_id in scope.impls() {
+ self.collect_from_impl(impl_id);
+ }
+
+ for (name, Item { def, vis, import }) in scope.types() {
+ if let Some(i) = import {
+ if is_explicit_import(vis) {
+ match i {
+ ImportOrExternCrate::Import(i) => push_import(self, i, name, def),
+ ImportOrExternCrate::ExternCrate(i) => {
+ push_extern_crate(self, i, name, def)
+ }
+ }
+ }
+ continue;
+ }
+ // self is a declaration
+ push_decl(self, def, name)
+ }
+
+ for (name, Item { def, vis, import }) in scope.macros() {
+ if let Some(i) = import {
+ if is_explicit_import(vis) {
+ push_import(self, i, name, def.into());
+ }
+ continue;
+ }
+ // self is a declaration
+ push_decl(self, def.into(), name)
+ }
+
+ for (name, Item { def, vis, import }) in scope.values() {
+ if let Some(i) = import {
+ if is_explicit_import(vis) {
+ push_import(self, i, name, def);
+ }
+ continue;
+ }
+ // self is a declaration
+ push_decl(self, def, name)
}
for const_id in scope.unnamed_consts() {
self.collect_from_body(const_id);
}
- for (_, id) in scope.legacy_macros() {
+ for (name, id) in scope.legacy_macros() {
for &id in id {
if id.module(self.db.upcast()) == module_id {
match id {
- MacroId::Macro2Id(id) => self.push_decl(id, false),
- MacroId::MacroRulesId(id) => self.push_decl(id, false),
- MacroId::ProcMacroId(id) => self.push_decl(id, false),
+ MacroId::Macro2Id(id) => self.push_decl(id, name, false),
+ MacroId::MacroRulesId(id) => self.push_decl(id, name, false),
+ MacroId::ProcMacroId(id) => self.push_decl(id, name, false),
}
}
}
@@ -223,8 +308,8 @@ impl<'a> SymbolCollector<'a> {
.to_smolstr(),
);
self.with_container_name(impl_name, |s| {
- for &assoc_item_id in impl_data.items.iter() {
- s.push_assoc_item(assoc_item_id)
+ for &(ref name, assoc_item_id) in &impl_data.items {
+ s.push_assoc_item(assoc_item_id, name)
}
})
}
@@ -232,8 +317,8 @@ impl<'a> SymbolCollector<'a> {
fn collect_from_trait(&mut self, trait_id: TraitId) {
let trait_data = self.db.trait_data(trait_id);
self.with_container_name(Some(trait_data.name.as_str().into()), |s| {
- for &(_, assoc_item_id) in &trait_data.items {
- s.push_assoc_item(assoc_item_id);
+ for &(ref name, assoc_item_id) in &trait_data.items {
+ s.push_assoc_item(assoc_item_id, name);
}
});
}
@@ -266,15 +351,15 @@ impl<'a> SymbolCollector<'a> {
}
}
- fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) {
+ fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
match assoc_item_id {
- AssocItemId::FunctionId(id) => self.push_decl(id, true),
- AssocItemId::ConstId(id) => self.push_decl(id, true),
- AssocItemId::TypeAliasId(id) => self.push_decl(id, true),
+ AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
+ AssocItemId::ConstId(id) => self.push_decl(id, name, true),
+ AssocItemId::TypeAliasId(id) => self.push_decl(id, name, true),
}
}
- fn push_decl<'db, L>(&mut self, id: L, is_assoc: bool)
+ fn push_decl<'db, L>(&mut self, id: L, name: &Name, is_assoc: bool)
where
L: Lookup<Database<'db> = dyn DefDatabase + 'db> + Into<ModuleDefId>,
<L as Lookup>::Data: HasSource,
@@ -287,13 +372,13 @@ impl<'a> SymbolCollector<'a> {
let dec_loc = DeclarationLocation {
hir_file_id: source.file_id,
ptr: SyntaxNodePtr::new(source.value.syntax()),
- name_ptr: AstPtr::new(&name_node),
+ name_ptr: AstPtr::new(&name_node).wrap_left(),
};
if let Some(attrs) = def.attrs(self.db) {
for alias in attrs.doc_aliases() {
- self.symbols.push(FileSymbol {
- name: alias.as_str().into(),
+ self.symbols.insert(FileSymbol {
+ name: alias.clone(),
def,
loc: dec_loc.clone(),
container_name: self.current_container_name.clone(),
@@ -303,8 +388,8 @@ impl<'a> SymbolCollector<'a> {
}
}
- self.symbols.push(FileSymbol {
- name: name_node.text().into(),
+ self.symbols.insert(FileSymbol {
+ name: name.symbol().clone(),
def,
container_name: self.current_container_name.clone(),
loc: dec_loc,
@@ -313,7 +398,7 @@ impl<'a> SymbolCollector<'a> {
});
}
- fn push_module(&mut self, module_id: ModuleId) {
+ fn push_module(&mut self, module_id: ModuleId, name: &Name) {
let def_map = module_id.def_map(self.db.upcast());
let module_data = &def_map[module_id.local_id];
let Some(declaration) = module_data.origin.declaration() else { return };
@@ -322,15 +407,15 @@ impl<'a> SymbolCollector<'a> {
let dec_loc = DeclarationLocation {
hir_file_id: declaration.file_id,
ptr: SyntaxNodePtr::new(module.syntax()),
- name_ptr: AstPtr::new(&name_node),
+ name_ptr: AstPtr::new(&name_node).wrap_left(),
};
let def = ModuleDef::Module(module_id.into());
if let Some(attrs) = def.attrs(self.db) {
for alias in attrs.doc_aliases() {
- self.symbols.push(FileSymbol {
- name: alias.as_str().into(),
+ self.symbols.insert(FileSymbol {
+ name: alias.clone(),
def,
loc: dec_loc.clone(),
container_name: self.current_container_name.clone(),
@@ -340,8 +425,8 @@ impl<'a> SymbolCollector<'a> {
}
}
- self.symbols.push(FileSymbol {
- name: name_node.text().into(),
+ self.symbols.insert(FileSymbol {
+ name: name.symbol().clone(),
def: ModuleDef::Module(module_id.into()),
container_name: self.current_container_name.clone(),
loc: dec_loc,