diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 699231fd378..7c11fb9d136 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -16,8 +16,8 @@ use crate::{ db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, - ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId, - UseId, + ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, + TraitId, UseId, }; #[derive(Debug, Default)] @@ -55,7 +55,7 @@ pub enum ImportOrDef { ExternCrate(ExternCrateId), Def(ModuleDefId), } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ImportId { pub import: UseId, pub idx: Idx, @@ -142,11 +142,77 @@ pub fn entries(&self) -> impl Iterator + '_ { .chain(self.values.keys()) .chain(self.macros.keys()) .chain(self.unresolved.iter()) - .sorted() .unique() + .sorted() .map(move |name| (name, self.get(name))) } + pub fn imports(&self) -> impl Iterator + '_ { + self.use_imports_types + .keys() + .copied() + .filter_map(ImportOrExternCrate::into_import) + .chain(self.use_imports_values.keys().copied()) + .chain(self.use_imports_macros.keys().copied()) + .unique() + .sorted() + } + + pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs { + let mut res = PerNs::none(); + + let mut def_map; + let mut scope = self; + while let Some(&m) = scope.use_imports_macros.get(&import) { + match m { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(ModuleDefId::MacroId(def)) => { + res.macros = Some((def, Visibility::Public, None)); + break; + } + _ => break, + } + } + let mut scope = self; + while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) { + match m { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(def) => { + res.types = Some((def, Visibility::Public, None)); + break; + } + _ => break, + } + } + let mut scope = self; + while let Some(&m) = scope.use_imports_values.get(&import) { + match m { + ImportOrDef::Import(i) => { + let module_id = i.import.lookup(db).container; + def_map = module_id.def_map(db); + scope = &def_map[module_id.local_id].scope; + import = i; + } + ImportOrDef::Def(def) => { + res.values = Some((def, Visibility::Public, None)); + break; + } + _ => break, + } + } + res + } + pub fn declarations(&self) -> impl Iterator + '_ { self.declarations.iter().copied() } diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 957a5cf2e2b..3e1922750b9 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -773,6 +773,19 @@ pub fn use_tree_to_ast( lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree"); source_map[index].clone() } + /// Maps a `UseTree` contained in this import back to its AST node. + pub fn use_tree_source_map( + &self, + db: &dyn DefDatabase, + file_id: HirFileId, + ) -> Arena { + // Re-lower the AST item and get the source map. + // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. + let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); + let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); + let hygiene = Hygiene::new(db.upcast(), file_id); + lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree").1 + } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index f8efc802234..e4702c113b8 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -780,7 +780,7 @@ fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree { } } -pub(super) fn lower_use_tree( +pub(crate) fn lower_use_tree( db: &dyn DefDatabase, hygiene: &Hygiene, tree: ast::UseTree, diff --git a/crates/hir-def/src/per_ns.rs b/crates/hir-def/src/per_ns.rs index da9c13740b3..14890364d0b 100644 --- a/crates/hir-def/src/per_ns.rs +++ b/crates/hir-def/src/per_ns.rs @@ -9,6 +9,13 @@ MacroId, ModuleDefId, }; +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +pub enum Namespace { + Types, + Values, + Macros, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct PerNs { pub types: Option<(ModuleDefId, Visibility, Option)>, diff --git a/crates/hir-def/src/src.rs b/crates/hir-def/src/src.rs index 6047f770d4d..3770103cda5 100644 --- a/crates/hir-def/src/src.rs +++ b/crates/hir-def/src/src.rs @@ -5,8 +5,8 @@ use syntax::ast; use crate::{ - db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Macro2Loc, MacroRulesLoc, - ProcMacroLoc, + db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Lookup, Macro2Loc, + MacroRulesLoc, ProcMacroLoc, UseId, }; pub trait HasSource { @@ -83,3 +83,18 @@ pub trait HasChildSource { type Value; fn child_source(&self, db: &dyn DefDatabase) -> InFile>; } + +impl HasChildSource> for UseId { + type Value = ast::UseTree; + fn child_source( + &self, + db: &dyn DefDatabase, + ) -> InFile, Self::Value>> { + let loc = &self.lookup(db); + let use_ = &loc.id.item_tree(db)[loc.id.value]; + InFile::new( + loc.id.file_id(), + use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(), + ) + } +} diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 364405f56a8..121e5a0a249 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -4,6 +4,7 @@ attr::{AttrsWithOwner, Documentation}, item_scope::ItemInNs, path::{ModPath, Path}, + per_ns::Namespace, resolver::{HasResolver, Resolver, TypeNs}, AssocItemId, AttrDefId, GenericParamId, ModuleDefId, }; @@ -28,13 +29,6 @@ fn resolve_doc_path( ) -> Option; } -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] -pub enum Namespace { - Types, - Values, - Macros, -} - /// Subset of `ide_db::Definition` that doc links can resolve to. pub enum DocLinkDef { ModuleDef(ModuleDef), diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 583e26c136c..512fe7e0428 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -88,7 +88,7 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ - attrs::{DocLinkDef, HasAttrs, Namespace}, + attrs::{DocLinkDef, HasAttrs}, diagnostics::{ AnyDiagnostic, BreakOutsideOfLoop, CaseType, ExpectedFunction, InactiveCode, IncoherentImpl, IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, @@ -122,6 +122,7 @@ lang_item::LangItem, nameres::{DefMap, ModuleSource}, path::{ModPath, PathKind}, + per_ns::Namespace, type_ref::{Mutability, TypeRef}, visibility::Visibility, // FIXME: This is here since some queries take it as input that are used diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index 43d957412bc..ca7874c3683 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -2,8 +2,10 @@ use base_db::FileRange; use hir_def::{ - src::HasSource, AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, - ModuleDefId, ModuleId, TraitId, + item_scope::ItemInNs, + src::{HasChildSource, HasSource}, + AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, + TraitId, }; use hir_expand::{HirFileId, InFile}; use hir_ty::db::HirDatabase; @@ -167,6 +169,40 @@ fn collect_from_module(&mut self, module_id: ModuleId) { self.collect_from_impl(impl_id); } + // Record renamed imports. + // In case it imports multiple items under different namespaces we just pick one arbitrarily + // for now. + for id in scope.imports() { + let loc = id.import.lookup(self.db.upcast()); + loc.id.item_tree(self.db.upcast()); + 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 dec_loc = DeclarationLocation { + hir_file_id: source.file_id, + ptr: SyntaxNodePtr::new(use_tree_src.syntax()), + name_ptr: SyntaxNodePtr::new(name.syntax()), + }; + + self.symbols.push(FileSymbol { + name: name.text().into(), + def, + container_name: self.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + }); + }); + } + for const_id in scope.unnamed_consts() { self.collect_from_body(const_id); } diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index ad1ce453eca..f699f999baf 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -419,9 +419,16 @@ mod a_mod { mod b_mod; + +use define_struct as really_define_struct; +use Macro as ItemLikeMacro; +use Macro as Trait; // overlay namespaces //- /b_mod.rs struct StructInModB; - "#, +use super::Macro as SuperItemLikeMacro; +use crate::b_mod::StructInModB as ThisStruct; +use crate::Trait as IsThisJustATrait; +"#, ); let symbols: Vec<_> = Crate::from(db.test_crate()) diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 1a00e29384e..87ad5844c64 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -118,6 +118,35 @@ container_name: None, is_alias: false, }, + FileSymbol { + name: "ItemLikeMacro", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, + ), + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 0, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 654..676, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 663..676, + }, + }, + container_name: None, + is_alias: false, + }, FileSymbol { name: "Macro", def: Macro( @@ -352,6 +381,35 @@ container_name: None, is_alias: false, }, + FileSymbol { + name: "Trait", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, + ), + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 0, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 682..696, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 691..696, + }, + }, + container_name: None, + is_alias: false, + }, FileSymbol { name: "Union", def: Adt( @@ -551,6 +609,35 @@ container_name: None, is_alias: false, }, + FileSymbol { + name: "really_define_struct", + def: Macro( + Macro { + id: MacroRulesId( + MacroRulesId( + 1, + ), + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 0, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 611..648, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 628..648, + }, + }, + container_name: None, + is_alias: false, + }, FileSymbol { name: "trait_fn", def: Function( @@ -631,6 +718,35 @@ }, }, [ + FileSymbol { + name: "IsThisJustATrait", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, + ), + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 1, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 111..143, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 127..143, + }, + }, + container_name: None, + is_alias: false, + }, FileSymbol { name: "StructInModB", def: Adt( @@ -660,6 +776,93 @@ container_name: None, is_alias: false, }, + FileSymbol { + name: "SuperItemLikeMacro", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, + ), + ), + }, + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 1, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 25..59, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 41..59, + }, + }, + container_name: None, + is_alias: false, + }, + FileSymbol { + name: "ThisStruct", + def: Adt( + Struct( + Struct { + id: StructId( + 3, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 1, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 65..105, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 95..105, + }, + }, + container_name: None, + is_alias: false, + }, + FileSymbol { + name: "ThisStruct", + def: Adt( + Struct( + Struct { + id: StructId( + 3, + ), + }, + ), + ), + loc: DeclarationLocation { + hir_file_id: FileId( + FileId( + 1, + ), + ), + ptr: SyntaxNodePtr { + kind: USE_TREE, + range: 65..105, + }, + name_ptr: SyntaxNodePtr { + kind: NAME, + range: 95..105, + }, + }, + container_name: None, + is_alias: false, + }, ], ), ]