Skip to content

Commit 8e0e925

Browse files
committed
Disallow linking to items with a mismatched disambiguator
1 parent f042d74 commit 8e0e925

File tree

3 files changed

+223
-2
lines changed

3 files changed

+223
-2
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -574,9 +574,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
574574
};
575575
let resolved_self;
576576
let mut path_str;
577+
let mut disambiguator = None;
577578
let (res, fragment) = {
578579
let mut kind = None;
579-
let mut disambiguator = None;
580580
path_str = if let Some(prefix) =
581581
["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
582582
.iter()
@@ -595,6 +595,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
595595
link.trim_start_matches(prefix)
596596
} else if link.ends_with("!()") {
597597
kind = Some(MacroNS);
598+
disambiguator = Some("bang");
598599
link.trim_end_matches("!()")
599600
} else if link.ends_with("()") {
600601
kind = Some(ValueNS);
@@ -610,7 +611,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
610611
link.trim_start_matches("derive@")
611612
} else if link.ends_with('!') {
612613
kind = Some(MacroNS);
613-
disambiguator = Some("macro");
614+
disambiguator = Some("bang");
614615
link.trim_end_matches('!')
615616
} else {
616617
&link[..]
@@ -789,6 +790,46 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
789790
} else {
790791
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
791792

793+
// Disallow e.g. linking to enums with `struct@`
794+
if let Res::Def(kind, id) = res {
795+
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
796+
// NOTE: this relies on the fact that `''` is never parsed as a disambiguator
797+
// NOTE: this needs to be kept in sync with the disambiguator parsing
798+
match (kind, disambiguator.unwrap_or_default().trim_end_matches("@")) {
799+
| (DefKind::Struct, "struct")
800+
| (DefKind::Enum, "enum")
801+
| (DefKind::Trait, "trait")
802+
| (DefKind::Union, "union")
803+
| (DefKind::Mod, "mod" | "module")
804+
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, "const")
805+
| (DefKind::Static, "static")
806+
// NOTE: this allows 'method' to mean both normal functions and associated functions
807+
// This can't cause ambiguity because both are in the same namespace.
808+
| (DefKind::Fn | DefKind::AssocFn, "fn" | "function" | "method")
809+
| (DefKind::Macro(MacroKind::Bang), "bang")
810+
| (DefKind::Macro(MacroKind::Derive), "derive")
811+
// These are namespaces; allow anything in the namespace to match
812+
| (_, "type" | "macro" | "value")
813+
// If no disambiguator given, allow anything
814+
| (_, "")
815+
// All of these are valid, so do nothing
816+
=> {}
817+
(_, disambiguator) => {
818+
// The resolved item did not match the disambiguator; give a better error than 'not found'
819+
let msg = format!("unresolved link to `{}`", path_str);
820+
report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| {
821+
let msg = format!("this item resolved to {} {}, which did not match the disambiguator '{}'", kind.article(), kind.descr(id), disambiguator);
822+
if let Some(sp) = sp {
823+
diag.span_note(sp, &msg);
824+
} else {
825+
diag.note(&msg);
826+
}
827+
});
828+
continue;
829+
}
830+
}
831+
}
832+
792833
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
793834
if let Some((src_id, dst_id)) = res
794835
.opt_def_id()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#![deny(broken_intra_doc_links)]
2+
//~^ NOTE lint level is defined
3+
pub enum S {}
4+
5+
macro_rules! m {
6+
() => {};
7+
}
8+
9+
static s: usize = 0;
10+
const c: usize = 0;
11+
12+
trait T {}
13+
14+
/// Link to [struct@S]
15+
//~^ ERROR unresolved link to `S`
16+
//~| NOTE did not match
17+
18+
/// Link to [mod@S]
19+
//~^ ERROR unresolved link to `S`
20+
//~| NOTE did not match
21+
22+
/// Link to [union@S]
23+
//~^ ERROR unresolved link to `S`
24+
//~| NOTE did not match
25+
26+
/// Link to [trait@S]
27+
//~^ ERROR unresolved link to `S`
28+
//~| NOTE did not match
29+
30+
/// Link to [struct@T]
31+
//~^ ERROR unresolved link to `T`
32+
//~| NOTE did not match
33+
34+
/// Link to [derive@m]
35+
//~^ ERROR unresolved link to `m`
36+
//~| NOTE did not match
37+
38+
/// Link to [const@s]
39+
//~^ ERROR unresolved link to `s`
40+
//~| NOTE did not match
41+
42+
/// Link to [static@c]
43+
//~^ ERROR unresolved link to `c`
44+
//~| NOTE did not match
45+
46+
/// Link to [fn@c]
47+
//~^ ERROR unresolved link to `c`
48+
//~| NOTE did not match
49+
50+
/// Link to [c()]
51+
//~^ ERROR unresolved link to `c`
52+
//~| NOTE did not match
53+
pub fn f() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
error: unresolved link to `S`
2+
--> $DIR/intra-links-disambiguator-mismatch.rs:16:14
3+
|
4+
LL | /// Link to [struct@S]
5+
| ^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/intra-links-disambiguator-mismatch.rs:1:9
9+
|
10+
LL | #![deny(broken_intra_doc_links)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
note: this item resolved to an enum, which did not match the disambiguator 'struct'
13+
--> $DIR/intra-links-disambiguator-mismatch.rs:16:14
14+
|
15+
LL | /// Link to [struct@S]
16+
| ^^^^^^^^
17+
18+
error: unresolved link to `S`
19+
--> $DIR/intra-links-disambiguator-mismatch.rs:20:14
20+
|
21+
LL | /// Link to [mod@S]
22+
| ^^^^^
23+
|
24+
note: this item resolved to an enum, which did not match the disambiguator 'mod'
25+
--> $DIR/intra-links-disambiguator-mismatch.rs:20:14
26+
|
27+
LL | /// Link to [mod@S]
28+
| ^^^^^
29+
30+
error: unresolved link to `S`
31+
--> $DIR/intra-links-disambiguator-mismatch.rs:24:14
32+
|
33+
LL | /// Link to [union@S]
34+
| ^^^^^^^
35+
|
36+
note: this item resolved to an enum, which did not match the disambiguator 'union'
37+
--> $DIR/intra-links-disambiguator-mismatch.rs:24:14
38+
|
39+
LL | /// Link to [union@S]
40+
| ^^^^^^^
41+
42+
error: unresolved link to `S`
43+
--> $DIR/intra-links-disambiguator-mismatch.rs:28:14
44+
|
45+
LL | /// Link to [trait@S]
46+
| ^^^^^^^
47+
|
48+
note: this item resolved to an enum, which did not match the disambiguator 'trait'
49+
--> $DIR/intra-links-disambiguator-mismatch.rs:28:14
50+
|
51+
LL | /// Link to [trait@S]
52+
| ^^^^^^^
53+
54+
error: unresolved link to `T`
55+
--> $DIR/intra-links-disambiguator-mismatch.rs:32:14
56+
|
57+
LL | /// Link to [struct@T]
58+
| ^^^^^^^^
59+
|
60+
note: this item resolved to a trait, which did not match the disambiguator 'struct'
61+
--> $DIR/intra-links-disambiguator-mismatch.rs:32:14
62+
|
63+
LL | /// Link to [struct@T]
64+
| ^^^^^^^^
65+
66+
error: unresolved link to `m`
67+
--> $DIR/intra-links-disambiguator-mismatch.rs:36:14
68+
|
69+
LL | /// Link to [derive@m]
70+
| ^^^^^^^^
71+
|
72+
note: this item resolved to a macro, which did not match the disambiguator 'derive'
73+
--> $DIR/intra-links-disambiguator-mismatch.rs:36:14
74+
|
75+
LL | /// Link to [derive@m]
76+
| ^^^^^^^^
77+
78+
error: unresolved link to `s`
79+
--> $DIR/intra-links-disambiguator-mismatch.rs:40:14
80+
|
81+
LL | /// Link to [const@s]
82+
| ^^^^^^^
83+
|
84+
note: this item resolved to a static, which did not match the disambiguator 'const'
85+
--> $DIR/intra-links-disambiguator-mismatch.rs:40:14
86+
|
87+
LL | /// Link to [const@s]
88+
| ^^^^^^^
89+
90+
error: unresolved link to `c`
91+
--> $DIR/intra-links-disambiguator-mismatch.rs:44:14
92+
|
93+
LL | /// Link to [static@c]
94+
| ^^^^^^^^
95+
|
96+
note: this item resolved to a constant, which did not match the disambiguator 'static'
97+
--> $DIR/intra-links-disambiguator-mismatch.rs:44:14
98+
|
99+
LL | /// Link to [static@c]
100+
| ^^^^^^^^
101+
102+
error: unresolved link to `c`
103+
--> $DIR/intra-links-disambiguator-mismatch.rs:48:14
104+
|
105+
LL | /// Link to [fn@c]
106+
| ^^^^
107+
|
108+
note: this item resolved to a constant, which did not match the disambiguator 'fn'
109+
--> $DIR/intra-links-disambiguator-mismatch.rs:48:14
110+
|
111+
LL | /// Link to [fn@c]
112+
| ^^^^
113+
114+
error: unresolved link to `c`
115+
--> $DIR/intra-links-disambiguator-mismatch.rs:52:14
116+
|
117+
LL | /// Link to [c()]
118+
| ^^^
119+
|
120+
note: this item resolved to a constant, which did not match the disambiguator 'fn'
121+
--> $DIR/intra-links-disambiguator-mismatch.rs:52:14
122+
|
123+
LL | /// Link to [c()]
124+
| ^^^
125+
126+
error: aborting due to 10 previous errors
127+

0 commit comments

Comments
 (0)