Skip to content

Commit

Permalink
Fix linkcheck issues
Browse files Browse the repository at this point in the history
Most of these are because alloc uses `#[lang_item]` to define methods,
but core documents primitives before those methods are available.

- Fix rustdoc-js-std test

  For some reason this change made CStr not show up in the results for
  `str,u8`. Since it still shows up for str, and since it wasn't a great
  match for that query anyway, I think this is ok to let slide.

- Add test that all primitives can be linked to
- Enable `doc(primitive)` in `core` as well
- Add linkcheck exception specifically for Windows

  Ideally this would be done automatically by the linkchecker by
  replacing `\\` with forward slashes, but this PR is already a ton of
  work ...

- Don't forcibly fail linkchecking if there's a broken intra-doc link on Windows

  Previously, it would exit with a hard error if a missing file had `::`
  in it. This changes it to report a missing file instead, which allows
  adding an exception.
  • Loading branch information
jyn514 committed Sep 12, 2021
1 parent cb7e527 commit 7b46920
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 8 deletions.
2 changes: 1 addition & 1 deletion library/core/src/char/methods.rs
Expand Up @@ -24,7 +24,7 @@ impl char {
/// decoding error.
///
/// It can occur, for example, when giving ill-formed UTF-8 bytes to
/// [`String::from_utf8_lossy`](string/struct.String.html#method.from_utf8_lossy).
/// [`String::from_utf8_lossy`](../std/string/struct.String.html#method.from_utf8_lossy).
#[stable(feature = "assoc_char_consts", since = "1.52.0")]
pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}';

Expand Down
6 changes: 3 additions & 3 deletions library/core/src/slice/mod.rs
Expand Up @@ -2257,9 +2257,9 @@ impl<T> [T] {
/// assert!(match r { Ok(1..=4) => true, _ => false, });
/// ```
// Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is
// in crate `alloc`, and as such doesn't exists yet when building `core`.
// links to downstream crate: #74481. Since primitives are only documented in
// libstd (#73423), this never leads to broken links in practice.
// in crate `alloc`, and as such doesn't exists yet when building `core`: #74481.
// This breaks links when slice is displayed in core, but changing it to use relative links
// would break when the item is re-exported. So allow the core links to be broken for now.
#[allow(rustdoc::broken_intra_doc_links)]
#[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/types.rs
Expand Up @@ -1774,7 +1774,7 @@ impl PrimitiveType {
debug!(?crate_num, ?crate_name);
for &(def_id, prim) in &e.primitives(tcx) {
// HACK: try to link to std instead where possible
if crate_name == sym::core && primitive_locations.get(&prim).is_some() {
if crate_name == sym::core && primitive_locations.contains_key(&prim) {
continue;
}
primitive_locations.insert(prim, def_id);
Expand Down
7 changes: 4 additions & 3 deletions src/test/rustdoc-js-std/multi-query.js
Expand Up @@ -2,8 +2,9 @@ const QUERY = 'str,u8';

const EXPECTED = {
'others': [
{ 'path': 'std', 'name': 'str' },
{ 'path': 'std', 'name': 'u8' },
{ 'path': 'std::ffi', 'name': 'CStr' },
{ 'path': 'std', 'name': 'str', 'href': '../std/primitive.str.html' },
{ 'path': 'std', 'name': 'u8', 'href': '../std/primitive.u8.html' },
{ 'path': 'std', 'name': 'str', 'href': '../std/str/index.html' },
{ 'path': 'std', 'name': 'u8', 'href': '../std/u8/index.html' },
],
};
10 changes: 10 additions & 0 deletions src/test/rustdoc/primitive/no_std.rs
@@ -1,6 +1,16 @@
#![no_std]
#![deny(warnings)]
#![deny(rustdoc::broken_intra_doc_links)]

// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link'
/// Link to [primitive link][u8]
pub fn foo() -> u8 {}

// Test that all primitives can be linked to.
/// [isize] [i8] [i16] [i32] [i64] [i128]
/// [usize] [u8] [u16] [u32] [u64] [u128]
/// [f32] [f64]
/// [char] [bool] [str] [slice] [array] [tuple] [unit]
/// [pointer] [reference] [fn] [never]
pub fn bar() {}
26 changes: 26 additions & 0 deletions src/tools/linkchecker/main.rs
Expand Up @@ -30,13 +30,27 @@ use regex::Regex;
// If at all possible you should use intra-doc links to avoid linkcheck issues. These
// are cases where that does not work
// [(generated_documentation_page, &[broken_links])]
#[rustfmt::skip]
const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
// These try to link to std::collections, but are defined in alloc
// https://github.com/rust-lang/rust/issues/74481
("std/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
("std/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
("alloc/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),

// These try to link to various things in std, but are defined in core.
// The docs in std::primitive use proper intra-doc links, so these seem fine to special-case.
// Most these are broken because liballoc uses `#[lang_item]` magic to define things on
// primitives that aren't available in core.
("alloc/slice/trait.Join.html", &["#method.join"]),
("alloc/slice/trait.Concat.html", &["#method.concat"]),
("alloc/slice/index.html", &["#method.concat", "#method.join"]),
("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]),
("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]),
("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase",
"core/slice::sort_by_key", "core\\slice::sort_by_key",
"#method.sort_by_cached_key"]),
];

#[rustfmt::skip]
Expand Down Expand Up @@ -376,6 +390,10 @@ impl Checker {

/// Load a file from disk, or from the cache if available.
fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
#[cfg(windows)]
const ERROR_INVALID_NAME: i32 = 123;

let pretty_path =
file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();

Expand All @@ -392,6 +410,14 @@ impl Checker {
}
Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
Err(e) => {
// If a broken intra-doc link contains `::`, on windows, it will cause `ERROR_INVALID_NAME` rather than `NotFound`.
// Explicitly check for that so that the broken link can be allowed in `LINKCHECK_EXCEPTIONS`.
#[cfg(windows)]
if e.raw_os_error() == Some(ERROR_INVALID_NAME)
&& file.as_os_str().to_str().map_or(false, |s| s.contains("::"))
{
return FileEntry::Missing;
}
panic!("unexpected read error for {}: {}", file.display(), e);
}
});
Expand Down

0 comments on commit 7b46920

Please sign in to comment.