Disallow linking to items with a mismatched disambiguator

This commit is contained in:
Joshua Nelson 2020-08-02 20:45:24 -04:00
parent f042d749b0
commit 8e0e925e2b
3 changed files with 223 additions and 2 deletions

View File

@ -574,9 +574,9 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
};
let resolved_self;
let mut path_str;
let mut disambiguator = None;
let (res, fragment) = {
let mut kind = None;
let mut disambiguator = None;
path_str = if let Some(prefix) =
["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
.iter()
@ -595,6 +595,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
link.trim_start_matches(prefix)
} else if link.ends_with("!()") {
kind = Some(MacroNS);
disambiguator = Some("bang");
link.trim_end_matches("!()")
} else if link.ends_with("()") {
kind = Some(ValueNS);
@ -610,7 +611,7 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
link.trim_start_matches("derive@")
} else if link.ends_with('!') {
kind = Some(MacroNS);
disambiguator = Some("macro");
disambiguator = Some("bang");
link.trim_end_matches('!')
} else {
&link[..]
@ -789,6 +790,46 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
} else {
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
// Disallow e.g. linking to enums with `struct@`
if let Res::Def(kind, id) = res {
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
// NOTE: this relies on the fact that `''` is never parsed as a disambiguator
// NOTE: this needs to be kept in sync with the disambiguator parsing
match (kind, disambiguator.unwrap_or_default().trim_end_matches("@")) {
| (DefKind::Struct, "struct")
| (DefKind::Enum, "enum")
| (DefKind::Trait, "trait")
| (DefKind::Union, "union")
| (DefKind::Mod, "mod" | "module")
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, "const")
| (DefKind::Static, "static")
// NOTE: this allows 'method' to mean both normal functions and associated functions
// This can't cause ambiguity because both are in the same namespace.
| (DefKind::Fn | DefKind::AssocFn, "fn" | "function" | "method")
| (DefKind::Macro(MacroKind::Bang), "bang")
| (DefKind::Macro(MacroKind::Derive), "derive")
// These are namespaces; allow anything in the namespace to match
| (_, "type" | "macro" | "value")
// If no disambiguator given, allow anything
| (_, "")
// All of these are valid, so do nothing
=> {}
(_, disambiguator) => {
// The resolved item did not match the disambiguator; give a better error than 'not found'
let msg = format!("unresolved link to `{}`", path_str);
report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| {
let msg = format!("this item resolved to {} {}, which did not match the disambiguator '{}'", kind.article(), kind.descr(id), disambiguator);
if let Some(sp) = sp {
diag.span_note(sp, &msg);
} else {
diag.note(&msg);
}
});
continue;
}
}
}
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
if let Some((src_id, dst_id)) = res
.opt_def_id()

View File

@ -0,0 +1,53 @@
#![deny(broken_intra_doc_links)]
//~^ NOTE lint level is defined
pub enum S {}
macro_rules! m {
() => {};
}
static s: usize = 0;
const c: usize = 0;
trait T {}
/// Link to [struct@S]
//~^ ERROR unresolved link to `S`
//~| NOTE did not match
/// Link to [mod@S]
//~^ ERROR unresolved link to `S`
//~| NOTE did not match
/// Link to [union@S]
//~^ ERROR unresolved link to `S`
//~| NOTE did not match
/// Link to [trait@S]
//~^ ERROR unresolved link to `S`
//~| NOTE did not match
/// Link to [struct@T]
//~^ ERROR unresolved link to `T`
//~| NOTE did not match
/// Link to [derive@m]
//~^ ERROR unresolved link to `m`
//~| NOTE did not match
/// Link to [const@s]
//~^ ERROR unresolved link to `s`
//~| NOTE did not match
/// Link to [static@c]
//~^ ERROR unresolved link to `c`
//~| NOTE did not match
/// Link to [fn@c]
//~^ ERROR unresolved link to `c`
//~| NOTE did not match
/// Link to [c()]
//~^ ERROR unresolved link to `c`
//~| NOTE did not match
pub fn f() {}

View File

@ -0,0 +1,127 @@
error: unresolved link to `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:16:14
|
LL | /// Link to [struct@S]
| ^^^^^^^^
|
note: the lint level is defined here
--> $DIR/intra-links-disambiguator-mismatch.rs:1:9
|
LL | #![deny(broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^
note: this item resolved to an enum, which did not match the disambiguator 'struct'
--> $DIR/intra-links-disambiguator-mismatch.rs:16:14
|
LL | /// Link to [struct@S]
| ^^^^^^^^
error: unresolved link to `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:20:14
|
LL | /// Link to [mod@S]
| ^^^^^
|
note: this item resolved to an enum, which did not match the disambiguator 'mod'
--> $DIR/intra-links-disambiguator-mismatch.rs:20:14
|
LL | /// Link to [mod@S]
| ^^^^^
error: unresolved link to `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:24:14
|
LL | /// Link to [union@S]
| ^^^^^^^
|
note: this item resolved to an enum, which did not match the disambiguator 'union'
--> $DIR/intra-links-disambiguator-mismatch.rs:24:14
|
LL | /// Link to [union@S]
| ^^^^^^^
error: unresolved link to `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:28:14
|
LL | /// Link to [trait@S]
| ^^^^^^^
|
note: this item resolved to an enum, which did not match the disambiguator 'trait'
--> $DIR/intra-links-disambiguator-mismatch.rs:28:14
|
LL | /// Link to [trait@S]
| ^^^^^^^
error: unresolved link to `T`
--> $DIR/intra-links-disambiguator-mismatch.rs:32:14
|
LL | /// Link to [struct@T]
| ^^^^^^^^
|
note: this item resolved to a trait, which did not match the disambiguator 'struct'
--> $DIR/intra-links-disambiguator-mismatch.rs:32:14
|
LL | /// Link to [struct@T]
| ^^^^^^^^
error: unresolved link to `m`
--> $DIR/intra-links-disambiguator-mismatch.rs:36:14
|
LL | /// Link to [derive@m]
| ^^^^^^^^
|
note: this item resolved to a macro, which did not match the disambiguator 'derive'
--> $DIR/intra-links-disambiguator-mismatch.rs:36:14
|
LL | /// Link to [derive@m]
| ^^^^^^^^
error: unresolved link to `s`
--> $DIR/intra-links-disambiguator-mismatch.rs:40:14
|
LL | /// Link to [const@s]
| ^^^^^^^
|
note: this item resolved to a static, which did not match the disambiguator 'const'
--> $DIR/intra-links-disambiguator-mismatch.rs:40:14
|
LL | /// Link to [const@s]
| ^^^^^^^
error: unresolved link to `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:44:14
|
LL | /// Link to [static@c]
| ^^^^^^^^
|
note: this item resolved to a constant, which did not match the disambiguator 'static'
--> $DIR/intra-links-disambiguator-mismatch.rs:44:14
|
LL | /// Link to [static@c]
| ^^^^^^^^
error: unresolved link to `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:48:14
|
LL | /// Link to [fn@c]
| ^^^^
|
note: this item resolved to a constant, which did not match the disambiguator 'fn'
--> $DIR/intra-links-disambiguator-mismatch.rs:48:14
|
LL | /// Link to [fn@c]
| ^^^^
error: unresolved link to `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:52:14
|
LL | /// Link to [c()]
| ^^^
|
note: this item resolved to a constant, which did not match the disambiguator 'fn'
--> $DIR/intra-links-disambiguator-mismatch.rs:52:14
|
LL | /// Link to [c()]
| ^^^
error: aborting due to 10 previous errors