Skip to content
Open
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
52 changes: 52 additions & 0 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Symbol> {
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
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,9 @@ pub struct Resolver<'ra, 'tcx> {

mods_with_parse_errors: FxHashSet<DefId> = default::fx_hash_set(),

// for better error reporting in doc alias for function
doc_aliases: FxHashMap<LocalDefId, FxHashSet<Symbol>> = 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,
Expand Down
33 changes: 33 additions & 0 deletions tests/ui/attributes/doc-alias-attr.rs
Original file line number Diff line number Diff line change
@@ -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`
}
58 changes: 58 additions & 0 deletions tests/ui/attributes/doc-alias-attr.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading