about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-12-19 01:52:43 -0500
committerJoshua Nelson <jyn514@gmail.com>2020-12-22 11:45:23 -0500
commit4092891a8f2ca5947d5312e1949ecf701a4f25de (patch)
treef8dc2936ce281aa34024650f41d290ab30543e2b
parent0fd4f8febf8fc0edb94481f35c44c7e9e6e1ba87 (diff)
downloadrust-4092891a8f2ca5947d5312e1949ecf701a4f25de.tar.gz
rust-4092891a8f2ca5947d5312e1949ecf701a4f25de.zip
Fix intra-doc links for non-path primitives
This does *not* currently work for associated items that are
auto-implemented by the compiler (e.g. `never::eq`), because they aren't
present in the source code. I plan to fix this in a follow-up PR.
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs54
-rw-r--r--src/test/rustdoc/intra-doc/non-path-primitives.rs66
2 files changed, 94 insertions, 26 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 1f1fb9754cf..b8db0d5a4d6 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -475,9 +475,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         });
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
         match result {
-            // resolver doesn't know about true and false so we'll have to resolve them
+            // resolver doesn't know about true, false, and types that aren't paths (e.g. `()`)
             // manually as bool
-            Err(()) => is_bool_value(path_str, ns),
+            Err(()) => resolve_primitive(path_str, ns),
             Ok(res) => Some(res),
         }
     }
@@ -1020,7 +1020,7 @@ impl LinkCollector<'_, '_> {
             (link.trim(), None)
         };
 
-        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
+        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*()[]&;".contains(ch))) {
             return None;
         }
 
@@ -1108,9 +1108,8 @@ impl LinkCollector<'_, '_> {
         // Sanity check to make sure we don't have any angle brackets after stripping generics.
         assert!(!path_str.contains(['<', '>'].as_slice()));
 
-        // The link is not an intra-doc link if it still contains commas or spaces after
-        // stripping generics.
-        if path_str.contains([',', ' '].as_slice()) {
+        // The link is not an intra-doc link if it still contains spaces after stripping generics.
+        if path_str.contains(' ') {
             return None;
         }
 
@@ -1476,8 +1475,11 @@ impl Disambiguator {
                 ("!", DefKind::Macro(MacroKind::Bang)),
             ];
             for &(suffix, kind) in &suffixes {
-                if link.ends_with(suffix) {
-                    return Ok((Kind(kind), link.trim_end_matches(suffix)));
+                if let Some(link) = link.strip_suffix(suffix) {
+                    // Avoid turning `!` or `()` into an empty string
+                    if !link.is_empty() {
+                        return Ok((Kind(kind), link));
+                    }
                 }
             }
             Err(())
@@ -2066,37 +2068,37 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
     }
     use PrimitiveType::*;
     let prim = match path_str {
-        "u8" => U8,
-        "u16" => U16,
-        "u32" => U32,
-        "u64" => U64,
-        "u128" => U128,
-        "usize" => Usize,
+        "isize" => Isize,
         "i8" => I8,
         "i16" => I16,
         "i32" => I32,
         "i64" => I64,
         "i128" => I128,
-        "isize" => Isize,
+        "usize" => Usize,
+        "u8" => U8,
+        "u16" => U16,
+        "u32" => U32,
+        "u64" => U64,
+        "u128" => U128,
         "f32" => F32,
         "f64" => F64,
-        "str" => Str,
-        "bool" | "true" | "false" => Bool,
         "char" => Char,
+        "bool" | "true" | "false" => Bool,
+        "str" => Str,
+        "slice" | "&[]" | "[T]" => Slice,
+        "array" | "[]" | "[T;N]" => Array,
+        "tuple" | "(,)" => Tuple,
+        "unit" | "()" => Unit,
+        "pointer" | "*" | "*const" | "*mut" => RawPointer,
+        "reference" | "&" | "&mut" => Reference,
+        "fn" => Fn,
+        "never" | "!" => Never,
         _ => return None,
     };
+    debug!("resolved primitives {:?}", prim);
     Some(Res::Primitive(prim))
 }
 
-/// Resolve a primitive value.
-fn is_bool_value(path_str: &str, ns: Namespace) -> Option<Res> {
-    if ns == TypeNS && (path_str == "true" || path_str == "false") {
-        Some(Res::Primitive(PrimitiveType::Bool))
-    } else {
-        None
-    }
-}
-
 fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
     let mut stripped_segments = vec![];
     let mut path = path_str.chars().peekable();
diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs
new file mode 100644
index 00000000000..83d081824ff
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs
@@ -0,0 +1,66 @@
+// ignore-tidy-linelength
+#![crate_name = "foo"]
+#![deny(broken_intra_doc_links)]
+
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'X'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'Y'
+//! [slice::rotate_left]
+//! [X]([T]::rotate_left)
+//! [Y](&[]::rotate_left)
+// These don't work because markdown syntax doesn't allow it.
+// [[T]::rotate_left]
+//! [&[]::rotate_left]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'X'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'Y'
+//! [array::map]
+//! [X]([]::map)
+//! [Y]([T;N]::map)
+// These don't work because markdown syntax doesn't allow it.
+// [Z]([T; N]::map)
+//! [`[T; N]::map`]
+//! [[]::map]
+// [Z][]
+//
+// [Z]: [T; N]::map
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*::is_null'
+//! [pointer::is_null]
+//! [*const::is_null]
+//! [*mut::is_null]
+//! [*::is_null]
+
+// FIXME: Associated items on some primitives aren't working, because the impls
+// are part of the compiler instead of being part of the source code.
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' '()'
+//! [unit]
+//! [()]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'X'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' '(,)'
+//! [tuple]
+//! [X]((,))
+//! [(,)]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+//! [reference]
+//! [&]
+//! [&mut]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+//! [fn]
+
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+//! [never]
+//! [!]