Skip to content

Commit

Permalink
Merge pull request rust-lang#18967 from Veykril/push-pwonkmwqmmol
Browse files Browse the repository at this point in the history
Properly record meaningful imports as re-exports in symbol index
  • Loading branch information
Veykril authored Jan 20, 2025
2 parents fe034ed + 4193abc commit 1eb9d15
Show file tree
Hide file tree
Showing 25 changed files with 368 additions and 265 deletions.
1 change: 1 addition & 0 deletions src/tools/rust-analyzer/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ dependencies = [
"hir-def",
"hir-expand",
"hir-ty",
"indexmap",
"intern",
"itertools",
"rustc-hash 2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"

[workspace.package]
rust-version = "1.82"
rust-version = "1.83"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
Expand Down
9 changes: 4 additions & 5 deletions src/tools/rust-analyzer/crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ bitflags::bitflags! {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
pub name: Name,
pub items: Vec<(Name, AssocItemId)>,
pub items: Box<[(Name, AssocItemId)]>,
pub flags: TraitFlags,
pub visibility: RawVisibility,
// box it as the vec is usually empty anyways
Expand Down Expand Up @@ -360,7 +360,7 @@ impl TraitAliasData {
pub struct ImplData {
pub target_trait: Option<TraitRef>,
pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>,
pub items: Box<[(Name, AssocItemId)]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
Expand Down Expand Up @@ -393,7 +393,6 @@ impl ImplData {
collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);

let (items, macro_calls, diagnostics) = collector.finish();
let items = items.into_iter().map(|(_, item)| item).collect();

(
Arc::new(ImplData {
Expand Down Expand Up @@ -648,12 +647,12 @@ impl<'a> AssocItemCollector<'a> {
fn finish(
self,
) -> (
Vec<(Name, AssocItemId)>,
Box<[(Name, AssocItemId)]>,
Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
Vec<DefDiagnostic>,
) {
(
self.items,
self.items.into_boxed_slice(),
if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
self.diagnostics,
)
Expand Down
19 changes: 14 additions & 5 deletions src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ impl ItemScope {
.map(move |name| (name, self.get(name)))
}

pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ {
self.values.iter().map(|(n, &i)| (n, i))
}

pub fn types(
&self,
) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrExternCrate>)> + '_ {
self.types.iter().map(|(n, &i)| (n, i))
}

pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ {
self.macros.iter().map(|(n, &i)| (n, i))
}

pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
self.use_imports_types
.keys()
Expand Down Expand Up @@ -263,11 +277,6 @@ impl ItemScope {
self.unnamed_consts.iter().copied()
}

/// Iterate over all module scoped macros
pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
}

/// Iterate over all legacy textual scoped macros visible at the end of the module
pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
self.legacy_macros.iter().map(|(name, def)| (name, &**def))
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl LangItems {
for (_, module_data) in crate_def_map.modules() {
for impl_def in module_data.scope.impls() {
lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
for assoc in db.impl_data(impl_def).items.iter().copied() {
for &(_, assoc) in db.impl_data(impl_def).items.iter() {
match assoc {
AssocItemId::FunctionId(f) => {
lang_items.collect_lang_item(db, f, LangItemTarget::Function)
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir-def/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ impl ModuleId {
}

/// Whether this module represents the crate root module
fn is_crate_root(&self) -> bool {
pub fn is_crate_root(&self) -> bool {
self.local_id == DefMap::ROOT && self.block.is_none()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,8 @@ impl DefCollector<'_> {
}
}
None => {
for (name, def) in root_scope.macros() {
self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
for (name, it) in root_scope.macros() {
self.def_map.macro_use_prelude.insert(name.clone(), (it.def, extern_crate));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,12 @@ impl Visibility {

if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A
return Some(Visibility::Module(mod_a, expl_b));
return Some(Visibility::Module(mod_a, expl_a));
}

if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_b, expl_a));
return Some(Visibility::Module(mod_b, expl_b));
}

None
Expand Down
40 changes: 33 additions & 7 deletions src/tools/rust-analyzer/crates/hir-expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use syntax::utils::is_raw_identifier;
/// and declarations. In theory, names should also carry hygiene info, but we are
/// not there yet!
///
/// Note that the rawness (`r#`) of names does not depend on whether they are written raw.
/// Note that the rawness (`r#`) of names is not preserved. Names are always stored without a `r#` prefix.
/// This is because we want to show (in completions etc.) names as raw depending on the needs
/// of the current crate, for example if it is edition 2021 complete `gen` even if the defining
/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well.
Expand Down Expand Up @@ -77,6 +77,7 @@ impl Name {
/// Hopefully, this should allow us to integrate hygiene cleaner in the
/// future, and to switch to interned representation of names.
fn new_text(text: &str) -> Name {
debug_assert!(!text.starts_with("r#"));
Name { symbol: Symbol::intern(text), ctx: () }
}

Expand All @@ -91,15 +92,34 @@ impl Name {

pub fn new_root(text: &str) -> Name {
// The edition doesn't matter for hygiene.
Self::new(text, SyntaxContextId::root(Edition::Edition2015))
Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
}

pub fn new_tuple_field(idx: usize) -> Name {
Name { symbol: Symbol::intern(&idx.to_string()), ctx: () }
let symbol = match idx {
0 => sym::INTEGER_0.clone(),
1 => sym::INTEGER_1.clone(),
2 => sym::INTEGER_2.clone(),
3 => sym::INTEGER_3.clone(),
4 => sym::INTEGER_4.clone(),
5 => sym::INTEGER_5.clone(),
6 => sym::INTEGER_6.clone(),
7 => sym::INTEGER_7.clone(),
8 => sym::INTEGER_8.clone(),
9 => sym::INTEGER_9.clone(),
10 => sym::INTEGER_10.clone(),
11 => sym::INTEGER_11.clone(),
12 => sym::INTEGER_12.clone(),
13 => sym::INTEGER_13.clone(),
14 => sym::INTEGER_14.clone(),
15 => sym::INTEGER_15.clone(),
_ => Symbol::intern(&idx.to_string()),
};
Name { symbol, ctx: () }
}

pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
Self::new_text(lt.text().as_str().trim_start_matches("r#"))
}

/// Resolve a name from the text of token.
Expand Down Expand Up @@ -142,15 +162,18 @@ impl Name {
}

/// Returns the text this name represents if it isn't a tuple field.
///
/// Do not use this for user-facing text, use `display` instead to handle editions properly.
pub fn as_str(&self) -> &str {
self.symbol.as_str()
}

// FIXME: Remove this
pub fn unescaped(&self) -> UnescapedName<'_> {
UnescapedName(self)
}

pub fn is_escaped(&self, edition: Edition) -> bool {
pub fn needs_escape(&self, edition: Edition) -> bool {
is_raw_identifier(self.symbol.as_str(), edition)
}

Expand All @@ -173,16 +196,19 @@ impl Name {
&self.symbol
}

pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
debug_assert!(!symbol.as_str().starts_with("r#"));
_ = ctx;
Self { symbol, ctx: () }
}

// FIXME: This needs to go once we have hygiene
pub const fn new_symbol_root(sym: Symbol) -> Self {
pub fn new_symbol_root(sym: Symbol) -> Self {
debug_assert!(!sym.as_str().starts_with("r#"));
Self { symbol: sym, ctx: () }
}

// FIXME: Remove this
#[inline]
pub fn eq_ident(&self, ident: &str) -> bool {
self.as_str() == ident.trim_start_matches("r#")
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ fn impl_def_datum(
let associated_ty_value_ids = impl_data
.items
.iter()
.filter_map(|item| match item {
.filter_map(|(_, item)| match item {
AssocItemId::TypeAliasId(type_alias) => Some(*type_alias),
_ => None,
})
Expand Down
26 changes: 12 additions & 14 deletions src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,16 +746,9 @@ fn lookup_impl_assoc_item_for_trait_ref(
let table = InferenceTable::new(db, env);

let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?;
let item = impl_data.items.iter().find_map(|&it| match it {
AssocItemId::FunctionId(f) => {
(db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f))
}
AssocItemId::ConstId(c) => db
.const_data(c)
.name
.as_ref()
.map(|n| n == name)
.and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }),
let item = impl_data.items.iter().find_map(|(n, it)| match *it {
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
AssocItemId::TypeAliasId(_) => None,
})?;
Some((item, impl_subst))
Expand Down Expand Up @@ -850,7 +843,7 @@ fn is_inherent_impl_coherent(
};
rustc_has_incoherent_inherent_impls
&& !impl_data.items.is_empty()
&& impl_data.items.iter().copied().all(|assoc| match assoc {
&& impl_data.items.iter().all(|&(_, assoc)| match assoc {
AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
Expand Down Expand Up @@ -1399,7 +1392,7 @@ fn iterate_inherent_methods(
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
for &impl_id in impls.for_self_ty(self_ty) {
for &item in table.db.impl_data(impl_id).items.iter() {
for &(ref item_name, item) in table.db.impl_data(impl_id).items.iter() {
let visible = match is_valid_impl_method_candidate(
table,
self_ty,
Expand All @@ -1408,6 +1401,7 @@ fn iterate_inherent_methods(
name,
impl_id,
item,
item_name,
) {
IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false,
Expand Down Expand Up @@ -1467,6 +1461,7 @@ fn is_valid_impl_method_candidate(
name: Option<&Name>,
impl_id: ImplId,
item: AssocItemId,
item_name: &Name,
) -> IsValidCandidate {
match item {
AssocItemId::FunctionId(f) => is_valid_impl_fn_candidate(
Expand All @@ -1477,11 +1472,12 @@ fn is_valid_impl_method_candidate(
receiver_ty,
self_ty,
visible_from_module,
item_name,
),
AssocItemId::ConstId(c) => {
let db = table.db;
check_that!(receiver_ty.is_none());
check_that!(name.is_none_or(|n| db.const_data(c).name.as_ref() == Some(n)));
check_that!(name.is_none_or(|n| n == item_name));

if let Some(from_module) = visible_from_module {
if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
Expand Down Expand Up @@ -1565,11 +1561,13 @@ fn is_valid_impl_fn_candidate(
receiver_ty: Option<&Ty>,
self_ty: &Ty,
visible_from_module: Option<ModuleId>,
item_name: &Name,
) -> IsValidCandidate {
check_that!(name.is_none_or(|n| n == item_name));

let db = table.db;
let data = db.function_data(fn_id);

check_that!(name.is_none_or(|n| n == &data.name));
if let Some(from_module) = visible_from_module {
if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) {
cov_mark::hit!(autoderef_candidate_not_visible);
Expand Down
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pub(crate) fn visit_module(
visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
for impl_id in crate_def_map[module_id].scope.impls() {
let impl_data = db.impl_data(impl_id);
for &item in impl_data.items.iter() {
for &(_, item) in impl_data.items.iter() {
match item {
AssocItemId::FunctionId(it) => {
let body = db.body(it.into());
Expand Down
1 change: 1 addition & 0 deletions src/tools/rust-analyzer/crates/hir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ itertools.workspace = true
smallvec.workspace = true
tracing.workspace = true
triomphe.workspace = true
indexmap.workspace = true

# local deps
base-db.workspace = true
Expand Down
Loading

0 comments on commit 1eb9d15

Please sign in to comment.