summaryrefslogtreecommitdiffstats
path: root/src/tools/jsondoclint
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/jsondoclint')
-rw-r--r--src/tools/jsondoclint/src/item_kind.rs33
-rw-r--r--src/tools/jsondoclint/src/json_find.rs5
-rw-r--r--src/tools/jsondoclint/src/json_find/tests.rs27
-rw-r--r--src/tools/jsondoclint/src/main.rs4
-rw-r--r--src/tools/jsondoclint/src/validator.rs53
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs50
6 files changed, 139 insertions, 33 deletions
diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs
index 6d986e575..b395c6e7d 100644
--- a/src/tools/jsondoclint/src/item_kind.rs
+++ b/src/tools/jsondoclint/src/item_kind.rs
@@ -1,7 +1,7 @@
use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary};
/// A univeral way to represent an [`ItemEnum`] or [`ItemKind`]
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
pub(crate) enum Kind {
Module,
ExternCrate,
@@ -17,7 +17,6 @@ pub(crate) enum Kind {
Constant,
Trait,
TraitAlias,
- Method,
Impl,
Static,
ForeignType,
@@ -63,18 +62,33 @@ impl Kind {
// Only in traits
AssocConst => false,
AssocType => false,
- Method => false,
StructField => false, // Only in structs or variants
Variant => false, // Only in enums
}
}
+ pub fn can_appear_in_import(self) -> bool {
+ match self {
+ Kind::Variant => true,
+ Kind::Import => false,
+ other => other.can_appear_in_mod(),
+ }
+ }
+
+ pub fn can_appear_in_glob_import(self) -> bool {
+ match self {
+ Kind::Module => true,
+ Kind::Enum => true,
+ _ => false,
+ }
+ }
+
pub fn can_appear_in_trait(self) -> bool {
match self {
Kind::AssocConst => true,
Kind::AssocType => true,
- Kind::Method => true,
+ Kind::Function => true,
Kind::Module => false,
Kind::ExternCrate => false,
@@ -84,7 +98,6 @@ impl Kind {
Kind::Union => false,
Kind::Enum => false,
Kind::Variant => false,
- Kind::Function => false,
Kind::Typedef => false,
Kind::OpaqueTy => false,
Kind::Constant => false,
@@ -114,11 +127,11 @@ impl Kind {
pub fn is_variant(self) -> bool {
matches!(self, Kind::Variant)
}
- pub fn is_trait(self) -> bool {
- matches!(self, Kind::Trait)
+ pub fn is_trait_or_alias(self) -> bool {
+ matches!(self, Kind::Trait | Kind::TraitAlias)
}
- pub fn is_struct_enum_union(self) -> bool {
- matches!(self, Kind::Struct | Kind::Enum | Kind::Union)
+ pub fn is_type(self) -> bool {
+ matches!(self, Kind::Struct | Kind::Enum | Kind::Union | Kind::Typedef)
}
pub fn from_item(i: &Item) -> Self {
@@ -134,7 +147,6 @@ impl Kind {
ItemEnum::Function(_) => Function,
ItemEnum::Trait(_) => Trait,
ItemEnum::TraitAlias(_) => TraitAlias,
- ItemEnum::Method(_) => Method,
ItemEnum::Impl(_) => Impl,
ItemEnum::Typedef(_) => Typedef,
ItemEnum::OpaqueTy(_) => OpaqueTy,
@@ -164,7 +176,6 @@ impl Kind {
ItemKind::Import => Import,
ItemKind::Keyword => Keyword,
ItemKind::Macro => Macro,
- ItemKind::Method => Method,
ItemKind::Module => Module,
ItemKind::OpaqueTy => OpaqueTy,
ItemKind::Primitive => Primitive,
diff --git a/src/tools/jsondoclint/src/json_find.rs b/src/tools/jsondoclint/src/json_find.rs
index 95ea88666..70e7440f7 100644
--- a/src/tools/jsondoclint/src/json_find.rs
+++ b/src/tools/jsondoclint/src/json_find.rs
@@ -2,7 +2,7 @@ use std::fmt::Write;
use serde_json::Value;
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SelectorPart {
Field(String),
Index(usize),
@@ -72,3 +72,6 @@ fn find_selector_recursive(
}
}
}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/tools/jsondoclint/src/json_find/tests.rs b/src/tools/jsondoclint/src/json_find/tests.rs
new file mode 100644
index 000000000..2a5335307
--- /dev/null
+++ b/src/tools/jsondoclint/src/json_find/tests.rs
@@ -0,0 +1,27 @@
+use super::*;
+
+#[test]
+fn basic_find() {
+ use SelectorPart::*;
+
+ let j = serde_json::json!({
+ "index": {
+ "4": {
+ "inner": {
+ "items": ["1", "2", "3"]
+ }
+ }
+ }
+ });
+
+ let sel = find_selector(&j, &serde_json::json!("1"));
+ let exp: Vec<Vec<SelectorPart>> = vec![vec![
+ Field("index".to_owned()),
+ Field("4".to_owned()),
+ Field("inner".to_owned()),
+ Field("items".to_owned()),
+ Index(0),
+ ]];
+
+ assert_eq!(exp, sel);
+}
diff --git a/src/tools/jsondoclint/src/main.rs b/src/tools/jsondoclint/src/main.rs
index 70d7a82a5..fc54c421b 100644
--- a/src/tools/jsondoclint/src/main.rs
+++ b/src/tools/jsondoclint/src/main.rs
@@ -9,13 +9,13 @@ pub(crate) mod item_kind;
mod json_find;
mod validator;
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
struct Error {
kind: ErrorKind,
id: Id,
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
enum ErrorKind {
NotFound,
Custom(String),
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 94af4c5e9..e15f5fe3c 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -3,9 +3,9 @@ use std::hash::Hash;
use rustdoc_json_types::{
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
- GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, 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, Module, OpaqueTy, Path,
+ Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
+ TypeBindingKind, Typedef, Union, Variant, WherePredicate,
};
use crate::{item_kind::Kind, Error, ErrorKind};
@@ -32,7 +32,10 @@ pub struct Validator<'a> {
enum PathKind {
Trait,
- StructEnumUnion,
+ /// Structs, Enums, Unions and Typedefs.
+ ///
+ /// This doesn't include trait's because traits are not types.
+ Type,
}
impl<'a> Validator<'a> {
@@ -57,6 +60,8 @@ impl<'a> Validator<'a> {
fn check_item(&mut self, id: &'a Id) {
if let Some(item) = &self.krate.index.get(id) {
+ item.links.values().for_each(|id| self.add_any_id(id));
+
match &item.inner {
ItemEnum::Import(x) => self.check_import(x),
ItemEnum::Union(x) => self.check_union(x),
@@ -67,7 +72,6 @@ impl<'a> Validator<'a> {
ItemEnum::Function(x) => self.check_function(x),
ItemEnum::Trait(x) => self.check_trait(x),
ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
- ItemEnum::Method(x) => self.check_method(x),
ItemEnum::Impl(x) => self.check_impl(x),
ItemEnum::Typedef(x) => self.check_typedef(x),
ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x),
@@ -101,9 +105,9 @@ impl<'a> Validator<'a> {
fn check_import(&mut self, x: &'a Import) {
if x.glob {
- self.add_mod_id(x.id.as_ref().unwrap());
+ self.add_glob_import_item_id(x.id.as_ref().unwrap());
} else if let Some(id) = &x.id {
- self.add_mod_item_id(id);
+ self.add_import_item_id(id);
}
}
@@ -176,11 +180,6 @@ impl<'a> Validator<'a> {
x.params.iter().for_each(|i| self.check_generic_bound(i));
}
- fn check_method(&mut self, x: &'a Method) {
- self.check_fn_decl(&x.decl);
- self.check_generics(&x.generics);
- }
-
fn check_impl(&mut self, x: &'a Impl) {
self.check_generics(&x.generics);
if let Some(path) = &x.trait_ {
@@ -230,7 +229,7 @@ impl<'a> Validator<'a> {
fn check_type(&mut self, x: &'a Type) {
match x {
- Type::ResolvedPath(path) => self.check_path(path, PathKind::StructEnumUnion),
+ Type::ResolvedPath(path) => self.check_path(path, PathKind::Type),
Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
Type::Generic(_) => {}
Type::Primitive(_) => {}
@@ -269,8 +268,8 @@ impl<'a> Validator<'a> {
fn check_path(&mut self, x: &'a Path, kind: PathKind) {
match kind {
- PathKind::Trait => self.add_trait_id(&x.id),
- PathKind::StructEnumUnion => self.add_struct_enum_union_id(&x.id),
+ PathKind::Trait => self.add_trait_or_alias_id(&x.id),
+ PathKind::Type => self.add_type_id(&x.id),
}
if let Some(args) = &x.args {
self.check_generic_args(&**args);
@@ -379,6 +378,10 @@ impl<'a> Validator<'a> {
}
}
+ fn add_any_id(&mut self, id: &'a Id) {
+ self.add_id_checked(id, |_| true, "any kind of item");
+ }
+
fn add_field_id(&mut self, id: &'a Id) {
self.add_id_checked(id, Kind::is_struct_field, "StructField");
}
@@ -394,12 +397,12 @@ impl<'a> Validator<'a> {
self.add_id_checked(id, Kind::is_variant, "Variant");
}
- fn add_trait_id(&mut self, id: &'a Id) {
- self.add_id_checked(id, Kind::is_trait, "Trait");
+ fn add_trait_or_alias_id(&mut self, id: &'a Id) {
+ self.add_id_checked(id, Kind::is_trait_or_alias, "Trait (or TraitAlias)");
}
- fn add_struct_enum_union_id(&mut self, id: &'a Id) {
- self.add_id_checked(id, Kind::is_struct_enum_union, "Struct or Enum or Union");
+ fn add_type_id(&mut self, id: &'a Id) {
+ self.add_id_checked(id, Kind::is_type, "Type (Struct, Enum, Union or Typedef)");
}
/// Add an Id that appeared in a trait
@@ -407,6 +410,15 @@ impl<'a> Validator<'a> {
self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item");
}
+ /// Add an Id that can be `use`d
+ fn add_import_item_id(&mut self, id: &'a Id) {
+ self.add_id_checked(id, Kind::can_appear_in_import, "Import inner item");
+ }
+
+ fn add_glob_import_item_id(&mut self, id: &'a Id) {
+ self.add_id_checked(id, Kind::can_appear_in_glob_import, "Glob import inner item");
+ }
+
/// Add an Id that appeared in a mod
fn add_mod_item_id(&mut self, id: &'a Id) {
self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item")
@@ -440,3 +452,6 @@ fn set_remove<T: Hash + Eq + Clone>(set: &mut HashSet<T>) -> Option<T> {
None
}
}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
new file mode 100644
index 000000000..c4aeee9c5
--- /dev/null
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -0,0 +1,50 @@
+use std::collections::HashMap;
+
+use rustdoc_json_types::{Crate, Item, Visibility};
+
+use super::*;
+
+#[track_caller]
+fn check(krate: &Crate, errs: &[Error]) {
+ let mut validator = Validator::new(krate);
+ validator.check_crate();
+
+ assert_eq!(errs, &validator.errs[..]);
+}
+
+fn id(s: &str) -> Id {
+ Id(s.to_owned())
+}
+
+#[test]
+fn errors_on_missing_links() {
+ let k = Crate {
+ root: id("0"),
+ crate_version: None,
+ includes_private: false,
+ index: HashMap::from_iter([(
+ id("0"),
+ Item {
+ name: Some("root".to_owned()),
+ id: id(""),
+ crate_id: 0,
+ span: None,
+ visibility: Visibility::Public,
+ docs: None,
+ links: HashMap::from_iter([("Not Found".to_owned(), id("1"))]),
+ attrs: vec![],
+ deprecation: None,
+ inner: ItemEnum::Module(Module {
+ is_crate: true,
+ items: vec![],
+ is_stripped: false,
+ }),
+ },
+ )]),
+ paths: HashMap::new(),
+ external_crates: HashMap::new(),
+ format_version: rustdoc_json_types::FORMAT_VERSION,
+ };
+
+ check(&k, &[Error { kind: ErrorKind::NotFound, id: id("1") }]);
+}