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.
This commit is contained in:
Joshua Nelson 2020-12-19 01:52:43 -05:00
parent 0fd4f8febf
commit 4092891a8f
2 changed files with 94 additions and 26 deletions

View File

@ -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();

View File

@ -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]
//! [!]