diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs index 89965dc2403..266900ea3a2 100644 --- a/src/tools/jsondoclint/src/main.rs +++ b/src/tools/jsondoclint/src/main.rs @@ -16,7 +16,7 @@ struct Error { #[derive(Debug, PartialEq, Eq)] enum ErrorKind { - NotFound, + NotFound(Vec), Custom(String), } @@ -37,49 +37,48 @@ fn main() -> Result<()> { let krate: Crate = serde_json::from_str(&contents)?; assert_eq!(krate.format_version, FORMAT_VERSION); - let mut validator = validator::Validator::new(&krate); + let krate_json: Value = serde_json::from_str(&contents)?; + + let mut validator = validator::Validator::new(&krate, krate_json); validator.check_crate(); if !validator.errs.is_empty() { for err in validator.errs { match err.kind { - ErrorKind::NotFound => { - let krate_json: Value = serde_json::from_str(&contents)?; - - let sels = - json_find::find_selector(&krate_json, &Value::String(err.id.0.clone())); - match &sels[..] { - [] => unreachable!( - "id must be in crate, or it wouldn't be reported as not found" - ), - [sel] => eprintln!( - "{} not in index or paths, but refered to at '{}'", - err.id.0, - json_find::to_jsonpath(&sel) - ), - [sel, ..] => { - if verbose { - let sels = sels - .iter() - .map(json_find::to_jsonpath) - .map(|i| format!("'{i}'")) - .collect::>() - .join(", "); - eprintln!( - "{} not in index or paths, but refered to at {sels}", - err.id.0 - ); - } else { - eprintln!( - "{} not in index or paths, but refered to at '{}' and {} more", - err.id.0, - json_find::to_jsonpath(&sel), - sels.len() - 1, - ) - } + ErrorKind::NotFound(sels) => match &sels[..] { + [] => { + unreachable!( + "id {:?} must be in crate, or it wouldn't be reported as not found", + err.id + ) + } + [sel] => eprintln!( + "{} not in index or paths, but refered to at '{}'", + err.id.0, + json_find::to_jsonpath(&sel) + ), + [sel, ..] => { + if verbose { + let sels = sels + .iter() + .map(json_find::to_jsonpath) + .map(|i| format!("'{i}'")) + .collect::>() + .join(", "); + eprintln!( + "{} not in index or paths, but refered to at {sels}", + err.id.0 + ); + } else { + eprintln!( + "{} not in index or paths, but refered to at '{}' and {} more", + err.id.0, + json_find::to_jsonpath(&sel), + sels.len() - 1, + ) } } - } + }, ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg), } } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 291d02d67bd..f1b9c1acbae 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -7,8 +7,9 @@ use rustdoc_json_types::{ Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding, TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate, }; +use serde_json::Value; -use crate::{item_kind::Kind, Error, ErrorKind}; +use crate::{item_kind::Kind, json_find, Error, ErrorKind}; /// The Validator walks over the JSON tree, and ensures it is well formed. /// It is made of several parts. @@ -22,6 +23,7 @@ use crate::{item_kind::Kind, Error, ErrorKind}; pub struct Validator<'a> { pub(crate) errs: Vec, krate: &'a Crate, + krate_json: Value, /// Worklist of Ids to check. todo: HashSet<&'a Id>, /// Ids that have already been visited, so don't need to be checked again. @@ -39,9 +41,10 @@ enum PathKind { } impl<'a> Validator<'a> { - pub fn new(krate: &'a Crate) -> Self { + pub fn new(krate: &'a Crate, krate_json: Value) -> Self { Self { krate, + krate_json, errs: Vec::new(), seen_ids: HashSet::new(), todo: HashSet::new(), @@ -373,7 +376,11 @@ impl<'a> Validator<'a> { } else { if !self.missing_ids.contains(id) { self.missing_ids.insert(id); - self.fail(id, ErrorKind::NotFound) + + let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); + assert_ne!(sels.len(), 0); + + self.fail(id, ErrorKind::NotFound(sels)) } } } diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index c4aeee9c53b..37b826153ef 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -2,11 +2,16 @@ use std::collections::HashMap; use rustdoc_json_types::{Crate, Item, Visibility}; +use crate::json_find::SelectorPart; + use super::*; #[track_caller] fn check(krate: &Crate, errs: &[Error]) { - let mut validator = Validator::new(krate); + let krate_string = serde_json::to_string(krate).unwrap(); + let krate_json = serde_json::from_str(&krate_string).unwrap(); + + let mut validator = Validator::new(krate, krate_json); validator.check_crate(); assert_eq!(errs, &validator.errs[..]); @@ -46,5 +51,16 @@ fn errors_on_missing_links() { format_version: rustdoc_json_types::FORMAT_VERSION, }; - check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]); + check( + &k, + &[Error { + kind: ErrorKind::NotFound(vec![vec![ + SelectorPart::Field("index".to_owned()), + SelectorPart::Field("0".to_owned()), + SelectorPart::Field("links".to_owned()), + SelectorPart::Field("Not Found".to_owned()), + ]]), + id: id("1"), + }], + ); }