From 4092891a8f2ca5947d5312e1949ecf701a4f25de Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 19 Dec 2020 01:52:43 -0500 Subject: [PATCH] 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. --- .../passes/collect_intra_doc_links.rs | 54 +++++++-------- .../rustdoc/intra-doc/non-path-primitives.rs | 66 +++++++++++++++++++ 2 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 src/test/rustdoc/intra-doc/non-path-primitives.rs 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 { } 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 { - 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> { 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] +//! [!]