Skip to content

Commit 762307d

Browse files
committed
collect doc alias as tips during resolution
1 parent a91f7d7 commit 762307d

File tree

6 files changed

+231
-30
lines changed

6 files changed

+231
-30
lines changed

compiler/rustc_attr/src/builtin.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1239,3 +1239,29 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
12391239

12401240
return Some(candidates);
12411241
}
1242+
1243+
pub fn collect_doc_alias_symbol_from_attrs<'tcx>(
1244+
attrs: impl Iterator<Item = &'tcx ast::Attribute>,
1245+
) -> Vec<Symbol> {
1246+
let doc_attrs = attrs.filter(|attr| attr.name_or_empty() == sym::doc);
1247+
let mut symbols = vec![];
1248+
for attr in doc_attrs {
1249+
let Some(values) = attr.meta_item_list() else {
1250+
continue;
1251+
};
1252+
let alias_values = values.iter().filter(|v| v.name_or_empty() == sym::alias);
1253+
for v in alias_values {
1254+
if let Some(nested) = v.meta_item_list() {
1255+
// #[doc(alias("foo", "bar"))]
1256+
let iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
1257+
symbols.extend(iter);
1258+
} else if let Some(meta) = v.meta_item()
1259+
&& let Some(lit) = meta.name_value_literal()
1260+
{
1261+
// #[doc(alias = "foo")]
1262+
symbols.push(lit.symbol);
1263+
}
1264+
}
1265+
}
1266+
symbols
1267+
}

compiler/rustc_hir_typeck/src/method/probe.rs

+11-29
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::MethodError;
44
use super::NoMatchData;
55

66
use crate::FnCtxt;
7+
use rustc_attr::collect_doc_alias_symbol_from_attrs;
78
use rustc_data_structures::fx::FxHashSet;
89
use rustc_errors::Applicability;
910
use rustc_hir as hir;
@@ -1827,9 +1828,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18271828
};
18281829
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
18291830
let attrs = self.fcx.tcx.hir().attrs(hir_id);
1831+
1832+
if collect_doc_alias_symbol_from_attrs(attrs.into_iter())
1833+
.iter()
1834+
.any(|alias| alias.as_str() == name.as_str())
1835+
{
1836+
return true;
1837+
}
1838+
18301839
for attr in attrs {
1831-
if sym::doc == attr.name_or_empty() {
1832-
} else if sym::rustc_confusables == attr.name_or_empty() {
1840+
if sym::rustc_confusables == attr.name_or_empty() {
18331841
let Some(confusables) = attr.meta_item_list() else {
18341842
continue;
18351843
};
@@ -1841,35 +1849,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18411849
return true;
18421850
}
18431851
}
1844-
continue;
1845-
} else {
1846-
continue;
1847-
};
1848-
let Some(values) = attr.meta_item_list() else {
1849-
continue;
1850-
};
1851-
for v in values {
1852-
if v.name_or_empty() != sym::alias {
1853-
continue;
1854-
}
1855-
if let Some(nested) = v.meta_item_list() {
1856-
// #[doc(alias("foo", "bar"))]
1857-
for n in nested {
1858-
if let Some(lit) = n.lit()
1859-
&& name.as_str() == lit.symbol.as_str()
1860-
{
1861-
return true;
1862-
}
1863-
}
1864-
} else if let Some(meta) = v.meta_item()
1865-
&& let Some(lit) = meta.name_value_literal()
1866-
&& name.as_str() == lit.symbol.as_str()
1867-
{
1868-
// #[doc(alias = "foo")]
1869-
return true;
1870-
}
18711852
}
18721853
}
1854+
18731855
false
18741856
}
18751857

compiler/rustc_resolve/src/late/diagnostics.rs

+58-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
44
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
55
use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
66
use crate::ty::fast_reject::SimplifiedType;
7-
use crate::{errors, path_names_to_string};
7+
use crate::{errors, path_names_to_string, Resolver};
88
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
99
use crate::{PathResult, PathSource, Segment};
10+
use rustc_attr::collect_doc_alias_symbol_from_attrs;
1011
use rustc_hir::def::Namespace::{self, *};
1112

1213
use rustc_ast::ptr::P;
@@ -452,6 +453,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
452453
return (err, Vec::new());
453454
}
454455

456+
if let Some(did) = self.lookup_doc_alias_name(path, source.namespace()) {
457+
err.span_label(
458+
self.r.def_span(did),
459+
format!(
460+
"`{}` has a name defined in the doc alias attribute as `{}`",
461+
self.r.tcx.item_name(did),
462+
path.last().unwrap().ident.as_str()
463+
),
464+
);
465+
return (err, Vec::new());
466+
};
467+
455468
let (found, mut candidates) = self.try_lookup_name_relaxed(
456469
&mut err,
457470
source,
@@ -776,6 +789,50 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
776789
return (false, candidates);
777790
}
778791

