Skip to content

Commit 4092891

Browse files
committed
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.
1 parent 0fd4f8f commit 4092891

File tree

2 files changed

+94
-26
lines changed

2 files changed

+94
-26
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+28-26
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
475475
});
476476
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
477477
match result {
478-
// resolver doesn't know about true and false so we'll have to resolve them
478+
// resolver doesn't know about true, false, and types that aren't paths (e.g. `()`)
479479
// manually as bool
480-
Err(()) => is_bool_value(path_str, ns),
480+
Err(()) => resolve_primitive(path_str, ns),
481481
Ok(res) => Some(res),
482482
}
483483
}
@@ -1020,7 +1020,7 @@ impl LinkCollector<'_, '_> {
10201020
(link.trim(), None)
10211021
};
10221022

1023-
if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
1023+
if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !*()[]&;".contains(ch))) {
10241024
return None;
10251025
}
10261026

@@ -1108,9 +1108,8 @@ impl LinkCollector<'_, '_> {
11081108
// Sanity check to make sure we don't have any angle brackets after stripping generics.
11091109
assert!(!path_str.contains(['<', '>'].as_slice()));
11101110

1111-
// The link is not an intra-doc link if it still contains commas or spaces after
1112-
// stripping generics.
1113-
if path_str.contains([',', ' '].as_slice()) {
1111+
// The link is not an intra-doc link if it still contains spaces after stripping generics.
1112+
if path_str.contains(' ') {
11141113
return None;
11151114
}
11161115

@@ -1476,8 +1475,11 @@ impl Disambiguator {
14761475
("!", DefKind::Macro(MacroKind::Bang)),
14771476
];
14781477
for &(suffix, kind) in &suffixes {
1479-
if link.ends_with(suffix) {
1480-
return Ok((Kind(kind), link.trim_end_matches(suffix)));
1478+
if let Some(link) = link.strip_suffix(suffix) {
1479+
// Avoid turning `!` or `()` into an empty string
1480+
if !link.is_empty() {
1481+
return Ok((Kind(kind), link));
1482+
}
14811483
}
14821484
}
14831485
Err(())
@@ -2066,37 +2068,37 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
20662068
}
20672069
use PrimitiveType::*;
20682070
let prim = match path_str {
2069-
"u8" => U8,
2070-
"u16" => U16,
2071-
"u32" => U32,
2072-
"u64" => U64,
2073-
"u128" => U128,
2074-
"usize" => Usize,
2071+
"isize" => Isize,
20752072
"i8" => I8,
20762073
"i16" => I16,
20772074
"i32" => I32,
20782075
"i64" => I64,
20792076
"i128" => I128,
2080-
"isize" => Isize,
2077+
"usize" => Usize,
2078+
"u8" => U8,
2079+
"u16" => U16,
2080+
"u32" => U32,
2081+
"u64" => U64,
2082+
"u128" => U128,
20812083
"f32" => F32,
20822084
"f64" => F64,
2083-
"str" => Str,
2084-
"bool" | "true" | "false" => Bool,
20852085
"char" => Char,
2086+
"bool" | "true" | "false" => Bool,
2087+
"str" => Str,
2088+
"slice" | "&[]" | "[T]" => Slice,
2089+
"array" | "[]" | "[T;N]" => Array,
2090+
"tuple" | "(,)" => Tuple,
2091+
"unit" | "()" => Unit,
2092+
"pointer" | "*" | "*const" | "*mut" => RawPointer,
2093+
"reference" | "&" | "&mut" => Reference,
2094+
"fn" => Fn,
2095+
"never" | "!" => Never,
20862096
_ => return None,
20872097
};
2098+
debug!("resolved primitives {:?}", prim);
20882099
Some(Res::Primitive(prim))
20892100
}
20902101

2091-
/// Resolve a primitive value.
2092-
fn is_bool_value(path_str: &str, ns: Namespace) -> Option<Res> {
2093-
if ns == TypeNS && (path_str == "true" || path_str == "false") {
2094-
Some(Res::Primitive(PrimitiveType::Bool))
2095-
} else {
2096-
None
2097-
}
2098-
}
2099-
21002102
fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
21012103
let mut stripped_segments = vec![];
21022104
let mut path = path_str.chars().peekable();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// ignore-tidy-linelength
2+
#![crate_name = "foo"]
3+
#![deny(broken_intra_doc_links)]
4+
5+
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
6+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'X'
7+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'Y'
8+
//! [slice::rotate_left]
9+
//! [X]([T]::rotate_left)
10+
//! [Y](&[]::rotate_left)
11+
// These don't work because markdown syntax doesn't allow it.
12+
// [[T]::rotate_left]
13+
//! [&[]::rotate_left]
14+
15+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
16+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'X'
17+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'Y'
18+
//! [array::map]
19+
//! [X]([]::map)
20+
//! [Y]([T;N]::map)
21+
// These don't work because markdown syntax doesn't allow it.
22+
// [Z]([T; N]::map)
23+
//! [`[T; N]::map`]
24+
//! [[]::map]
25+
// [Z][]
26+
//
27+
// [Z]: [T; N]::map
28+
29+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
30+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
31+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
32+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*::is_null'
33+
//! [pointer::is_null]
34+
//! [*const::is_null]
35+
//! [*mut::is_null]
36+
//! [*::is_null]
37+
38+
// FIXME: Associated items on some primitives aren't working, because the impls
39+
// are part of the compiler instead of being part of the source code.
40+
41+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
42+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' '()'
43+
//! [unit]
44+
//! [()]
45+
46+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
47+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'X'
48+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' '(,)'
49+
//! [tuple]
50+
//! [X]((,))
51+
//! [(,)]
52+
53+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
54+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
55+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
56+
//! [reference]
57+
//! [&]
58+
//! [&mut]
59+
60+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
61+
//! [fn]
62+
63+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
64+
// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
65+
//! [never]
66+
//! [!]

0 commit comments

Comments
 (0)