Skip to content

collect doc alias as tips during resolution #127721

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
26 changes: 26 additions & 0 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,3 +1285,29 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {

Some(candidates)
}

pub fn collect_doc_alias_symbol_from_attrs<'tcx>(
attrs: impl Iterator<Item = &'tcx ast::Attribute>,
) -> Vec<Symbol> {
let doc_attrs = attrs.filter(|attr| attr.name_or_empty() == sym::doc);
let mut symbols = vec![];
for attr in doc_attrs {
let Some(values) = attr.meta_item_list() else {
continue;
};
let alias_values = values.iter().filter(|v| v.name_or_empty() == sym::alias);
for v in alias_values {
if let Some(nested) = v.meta_item_list() {
// #[doc(alias("foo", "bar"))]
let iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
symbols.extend(iter);
} else if let Some(meta) = v.meta_item()
&& let Some(lit) = meta.name_value_literal()
{
// #[doc(alias = "foo")]
symbols.push(lit.symbol);
}
}
}
symbols
}
40 changes: 11 additions & 29 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::cmp::max;
use std::iter;
use std::ops::Deref;

use rustc_attr::collect_doc_alias_symbol_from_attrs;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
Expand Down Expand Up @@ -1921,9 +1922,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
};
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
let attrs = self.fcx.tcx.hir().attrs(hir_id);

if collect_doc_alias_symbol_from_attrs(attrs.into_iter())
.iter()
.any(|alias| *alias == method.name)
{
return true;
}

for attr in attrs {
if sym::doc == attr.name_or_empty() {
} else if sym::rustc_confusables == attr.name_or_empty() {
if sym::rustc_confusables == attr.name_or_empty() {
let Some(confusables) = attr.meta_item_list() else {
continue;
};
Expand All @@ -1935,35 +1943,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
return true;
}
}
continue;
} else {
continue;
};
let Some(values) = attr.meta_item_list() else {
continue;
};
for v in values {
if v.name_or_empty() != sym::alias {
continue;
}
if let Some(nested) = v.meta_item_list() {
// #[doc(alias("foo", "bar"))]
for n in nested {
if let Some(lit) = n.lit()
&& method.name == lit.symbol
{
return true;
}
}
} else if let Some(meta) = v.meta_item()
&& let Some(lit) = meta.name_value_literal()
&& method.name == lit.symbol
{
// #[doc(alias = "foo")]
return true;
}
}
}

false
}

Expand Down
59 changes: 58 additions & 1 deletion compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_ast::{
Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind,
};
use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
use rustc_attr::collect_doc_alias_symbol_from_attrs;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
Expand Down Expand Up @@ -40,7 +41,7 @@ use crate::late::{
};
use crate::ty::fast_reject::SimplifiedType;
use crate::{
Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors,
Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors,
path_names_to_string,
};

Expand Down Expand Up @@ -459,6 +460,18 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
return (err, Vec::new());
}

if let Some(did) = self.lookup_doc_alias_name(path, source.namespace()) {
err.span_label(
self.r.def_span(did),
format!(
"`{}` has a name defined in the doc alias attribute as `{}`",
self.r.tcx.item_name(did),
path.last().unwrap().ident.as_str()
),
);
return (err, Vec::new());
};

let (found, mut candidates) = self.try_lookup_name_relaxed(
&mut err,
source,
Expand Down Expand Up @@ -783,6 +796,50 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
(false, candidates)
}

fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<DefId> {
let item_str = path.last().unwrap().ident;

let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>| {
for resolution in r.resolutions(m).borrow().values() {
let Some(did) =
resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id())
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;
}
let symbols = collect_doc_alias_symbol_from_attrs(r.tcx.get_attrs(did, sym::doc));
if symbols.contains(&item_str.name) {
return Some(did);
}
}
None
};

if path.len() == 1 {
for rib in self.ribs[ns].iter().rev() {
if let RibKind::Module(module) = rib.kind
&& let Some(did) = find_doc_alias_name(self.r, module)
{
return Some(did);
}
}
} else {
let mod_path = &path[..path.len() - 1];
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), None)
&& let Some(did) = find_doc_alias_name(self.r, module)
{
return Some(did);
}
}
None
}

