Skip to content

Commit 80e3b09

Browse files
committed
collect doc alias as tips during resolution
1 parent ac9ac0e commit 80e3b09

File tree

7 files changed

+263
-32
lines changed

7 files changed

+263
-32
lines changed

compiler/rustc_attr_parsing/src/attributes/util.rs

+30
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,33 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
2626
pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
2727
first_attr_value_str_by_name(attrs, sym::crate_name)
2828
}
29+
30+
pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
31+
attrs: impl Iterator<Item = &'tcx T>,
32+
symbol: Symbol,
33+
) -> bool {
34+
let doc_attrs = attrs.filter(|attr| attr.has_name(sym::doc));
35+
for attr in doc_attrs {
36+
let Some(values) = attr.meta_item_list() else {
37+
continue;
38+
};
39+
let alias_values = values.iter().filter(|v| v.has_name(sym::alias));
40+
for v in alias_values {
41+
if let Some(nested) = v.meta_item_list() {
42+
// #[doc(alias("foo", "bar"))]
43+
let mut iter = nested.iter().filter_map(|item| item.lit()).map(|item| item.symbol);
44+
if iter.any(|s| s == symbol) {
45+
return true;
46+
}
47+
} else if let Some(meta) = v.meta_item()
48+
&& let Some(lit) = meta.name_value_literal()
49+
{
50+
// #[doc(alias = "foo")]
51+
if lit.symbol == symbol {
52+
return true;
53+
}
54+
}
55+
}
56+
}
57+
false
58+
}

compiler/rustc_attr_parsing/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ pub mod parser;
9090
mod session_diagnostics;
9191

9292
pub use attributes::cfg::*;
93-
pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version};
93+
pub use attributes::util::{
94+
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
95+
};
9496
pub use context::{AttributeParser, OmitDoc};
9597
pub use rustc_attr_data_structures::*;
9698

compiler/rustc_hir_typeck/src/method/probe.rs

+7-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::cell::{Cell, RefCell};
22
use std::cmp::max;
33
use std::ops::Deref;
44

5+
use rustc_attr_parsing::is_doc_alias_attrs_contain_symbol;
56
use rustc_data_structures::fx::FxHashSet;
67
use rustc_data_structures::sso::SsoHashSet;
78
use rustc_errors::Applicability;
@@ -2333,10 +2334,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
23332334
};
23342335
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
23352336
let attrs = self.fcx.tcx.hir_attrs(hir_id);
2337+
2338+
if is_doc_alias_attrs_contain_symbol(attrs.into_iter(), method.name) {
2339+
return true;
2340+
}
2341+
23362342
for attr in attrs {
2337-
if attr.has_name(sym::doc) {
2338-
// do nothing
2339-
} else if attr.has_name(sym::rustc_confusables) {
2343+
if attr.has_name(sym::rustc_confusables) {
23402344
let Some(confusables) = attr.meta_item_list() else {
23412345
continue;
23422346
};
@@ -2348,33 +2352,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
23482352
return true;
23492353
}
23502354
}
2351-
continue;
2352-
} else {
2353-
continue;
2354-
};
2355-
let Some(values) = attr.meta_item_list() else {
2356-
continue;
2357-
};
2358-
for v in values {
2359-
if !v.has_name(sym::alias) {
2360-
continue;
2361-
}
2362-
if let Some(nested) = v.meta_item_list() {
2363-
// #[doc(alias("foo", "bar"))]
2364-
for n in nested {
2365-
if let Some(lit) = n.lit()
2366-
&& method.name == lit.symbol
2367-
{
2368-
return true;
2369-
}
2370-
}
2371-
} else if let Some(meta) = v.meta_item()
2372-
&& let Some(lit) = meta.name_value_literal()
2373-
&& method.name == lit.symbol
2374-
{
2375-
// #[doc(alias = "foo")]
2376-
return true;
2377-
}
23782355
}
23792356
}
23802357
false

compiler/rustc_resolve/src/late/diagnostics.rs

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

