summaryrefslogtreecommitdiffstats
path: root/src/tools/jsondoclint/src/validator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/jsondoclint/src/validator.rs')
-rw-r--r--src/tools/jsondoclint/src/validator.rs76
1 files changed, 53 insertions, 23 deletions
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index e15f5fe3c..c6f55410e 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -3,12 +3,16 @@ use std::hash::Hash;
use rustdoc_json_types::{
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
- GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
- Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
- TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+ GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module,
+ OpaqueTy, Path, 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};
+
+// This is a rustc implementation detail that we rely on here
+const LOCAL_CRATE_ID: u32 = 0;
/// The Validator walks over the JSON tree, and ensures it is well formed.
/// It is made of several parts.
@@ -22,6 +26,7 @@ use crate::{item_kind::Kind, Error, ErrorKind};
pub struct Validator<'a> {
pub(crate) errs: Vec<Error>,
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 +44,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(),
@@ -50,12 +56,19 @@ impl<'a> Validator<'a> {
}
pub fn check_crate(&mut self) {
+ // Graph traverse the index
let root = &self.krate.root;
self.add_mod_id(root);
while let Some(id) = set_remove(&mut self.todo) {
self.seen_ids.insert(id);
self.check_item(id);
}
+
+ let root_crate_id = self.krate.index[root].crate_id;
+ assert_eq!(root_crate_id, LOCAL_CRATE_ID, "LOCAL_CRATE_ID is wrong");
+ for (id, item_info) in &self.krate.paths {
+ self.check_item_info(id, item_info);
+ }
}
fn check_item(&mut self, id: &'a Id) {
@@ -140,24 +153,24 @@ impl<'a> Validator<'a> {
}
fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
- match x {
- Variant::Plain(discr) => {
- if let Some(discr) = discr {
- if let (Err(_), Err(_)) =
- (discr.value.parse::<i128>(), discr.value.parse::<u128>())
- {
- self.fail(
- id,
- ErrorKind::Custom(format!(
- "Failed to parse discriminant value `{}`",
- discr.value
- )),
- );
- }
- }
+ let Variant { kind, discriminant } = x;
+
+ if let Some(discr) = discriminant {
+ if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+ self.fail(
+ id,
+ ErrorKind::Custom(format!(
+ "Failed to parse discriminant value `{}`",
+ discr.value
+ )),
+ );
}
- Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
- Variant::Struct { fields, fields_stripped: _ } => {
+ }
+
+ match kind {
+ VariantKind::Plain => {}
+ VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+ VariantKind::Struct { fields, fields_stripped: _ } => {
fields.iter().for_each(|f| self.add_field_id(f))
}
}
@@ -361,6 +374,19 @@ impl<'a> Validator<'a> {
fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
}
+ fn check_item_info(&mut self, id: &Id, item_info: &ItemSummary) {
+ // FIXME: Their should be a better way to determine if an item is local, rather than relying on `LOCAL_CRATE_ID`,
+ // which encodes rustc implementation details.
+ if item_info.crate_id == LOCAL_CRATE_ID && !self.krate.index.contains_key(id) {
+ self.errs.push(Error {
+ id: id.clone(),
+ kind: ErrorKind::Custom(
+ "Id for local item in `paths` but not in `index`".to_owned(),
+ ),
+ })
+ }
+ }
+
fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
if let Some(kind) = self.kind_of(id) {
if valid(kind) {
@@ -373,7 +399,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))
}
}
}