Skip to content

Commit c5f9423

Browse files
committed
collect doc alias as tips during resolution
1 parent 2aa26d8 commit c5f9423

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
@@ -1285,3 +1285,29 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
12851285

12861286
Some(candidates)
12871287
}
1288+
1289+
pub fn collect_doc_alias_symbol_from_attrs<'tcx>(
1290+
attrs: impl Iterator<Item = &'tcx ast::Attribute>,
1291+
) -> Vec<Symbol> {
1292+
let doc_attrs = attrs.filter(|attr| attr.name_or_empty() == sym::doc);
1293+
let mut symbols = vec![];
1294+
for attr in doc_attrs {
1295+
let Some(values) = attr.meta_item_list() else {
1296+
continue;
1297+
};
1298+
let alias_values = values.iter().filter(|v| v.name_or_empty() == sym::alias);
1299+
for v in alias_values {
1300+
if let Some(nested) = v.meta_item_list() {
1301+
// #[doc(alias("foo", "bar"))]
1302+
let iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
1303+
symbols.extend(iter);
1304+
} else if let Some(meta) = v.meta_item()
1305+
&& let Some(lit) = meta.name_value_literal()
1306+
{
1307+
// #[doc(alias = "foo")]
1308+
symbols.push(lit.symbol);
1309+
}
1310+
}
1311+
}
1312+
symbols
1313+
}

compiler/rustc_hir_typeck/src/method/probe.rs

+11-29
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::cmp::max;
33
use std::iter;
44
use std::ops::Deref;
55

6+
use rustc_attr::collect_doc_alias_symbol_from_attrs;
67
use rustc_data_structures::fx::FxHashSet;
78
use rustc_errors::Applicability;
89
use rustc_hir as hir;
@@ -1921,9 +1922,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19211922
};
19221923
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
19231924
let attrs = self.fcx.tcx.hir().attrs(hir_id);
1925+
1926+
if collect_doc_alias_symbol_from_attrs(attrs.into_iter())
1927+
.iter()
1928+
.any(|alias| *alias == method.name)
1929+
{
1930+
return true;
1931+
}
1932+
19241933
for attr in attrs {
1925-
if sym::doc == attr.name_or_empty() {
1926-
} else if sym::rustc_confusables == attr.name_or_empty() {
1934+
if sym::rustc_confusables == attr.name_or_empty() {
19271935
let Some(confusables) = attr.meta_item_list() else {
19281936
continue;
19291937
};
@@ -1935,35 +1943,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
19351943
return true;
19361944
}
19371945
}
1938-
continue;
1939-
} else {
1940-
continue;
1941-
};
1942-
let Some(values) = attr.meta_item_list() else {
1943-
continue;
1944-
};
1945-
for v in values {
1946-
if v.name_or_empty() != sym::alias {
1947-
continue;
1948-
}
1949-
if let Some(nested) = v.meta_item_list() {
1950-
// #[doc(alias("foo", "bar"))]
1951-
for n in nested {
1952-
if let Some(lit) = n.lit()
1953-
&& method.name == lit.symbol
1954-
{
1955-
return true;
1956-
}
1957-
}
1958-
} else if let Some(meta) = v.meta_item()
1959-
&& let Some(lit) = meta.name_value_literal()
1960-
&& method.name == lit.symbol
1961-
{
1962-
// #[doc(alias = "foo")]
1963-
return true;
1964-
}
19651946
}
19661947
}
1948+
19671949
false
19681950
}
19691951

compiler/rustc_resolve/src/late/diagnostics.rs

+58-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_ast::{
1111
Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind,
1212
};
1313
use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
14+
use rustc_attr::collect_doc_alias_symbol_from_attrs;
1415
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
1516
use rustc_errors::codes::*;
1617
use rustc_errors::{
@@ -40,7 +41,7 @@ use crate::late::{
4041
};
4142
use crate::ty::fast_reject::SimplifiedType;
4243
use crate::{
43-
Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Segment, errors,
44+
Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors,
4445
path_names_to_string,
4546
};
4647

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

463+
if let Some(did) = self.lookup_doc_alias_name(path, source.namespace()) {
464+
err.span_label(
465+
self.r.def_span(did),
466+
format!(
467+
"`{}` has a name defined in the doc alias attribute as `{}`",
468+
self.r.tcx.item_name(did),
469+
path.last().unwrap().ident.as_str()
470+
),
471+
);
472+
return (err, Vec::new());
473+
};
474+
462475
let (found, mut candidates) = self.try_lookup_name_relaxed(
463476
&mut err,
464477
source,
@@ -783,6 +796,50 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
783796
(false, candidates)
784797
}
785798

799+
fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<DefId> {
800+
let item_str = path.last().unwrap().ident;
801+
802+
let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>| {
803+
for resolution in r.resolutions(m).borrow().values() {
804+
let Some(did) =
805+
resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id())
806+
else {
807+
continue;
808+
};
809+
if did.is_local() {
810+
// We don't record the doc alias name in the local crate
811+
// because the people who write doc alias are usually not
812+
// confused by them.
813+
continue;
814+
}
815+
let symbols = collect_doc_alias_symbol_from_attrs(r.tcx.get_attrs(did, sym::doc));
816+
if symbols.contains(&item_str.name) {
817+
return Some(did);
818+
}
819+
}
820+
None
821+
};
822+
823+
if path.len() == 1 {
824+
for rib in self.ribs[ns].iter().rev() {
825+
if let RibKind::Module(module) = rib.kind
826+
&& let Some(did) = find_doc_alias_name(self.r, module)
827+
{
828+
return Some(did);
829+
}
830+
}
831+
} else {
832+
let mod_path = &path[..path.len() - 1];
833+
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
834+
self.resolve_path(mod_path, Some(TypeNS), None)
835+
&& let Some(did) = find_doc_alias_name(self.r, module)
836+
{
837+
return Some(did);
838+
}
839+
}
840+
None
841+
}
842+
786843
fn suggest_trait_and_bounds(
787844
&mut self,
788845
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)