@@ -477,6 +478,18 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
477478
return (err, Vec::new());
478479
}
479480

481+
if let Some(did) = self.lookup_doc_alias_name(path, source.namespace()) {
482+
err.span_help(
483+
self.r.def_span(did),
484+
format!(
485+
"`{}` has a name defined in the doc alias attribute as `{}`",
486+
self.r.tcx.item_name(did),
487+
path.last().unwrap().ident
488+
),
489+
);
490+
return (err, Vec::new());
491+
};
492+
480493
let (found, suggested_candidates, mut candidates) = self.try_lookup_name_relaxed(
481494
&mut err,
482495
source,
@@ -852,6 +865,51 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
852865
(false, suggested_candidates, candidates)
853866
}
854867

868+
fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<DefId> {
869+
let item = path.last()?.ident;
870+
871+
let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>| {
872+
for resolution in r.resolutions(m).borrow().values() {
873+
let Some(did) =
874+
resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id())
875+
else {
876+
continue;
877+
};
878+
if did.is_local() {
879+
// We don't record the doc alias name in the local crate
880+
// because the people who write doc alias are usually not
881+
// confused by them.
882+
continue;
883+
}
884+
if is_doc_alias_attrs_contain_symbol(r.tcx.get_attrs(did, sym::doc), item.name) {
885+
return Some(did);
886+
}
887+
}
888+
None
889+
};
890+
891+
if path.len() == 1 {
892+
for rib in self.ribs[ns].iter().rev() {
893+
if let RibKind::Module(module) = rib.kind
894+
&& let Some(did) = find_doc_alias_name(self.r, module)
895+
{
896+
return Some(did);
897+
}
898+
}
899+
} else {
900+
let mod_seg = path[path.len() - 2];
901+
if let Some(seg_id) = mod_seg.id
902+
&& let Some(res) = self.r.partial_res_map.get(&seg_id)
903+
&& let hir::def::Res::Def(hir::def::DefKind::Mod, module) = res.base_res()
904+
&& let Some(module) = self.r.get_module(module)
905+
&& let Some(did) = find_doc_alias_name(self.r, module)
906+
{
907+
return Some(did);
908+
}
909+
}
910+
None
911+
}
912+
855913
fn suggest_trait_and_bounds(
856914
&mut self,
857915
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+
}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ aux-build: use-doc-alias-name-extern.rs
2+
3+
// issue#124273
4+
5+
extern crate use_doc_alias_name_extern;
6+
7+
use use_doc_alias_name_extern::*;
8+
9+
#[doc(alias="LocalDocAliasS")]
10+
struct S;
11+
12+
fn main() {
13+
LocalDocAliasS; // don't show help in local crate
14+
//~^ ERROR: cannot find value `LocalDocAliasS` in this scope
15+
16+
DocAliasS1;
17+
//~^ ERROR: cannot find value `DocAliasS1` in this scope
18+
//~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
19+
DocAliasS2;
20+
//~^ ERROR: cannot find value `DocAliasS2` in this scope
21+
//~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
22+
DocAliasS3;
23+
//~^ ERROR: cannot find value `DocAliasS3` in this scope
24+
//~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
25+
DocAliasS4;
26+
//~^ ERROR: cannot find value `DocAliasS4` in this scope
27+
//~| HELP: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
28+
doc_alias_f1();
29+
//~^ ERROR: cannot find function `doc_alias_f1` in this scope
30+
//~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
31+
doc_alias_f2();
32+
//~^ ERROR: cannot find function `doc_alias_f2` in this scope
33+
//~| HELP: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
34+
m::DocAliasS5;
35+
//~^ ERROR: cannot find value `DocAliasS5` in module `m`
36+
//~| HELP: `S5` has a name defined in the doc alias attribute as `DocAliasS5`
37+
}
38+
39+
trait T {
40+
fn f() {
41+
DocAliasS1;
42+
//~^ ERROR: cannot find value `DocAliasS1` in this scope
43+
//~| HELP: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
error[E0425]: cannot find value `LocalDocAliasS` in this scope
2+
--> $DIR/use-doc-alias-name.rs:13:5
3+
|
4+
LL | LocalDocAliasS; // don't show help in local crate
5+
| ^^^^^^^^^^^^^^ not found in this scope
6+
7+
error[E0425]: cannot find value `DocAliasS1` in this scope
8+
--> $DIR/use-doc-alias-name.rs:16:5
9+
|
10+
LL | DocAliasS1;
11+
| ^^^^^^^^^^
12+
|
13+
help: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
14+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:2:1
15+
|
16+
LL | pub struct S1;
17+
| ^^^^^^^^^^^^^
18+
19+
error[E0425]: cannot find value `DocAliasS2` in this scope
20+
--> $DIR/use-doc-alias-name.rs:19:5
21+
|
22+
LL | DocAliasS2;
23+
| ^^^^^^^^^^
24+
|
25+
help: `S2` has a name defined in the doc alias attribute as `DocAliasS2`
26+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
27+
|
28+
LL | pub struct S2;
29+
| ^^^^^^^^^^^^^
30+
31+
error[E0425]: cannot find value `DocAliasS3` in this scope
32+
--> $DIR/use-doc-alias-name.rs:22:5
33+
|
34+
LL | DocAliasS3;
35+
| ^^^^^^^^^^
36+
|
37+
help: `S2` has a name defined in the doc alias attribute as `DocAliasS3`
38+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
39+
|
40+
LL | pub struct S2;
41+
| ^^^^^^^^^^^^^
42+
43+
error[E0425]: cannot find value `DocAliasS4` in this scope
44+
--> $DIR/use-doc-alias-name.rs:25:5
45+
|
46+
LL | DocAliasS4;
47+
| ^^^^^^^^^^
48+
|
49+
help: `S2` has a name defined in the doc alias attribute as `DocAliasS4`
50+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:6:1
51+
|
52+
LL | pub struct S2;
53+
| ^^^^^^^^^^^^^
54+
55+
error[E0425]: cannot find value `DocAliasS5` in module `m`
56+
--> $DIR/use-doc-alias-name.rs:34:8
57+
|
58+
LL | m::DocAliasS5;
59+
| ^^^^^^^^^^
60+
|
61+
help: `S5` has a name defined in the doc alias attribute as `DocAliasS5`
62+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:13:5
63+
|
64+
LL | pub struct S5;
65+
| ^^^^^^^^^^^^^
66+
67+
error[E0425]: cannot find value `DocAliasS1` in this scope
68+
--> $DIR/use-doc-alias-name.rs:41:9
69+
|
70+
LL | DocAliasS1;
71+
| ^^^^^^^^^^
72+
|
73+
help: `S1` has a name defined in the doc alias attribute as `DocAliasS1`
74+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:2:1
75+
|
76+
LL | pub struct S1;
77+
| ^^^^^^^^^^^^^
78+
79+
error[E0425]: cannot find function `doc_alias_f1` in this scope
80+
--> $DIR/use-doc-alias-name.rs:28:5
81+
|
82+
LL | doc_alias_f1();
83+
| ^^^^^^^^^^^^
84+
|
85+
help: `f` has a name defined in the doc alias attribute as `doc_alias_f1`
86+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
87+
|
88+
LL | pub fn f() {}
89+
| ^^^^^^^^^^
90+
91+
error[E0425]: cannot find function `doc_alias_f2` in this scope
92+
--> $DIR/use-doc-alias-name.rs:31:5
93+
|
94+
LL | doc_alias_f2();
95+
| ^^^^^^^^^^^^
96+
|
97+
help: `f` has a name defined in the doc alias attribute as `doc_alias_f2`
98+
--> $DIR/auxiliary/use-doc-alias-name-extern.rs:9:1
99+
|
100+
LL | pub fn f() {}
101+
| ^^^^^^^^^^
102+
103+
error: aborting due to 9 previous errors
104+
105+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)