use crate::Redirect::*;
+// Add linkcheck exceptions here
+// 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])]
+const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
+ // These are methods on slice, and `Self` does not work on primitive impls
+ // in intra-doc links (primitive impls are weird)
+ // https://github.com/rust-lang/rust/issues/62834 is necessary to be
+ // able to link to slices
+ (
+ "std/io/struct.IoSlice.html",
+ &[
+ "#method.as_mut_ptr",
+ "#method.sort_by_key",
+ "#method.make_ascii_uppercase",
+ "#method.make_ascii_lowercase",
+ ],
+ ),
+ // 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"]),
+];
+
macro_rules! t {
($e:expr) => {
match $e {
}
}
+fn is_exception(file: &Path, link: &str) -> bool {
+ if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+ entry.1.contains(&link)
+ } else {
+ false
+ }
+}
+
fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> {
// Ignore non-HTML files.
if file.extension().and_then(|s| s.to_str()) != Some("html") {
return None;
}
- // Unfortunately we're not 100% full of valid links today to we need a few
- // exceptions to get this past `make check` today.
- // FIXME(#32129)
- if file.ends_with("std/io/struct.IoSlice.html")
- {
- return None;
- }
-
- // FIXME(#32130)
- if file.ends_with("alloc/collections/btree_map/struct.BTreeMap.html")
- || file.ends_with("alloc/collections/btree_set/struct.BTreeSet.html")
- || file.ends_with("std/collections/btree_map/struct.BTreeMap.html")
- || file.ends_with("std/collections/btree_set/struct.BTreeSet.html")
- || file.ends_with("std/collections/hash_map/struct.HashMap.html")
- || file.ends_with("std/collections/hash_set/struct.HashSet.html")
- {
- return None;
- }
-
let res = load_file(cache, root, file, SkipRedirect);
let (pretty_file, contents) = match res {
Ok(res) => res,
{
return;
}
- let mut parts = url.splitn(2, "#");
+ let mut parts = url.splitn(2, '#');
let url = parts.next().unwrap();
let fragment = parts.next();
- let mut parts = url.splitn(2, "?");
+ let mut parts = url.splitn(2, '?');
let url = parts.next().unwrap();
// Once we've plucked out the URL, parse it using our base url and
}
// These appear to be broken in mdbook right now?
- if fragment.starts_with("-") {
+ if fragment.starts_with('-') {
return;
}
let entry = &mut cache.get_mut(&pretty_path).unwrap();
entry.parse_ids(&pretty_path, &contents, errors);
- if !entry.ids.contains(*fragment) {
+ if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment))
+ {
*errors = true;
print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1);
println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
};
}
} else {
- *errors = true;
- print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
let pretty_path = path.strip_prefix(root).unwrap_or(&path);
- println!("{}", pretty_path.display());
+ if !is_exception(file, pretty_path.to_str().unwrap()) {
+ *errors = true;
+ print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
+ println!("{}", pretty_path.display());
+ }
}
});
Some(pretty_file)
}
fn maybe_redirect(source: &str) -> Option<String> {
- const REDIRECT: &'static str = "<p>Redirecting to <a href=";
+ const REDIRECT: &str = "<p>Redirecting to <a href=";
let mut lines = source.lines();
let redirect_line = lines.nth(6)?;
// we can get away with using one pass.
let is_base = line[..j].ends_with("<base");
line = rest;
- let pos_equals = match rest.find("=") {
+ let pos_equals = match rest.find('=') {
Some(i) => i,
None => continue,
};
- if rest[..pos_equals].trim_start_matches(" ") != "" {
+ if rest[..pos_equals].trim_start_matches(' ') != "" {
continue;
}
};
let quote_delim = rest.as_bytes()[pos_quote] as char;
- if rest[..pos_quote].trim_start_matches(" ") != "" {
+ if rest[..pos_quote].trim_start_matches(' ') != "" {
continue;
}
let rest = &rest[pos_quote + 1..];