Record import aliases in symbol index

This commit is contained in:
Lukas Wirth 2023-08-18 11:46:35 +02:00
parent 637f496a81
commit eb6244c5f9
10 changed files with 360 additions and 18 deletions

View File

@ -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<ast::UseTree>,
@ -142,11 +142,77 @@ pub fn entries(&self) -> impl Iterator<Item = (&Name, PerNs)> + '_ {
.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<Item = ImportId> + '_ {
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<Item = ModuleDefId> + '_ {
self.declarations.iter().copied()
}

View File

@ -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<ast::UseTree> {
// 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)]

View File

@ -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,

View File

@ -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<ImportOrExternCrate>)>,

View File

@ -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<ChildId> {
type Value;
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
}
impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
type Value = ast::UseTree;
fn child_source(
&self,
db: &dyn DefDatabase,
) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, 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(),
)
}
}

View File

@ -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<DocLinkDef>;
}
#[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),

View File

@ -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

View File

@ -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);
}

View File

@ -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())

View File

@ -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,
},
],
),
]