Skip to content

feat: Record import aliases in symbol index #15477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 70 additions & 4 deletions crates/hir-def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use syntax::ast;

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)]
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -142,11 +142,77 @@ impl ItemScope {
.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()
}
Expand Down
13 changes: 13 additions & 0 deletions crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,19 @@ impl Use {
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)]
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ impl UseTreeLowering<'_> {
}
}

pub(super) fn lower_use_tree(
pub(crate) fn lower_use_tree(
db: &dyn DefDatabase,
hygiene: &Hygiene,
tree: ast::UseTree,
Expand Down
7 changes: 7 additions & 0 deletions crates/hir-def/src/per_ns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ use crate::{
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>)>,
Expand Down
19 changes: 17 additions & 2 deletions crates/hir-def/src/src.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use la_arena::ArenaMap;
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 {
Expand Down Expand Up @@ -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(),
)
}
}
8 changes: 1 addition & 7 deletions crates/hir/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use hir_def::{
attr::{AttrsWithOwner, Documentation},
item_scope::ItemInNs,
path::{ModPath, Path},
per_ns::Namespace,
resolver::{HasResolver, Resolver, TypeNs},
AssocItemId, AttrDefId, GenericParamId, ModuleDefId,
};
Expand All @@ -28,13 +29,6 @@ pub trait HasAttrs {
) -> 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),
Expand Down
3 changes: 2 additions & 1 deletion crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ use triomphe::Arc;
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,
Expand Down Expand Up @@ -122,6 +122,7 @@ pub use {
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
Expand Down
40 changes: 38 additions & 2 deletions crates/hir/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -167,6 +169,40 @@ impl<'a> SymbolCollector<'a> {
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);
}
Expand Down
9 changes: 8 additions & 1 deletion crates/ide-db/src/symbol_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,16 @@ const CONST_WITH_INNER: () = {

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())
Expand Down
Loading