792+
fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<DefId> {
793+
let item_str = path.last().unwrap().ident;
794+
795+
let find_doc_alias_name = |r: &mut Resolver<'a, '_>, m: Module<'a>| {
796+
for resolution in r.resolutions(m).borrow().values() {
797+
let Some(did) =
798+
resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id())
799+
else {
800+
continue;
801+
};
802+
if did.is_local() {
803+
// We don't record the doc alias name in the local crate
804+
// because the people who write doc alias are usually not
805+
// confused by them.
806+
continue;
807+
}
808+
let symbols = collect_doc_alias_symbol_from_attrs(r.tcx.get_attrs(did, sym::doc));
809+
if symbols.contains(&item_str.name) {
810+
return Some(did);
811+
}
812+
}
813+
None
814+
};
815+
816+
if path.len() == 1 {
817+
for rib in self.ribs[ns].iter().rev() {
818+
if let RibKind::Module(module) = rib.kind
819+
&& let Some(did) = find_doc_alias_name(self.r, module)
820+
{
821+
return Some(did);
822+
}
823+
}
824+
} else {
825+
let mod_path = &path[..path.len() - 1];
826+
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
827+
self.resolve_path(mod_path, Some(TypeNS), None)
828+
&& let Some(did) = find_doc_alias_name(self.r, module)
829+
{
830+
return Some(did);
831+
}
832+
}
833+
None
834+
}
835+
779836
fn suggest_trait_and_bounds(
780837
&mut self,
781838
err: &mut Diag<'_>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#[doc(alias="DocAliasS1")]
2+
pub struct S1;
3+
4+
#[doc(alias="DocAliasS2")]
5+
#[doc(alias("DocAliasS3", "DocAliasS4"))]
6+
pub struct S2;
7+
8+
#[doc(alias("doc_alias_f1", "doc_alias_f2"))]
9+
pub fn f() {}
10+
11+
pub mod m {
12+
#[doc(alias="DocAliasS5")]
13+
pub struct S5;
14+
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ aux-build: use-doc-alias-name-extern.rs
2+
//@ error-pattern: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
3+
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
4+
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
5+
//@ error-pattern: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
6+
//@ error-pattern: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
7+
//@ error-pattern: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
8+
//@ error-pattern: `S5` has a name defined in the doc alias attribute as `DocAliasS5`
9+
10+
// issue#124273
11+
12+
extern crate use_doc_alias_name_extern;
13+
14+
use use_doc_alias_name_extern::*;
15+
16+
#[doc(alias="LocalDocAliasS")]
17+
struct S;
18+
19+
fn main() {
20+
LocalDocAliasS;
21+
//~^ ERROR: cannot find value `LocalDocAliasS` in this scope
22+
DocAliasS1;
23+
//~^ ERROR: cannot find value `DocAliasS1` in this scope
24+
DocAliasS2;
25+
//~^ ERROR: cannot find value `DocAliasS2` in this scope
26+
DocAliasS3;
27+
//~^ ERROR: cannot find value `DocAliasS3` in this scope
28+
DocAliasS4;
29+
//~^ ERROR: cannot find value `DocAliasS4` in this scope
30+
doc_alias_f1();
31+
//~^ ERROR: cannot find function `doc_alias_f1` in this scope
32+
doc_alias_f2();
33+
//~^ ERROR: cannot find function `doc_alias_f2` in this scope
34+
m::DocAliasS5;
35+
//~^ ERROR: cannot find value `DocAliasS5` in module `m`
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
error[E0425]: cannot find value `LocalDocAliasS` in this scope
2+
--> $DIR/use-doc-alias-name.rs:20:5
3+
|
4+
LL | LocalDocAliasS;
5+
| ^^^^^^^^^^^^^^ not found in this scope
6+
7+
error[E0425]: cannot find value `DocAliasS1` in this scope
8+
--> $DIR/use-doc-alias-name.rs:22:5
9+
|
10+
LL | DocAliasS1;
11+
| ^^^^^^^^^^
12+
|
13+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:2:1
14+
|
15+
LL | pub struct S1;
16+
| ------------- `S1` has a name defined in the doc alias attribute as `DocAliasS1`
17+
18+
error[E0425]: cannot find value `DocAliasS2` in this scope
19+
--> $DIR/use-doc-alias-name.rs:24:5
20+
|
21+
LL | DocAliasS2;
22+
| ^^^^^^^^^^
23+
|
24+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
25+
|
26+
LL | pub struct S2;
27+
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS2`
28+
29+
error[E0425]: cannot find value `DocAliasS3` in this scope
30+
--> $DIR/use-doc-alias-name.rs:26:5
31+
|
32+
LL | DocAliasS3;
33+
| ^^^^^^^^^^
34+
|
35+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
36+
|
37+
LL | pub struct S2;
38+
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS3`
39+
40+
error[E0425]: cannot find value `DocAliasS4` in this scope
41+
--> $DIR/use-doc-alias-name.rs:28:5
42+
|
43+
LL | DocAliasS4;
44+
| ^^^^^^^^^^
45+
|
46+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
47+
|
48+
LL | pub struct S2;
49+
| ------------- `S2` has a name defined in the doc alias attribute as `DocAliasS4`
50+
51+
error[E0425]: cannot find value `DocAliasS5` in module `m`
52+
--> $DIR/use-doc-alias-name.rs:34:8
53+
|
54+
LL | m::DocAliasS5;
55+
| ^^^^^^^^^^
56+
|
57+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:13:5
58+
|
59+
LL | pub struct S5;
60+
| ------------- `S5` has a name defined in the doc alias attribute as `DocAliasS5`
61+
62+
error[E0425]: cannot find function `doc_alias_f1` in this scope
63+
--> $DIR/use-doc-alias-name.rs:30:5
64+
|
65+
LL | doc_alias_f1();
66+
| ^^^^^^^^^^^^
67+
|
68+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
69+
|
70+
LL | pub fn f() {}
71+
| ---------- `f` has a name defined in the doc alias attribute as `doc_alias_f1`
72+
73+
error[E0425]: cannot find function `doc_alias_f2` in this scope
74+
--> $DIR/use-doc-alias-name.rs:32:5
75+
|
76+
LL | doc_alias_f2();
77+
| ^^^^^^^^^^^^
78+
|
79+
::: $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
80+
|
81+
LL | pub fn f() {}
82+
| ---------- `f` has a name defined in the doc alias attribute as `doc_alias_f2`
83+
84+
error: aborting due to 8 previous errors
85+
86+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)