about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamelid <camelidcamel@gmail.com>2021-03-26 18:14:47 -0700
committerCamelid <camelidcamel@gmail.com>2021-03-26 19:50:07 -0700
commit4572e7f903a3d6bd5b401e886c9e7e2ef97998f0 (patch)
tree8b6c6e2768a4631c59b4a15cfd39a258262844c2
parent5e65467eff3d1da4712586d8402d1d2e1d6654bc (diff)
downloadrust-4572e7f903a3d6bd5b401e886c9e7e2ef97998f0.tar.gz
rust-4572e7f903a3d6bd5b401e886c9e7e2ef97998f0.zip
Lint on unknown intra-doc link disambiguators
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs45
-rw-r--r--src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs10
-rw-r--r--src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr40
3 files changed, 84 insertions, 11 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 499931f7e96..f5c5c9ca4aa 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -973,10 +973,13 @@ impl LinkCollector<'_, '_> {
         };
 
         // Parse and strip the disambiguator from the link, if present.
-        let (mut path_str, disambiguator) = if let Ok((d, path)) = Disambiguator::from_str(&link) {
-            (path.trim(), Some(d))
-        } else {
-            (link.trim(), None)
+        let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) {
+            Ok(Some((d, path))) => (path.trim(), Some(d)),
+            Ok(None) => (link.trim(), None),
+            Err(err_msg) => {
+                disambiguator_error(self.cx, &item, dox, ori_link.range, &err_msg);
+                return None;
+            }
         };
 
         if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*&;".contains(ch))) {
@@ -1514,8 +1517,12 @@ impl Disambiguator {
         }
     }
 
-    /// Given a link, parse and return `(disambiguator, path_str)`
-    fn from_str(link: &str) -> Result<(Self, &str), ()> {
+    /// Given a link, parse and return `(disambiguator, path_str)`.
+    ///
+    /// This returns `Ok(Some(...))` if a disambiguator was found,
+    /// `Ok(None)` if no disambiguator was found, or `Err(...)`
+    /// if there was a problem with the disambiguator.
+    fn from_str(link: &str) -> Result<Option<(Self, &str)>, String> {
         use Disambiguator::{Kind, Namespace as NS, Primitive};
 
         let find_suffix = || {
@@ -1528,11 +1535,11 @@ impl Disambiguator {
                 if let Some(link) = link.strip_suffix(suffix) {
                     // Avoid turning `!` or `()` into an empty string
                     if !link.is_empty() {
-                        return Ok((Kind(kind), link));
+                        return Some((Kind(kind), link));
                     }
                 }
             }
-            Err(())
+            None
         };
 
         if let Some(idx) = link.find('@') {
@@ -1551,11 +1558,11 @@ impl Disambiguator {
                 "value" => NS(Namespace::ValueNS),
                 "macro" => NS(Namespace::MacroNS),
                 "prim" | "primitive" => Primitive,
-                _ => return find_suffix(),
+                _ => return Err(format!("unknown disambiguator `{}`", prefix)),
             };
-            Ok((d, &rest[1..]))
+            Ok(Some((d, &rest[1..])))
         } else {
-            find_suffix()
+            Ok(find_suffix())
         }
     }
 
@@ -1979,6 +1986,22 @@ fn anchor_failure(
     });
 }
 
+/// Report an error in the link disambiguator.
+fn disambiguator_error(
+    cx: &DocContext<'_>,
+    item: &Item,
+    dox: &str,
+    link_range: Range<usize>,
+    msg: &str,
+) {
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, item, dox, &link_range, |diag, _sp| {
+        diag.note(
+            "the disambiguator is the part of the link before the `@` sign, \
+             or a suffix such as `()` for functions",
+        );
+    });
+}
+
 /// Report an ambiguity error, where there were multiple possible resolutions.
 fn ambiguity_error(
     cx: &DocContext<'_>,
diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs
new file mode 100644
index 00000000000..9222025367d
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs
@@ -0,0 +1,10 @@
+//! Linking to [foo@banana] and [`bar@banana!()`].
+//~^ ERROR unknown disambiguator `foo`
+//~| ERROR unknown disambiguator `bar`
+//! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+//~^ ERROR unknown disambiguator ``
+//~| ERROR unknown disambiguator ``
+
+#![deny(warnings)]
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
new file mode 100644
index 00000000000..9e7699eea9a
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
@@ -0,0 +1,40 @@
+error: unknown disambiguator `foo`
+  --> $DIR/unknown-disambiguator.rs:1:17
+   |
+LL | //! Linking to [foo@banana] and [`bar@banana!()`].
+   |                 ^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unknown-disambiguator.rs:8:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
+   = note: the disambiguator is the part of the link before the `@` sign, or a suffix such as `()` for functions
+
+error: unknown disambiguator `bar`
+  --> $DIR/unknown-disambiguator.rs:1:34
+   |
+LL | //! Linking to [foo@banana] and [`bar@banana!()`].
+   |                                  ^^^^^^^^^^^^^^^
+   |
+   = note: the disambiguator is the part of the link before the `@` sign, or a suffix such as `()` for functions
+
+error: unknown disambiguator ``
+  --> $DIR/unknown-disambiguator.rs:4:31
+   |
+LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+   |                               ^^^^^^^^^^
+   |
+   = note: the disambiguator is the part of the link before the `@` sign, or a suffix such as `()` for functions
+
+error: unknown disambiguator ``
+  --> $DIR/unknown-disambiguator.rs:4:57
+   |
+LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
+   |                                                         ^^^^^^^^^^^
+   |
+   = note: the disambiguator is the part of the link before the `@` sign, or a suffix such as `()` for functions
+
+error: aborting due to 4 previous errors
+