fn suggest_trait_and_bounds(
&mut self,
err: &mut Diag<'_>,
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/attributes/auxiliary/use-doc-alias-name-extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[doc(alias="DocAliasS1")]
pub struct S1;

#[doc(alias="DocAliasS2")]
#[doc(alias("DocAliasS3", "DocAliasS4"))]
pub struct S2;

#[doc(alias("doc_alias_f1", "doc_alias_f2"))]
pub fn f() {}

pub mod m {
#[doc(alias="DocAliasS5")]
pub struct S5;
}
36 changes: 36 additions & 0 deletions tests/ui/attributes/use-doc-alias-name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//@ aux-build: use-doc-alias-name-extern.rs
//@ error-pattern: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
//@ error-pattern: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
//@ error-pattern: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
//@ error-pattern: `S5` has a name defined in the doc alias attribute as `DocAliasS5`

// issue#124273

extern crate use_doc_alias_name_extern;

use use_doc_alias_name_extern::*;

#[doc(alias="LocalDocAliasS")]
struct S;

fn main() {
LocalDocAliasS;
//~^ ERROR: cannot find value `LocalDocAliasS` in this scope
DocAliasS1;
//~^ ERROR: cannot find value `DocAliasS1` in this scope
DocAliasS2;
//~^ ERROR: cannot find value `DocAliasS2` in this scope
DocAliasS3;
//~^ ERROR: cannot find value `DocAliasS3` in this scope
DocAliasS4;
//~^ ERROR: cannot find value `DocAliasS4` in this scope
doc_alias_f1();
//~^ ERROR: cannot find function `doc_alias_f1` in this scope
doc_alias_f2();
//~^ ERROR: cannot find function `doc_alias_f2` in this scope
m::DocAliasS5;
//~^ ERROR: cannot find value `DocAliasS5` in module `m`
}
86 changes: 86 additions & 0 deletions tests/ui/attributes/use-doc-alias-name.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
error[E0425]: cannot find value `LocalDocAliasS` in this scope
--> $DIR/use-doc-alias-name.rs:20:5
|
LL | LocalDocAliasS;
| ^^^^^^^^^^^^^^ not found in this scope

error[E0425]: cannot find value `DocAliasS1` in this scope
--> $DIR/use-doc-alias-name.rs:22:5
|
LL | DocAliasS1;
| ^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:2:1
|
LL | pub struct S1;
| ------------- `S1` has a name defined in the doc alias attribute as `DocAliasS1`

error[E0425]: cannot find value `DocAliasS2` in this scope
--> $DIR/use-doc-alias-name.rs:24:5
|
LL | DocAliasS2;
| ^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
|
LL | pub struct S2;
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS2`

error[E0425]: cannot find value `DocAliasS3` in this scope
--> $DIR/use-doc-alias-name.rs:26:5
|
LL | DocAliasS3;
| ^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
|
LL | pub struct S2;
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS3`

error[E0425]: cannot find value `DocAliasS4` in this scope
--> $DIR/use-doc-alias-name.rs:28:5
|
LL | DocAliasS4;
| ^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
|
LL | pub struct S2;
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS4`

error[E0425]: cannot find value `DocAliasS5` in module `m`
--> $DIR/use-doc-alias-name.rs:34:8
|
LL | m::DocAliasS5;
| ^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:13:5
|
LL | pub struct S5;
| ------------- `S5` has a name defined in the doc alias attribute as `DocAliasS5`

error[E0425]: cannot find function `doc_alias_f1` in this scope
--> $DIR/use-doc-alias-name.rs:30:5
|
LL | doc_alias_f1();
| ^^^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
|
LL | pub fn f() {}
| ---------- `f` has a name defined in the doc alias attribute as `doc_alias_f1`

error[E0425]: cannot find function `doc_alias_f2` in this scope
--> $DIR/use-doc-alias-name.rs:32:5
|
LL | doc_alias_f2();
| ^^^^^^^^^^^^
|
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
|
LL | pub fn f() {}
| ---------- `f` has a name defined in the doc alias attribute as `doc_alias_f2`

error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0425`.
Loading