diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 29b5cdb2c8999..5513b19881035 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -14,6 +14,7 @@ use rustc_ast::{ }; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; +use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; use rustc_hir::Attribute; @@ -569,6 +570,52 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } + /// Extracts `#[doc(alias = "...")]` and `#[doc(alias(...))]` from attributes. + /// + /// Uses a lightweight, ad-hoc approach instead of the full attribute parsing + /// machinery to collect aliases for later use in diagnostics. + fn parse_doc_aliases(&self, attrs: &[ast::Attribute]) -> FxHashSet { + let mut aliases = FxHashSet::default(); + + for attr in attrs { + if !attr.has_name(sym::doc) { + continue; + } + + // Get #[doc(...)] list + let Some(items) = attr.meta_item_list() else { + continue; + }; + + for item in items { + let Some(meta) = item.meta_item() else { + continue; + }; + + if !meta.has_name(sym::alias) { + continue; + } + + // Case 1: #[doc(alias = "foo")] + if let Some(value) = meta.value_str() { + aliases.insert(value); + continue; + } + + // Case 2: #[doc(alias("foo", "bar"))] + if let Some(nested) = meta.meta_item_list() { + for nested_item in nested { + if let Some(lit) = nested_item.lit() { + aliases.insert(lit.symbol); + } + } + } + } + } + + aliases + } + fn build_reduced_graph_for_use_tree( &mut self, // This particular use tree @@ -875,6 +922,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Fn(box Fn { ident, .. }) => { self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion); + if !item.attrs.is_empty() { + // for better error reporting in doc alias for function + let aliases = self.parse_doc_aliases(&item.attrs); + self.r.doc_aliases.insert(local_def_id, aliases); + } // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). self.define_macro(item); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7539e3c4f499f..ae8481731f0f3 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1112,11 +1112,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { else { continue; }; - if did.is_local() { - // We don't record the doc alias name in the local crate - // because the people who write doc alias are usually not - // confused by them. - continue; + if let Some(local) = did.as_local() { + if let Some(aliases) = r.doc_aliases.get(&local) + && aliases.contains(&item_name) + { + return Some(did); + } else { + continue; + } } if let Some(d) = hir::find_attr!(r.tcx, did, Doc(d) => d) && d.aliases.contains_key(&item_name) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d75f2981a7724..e77919cd6acf0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1404,6 +1404,9 @@ pub struct Resolver<'ra, 'tcx> { mods_with_parse_errors: FxHashSet = default::fx_hash_set(), + // for better error reporting in doc alias for function + doc_aliases: FxHashMap> = default::fx_hash_map(), + /// Whether `Resolver::register_macros_for_all_crates` has been called once already, as we /// don't need to run it more than once. all_crate_macros_already_registered: bool = false, diff --git a/tests/ui/attributes/doc-alias-attr.rs b/tests/ui/attributes/doc-alias-attr.rs new file mode 100644 index 0000000000000..76105073876de --- /dev/null +++ b/tests/ui/attributes/doc-alias-attr.rs @@ -0,0 +1,33 @@ +#[doc(alias = "bar")] +fn foo() {} + +#[doc(alias("sum", "plus"))] +fn net() {} + +struct S; + +impl S { + #[doc(alias("bar"))] + fn foo() {} + + #[doc(alias= "baz")] + fn qux(&self, x: i32) {} +} + + +fn main() { + S::bar(); + //~^ ERROR no associated function or constant named `bar` found for struct `S` in the current scope + //~| HELP there is an associated function `foo` with a similar name + + let s = S; + s.baz(10); + //~^ ERROR no method named `baz` + //~| HELP there is a method `qux` with a similar name + + sum(); //~ ERROR: cannot find function `sum` in this scope + //~| HELP: `net` has a name defined in the doc alias attribute as `sum` + + bar(); //~ ERROR: cannot find function `bar` in this scope + //~| HELP: `foo` has a name defined in the doc alias attribute as `bar` +} diff --git a/tests/ui/attributes/doc-alias-attr.stderr b/tests/ui/attributes/doc-alias-attr.stderr new file mode 100644 index 0000000000000..8576864e3a12f --- /dev/null +++ b/tests/ui/attributes/doc-alias-attr.stderr @@ -0,0 +1,58 @@ +error[E0599]: no associated function or constant named `bar` found for struct `S` in the current scope + --> $DIR/doc-alias-attr.rs:19:8 + | +LL | struct S; + | -------- associated function or constant `bar` not found for this struct +... +LL | S::bar(); + | ^^^ associated function or constant not found in `S` + | +help: there is an associated function `foo` with a similar name + | +LL - S::bar(); +LL + S::foo(); + | + +error[E0599]: no method named `baz` found for struct `S` in the current scope + --> $DIR/doc-alias-attr.rs:24:7 + | +LL | struct S; + | -------- method `baz` not found for this struct +... +LL | s.baz(10); + | ^^^ + | +help: there is a method `qux` with a similar name + | +LL - s.baz(10); +LL + s.qux(10); + | + +error[E0425]: cannot find function `sum` in this scope + --> $DIR/doc-alias-attr.rs:28:5 + | +LL | sum(); + | ^^^ + | +help: `net` has a name defined in the doc alias attribute as `sum` + | +LL - sum(); +LL + net(); + | + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/doc-alias-attr.rs:31:5 + | +LL | bar(); + | ^^^ + | +help: `foo` has a name defined in the doc alias attribute as `bar` + | +LL - bar(); +LL + foo(); + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`.