Skip to content

Commit

Permalink
collect doc alias as tips during resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
bvanjoi committed Jul 16, 2024
1 parent a91f7d7 commit 762307d
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 30 deletions.
26 changes: 26 additions & 0 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,3 +1239,29 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {

return 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 @@ -4,6 +4,7 @@ use super::MethodError;
use super::NoMatchData;

use crate::FnCtxt;
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 @@ -1827,9 +1828,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.as_str() == name.as_str())
{
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 @@ -1841,35 +1849,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()
&& name.as_str() == lit.symbol.as_str()
{
return true;
}
}
} else if let Some(meta) = v.meta_item()
&& let Some(lit) = meta.name_value_literal()
&& name.as_str() == lit.symbol.as_str()
{
// #[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 @@ -4,9 +4,10 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
use crate::ty::fast_reject::SimplifiedType;
use crate::{errors, path_names_to_string};
use crate::{errors, path_names_to_string, Resolver};
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
use rustc_attr::collect_doc_alias_symbol_from_attrs;
use rustc_hir::def::Namespace::{self, *};

use rustc_ast::ptr::P;
Expand Down Expand Up @@ -452,6 +453,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, '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 @@ -776,6 +789,50 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
return (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<'a, '_>, m: Module<'a>| {
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`.

0 comments on commit 762307d

Please sign in to comment.