From bb1911db393047382ae040c23598e25984244644 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 24 Aug 2022 19:44:32 +0100 Subject: [PATCH] jsondoclint: Add `Kind` abstraction --- src/tools/jsondoclint/src/item_kind.rs | 203 +++++++++++++++++++++---- src/tools/jsondoclint/src/validator.rs | 74 +++++---- 2 files changed, 212 insertions(+), 65 deletions(-) diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 7c6c0b54379..15866ab6950 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -1,29 +1,180 @@ -use rustdoc_json_types::ItemEnum; +use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary}; -pub(crate) fn can_appear_in_mod(kind: &ItemEnum) -> bool { - match kind { - ItemEnum::Module(_) => true, - ItemEnum::ExternCrate { .. } => true, - ItemEnum::Import(_) => true, - ItemEnum::Union(_) => true, - ItemEnum::Struct(_) => true, - ItemEnum::StructField(_) => false, // Only in structs or variants - ItemEnum::Enum(_) => true, - ItemEnum::Variant(_) => false, // Only in enums - ItemEnum::Function(_) => true, - ItemEnum::Trait(_) => true, - ItemEnum::TraitAlias(_) => true, - ItemEnum::Method(_) => false, // Only in traits - ItemEnum::Impl(_) => true, - ItemEnum::Typedef(_) => true, - ItemEnum::OpaqueTy(_) => todo!("IDK"), // On - ItemEnum::Constant(_) => true, - ItemEnum::Static(_) => true, - ItemEnum::ForeignType => todo!("IDK"), - ItemEnum::Macro(_) => true, - ItemEnum::ProcMacro(_) => true, - ItemEnum::PrimitiveType(_) => todo!("IDK"), - ItemEnum::AssocConst { .. } => false, // Trait Only - ItemEnum::AssocType { .. } => false, // Trait only +// We want a univeral way to represent an `ItemEnum` or `ItemKind` + +#[derive(Debug)] +pub(crate) enum Kind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, + // Not in ItemKind + ProcMacro, + PrimitiveType, +} + +impl Kind { + pub fn can_appear_in_mod(self) -> bool { + use Kind::*; + match self { + Module => true, + ExternCrate => true, + Import => true, + Union => true, + Struct => true, + Enum => true, + Function => true, + Trait => true, + TraitAlias => true, + Impl => true, + Typedef => true, + Constant => true, + Static => true, + Macro => true, + ProcMacro => true, + + ForeignType => todo!("IDK"), + Keyword => todo!("IDK"), + OpaqueTy => todo!("IDK"), + Primitive => todo!("IDK"), + PrimitiveType => todo!("IDK"), + ProcAttribute => todo!("IDK"), + ProcDerive => todo!("IDK"), + + // 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_trait(self) -> bool { + match self { + Kind::AssocConst => true, + Kind::AssocType => true, + Kind::Method => true, + + Kind::Module => false, + Kind::ExternCrate => false, + Kind::Import => false, + Kind::Struct => false, + Kind::StructField => false, + Kind::Union => false, + Kind::Enum => false, + Kind::Variant => false, + Kind::Function => false, + Kind::Typedef => false, + Kind::OpaqueTy => false, + Kind::Constant => false, + Kind::Trait => false, + Kind::TraitAlias => false, + Kind::Impl => false, + Kind::Static => false, + Kind::ForeignType => false, + Kind::Macro => false, + Kind::ProcAttribute => false, + Kind::ProcDerive => false, + Kind::Primitive => false, + Kind::Keyword => false, + Kind::ProcMacro => false, + Kind::PrimitiveType => false, + } + } + + pub fn is_struct_field(self) -> bool { + matches!(self, Kind::StructField) + } + pub fn is_module(self) -> bool { + matches!(self, Kind::Module) + } + pub fn is_impl(self) -> bool { + matches!(self, Kind::Impl) + } + pub fn is_variant(self) -> bool { + matches!(self, Kind::Variant) + } + + pub fn from_item(i: &Item) -> Self { + use Kind::*; + match i.inner { + ItemEnum::Module(_) => Module, + ItemEnum::Import(_) => Import, + ItemEnum::Union(_) => Union, + ItemEnum::Struct(_) => Struct, + ItemEnum::StructField(_) => StructField, + ItemEnum::Enum(_) => Enum, + ItemEnum::Variant(_) => Variant, + ItemEnum::Function(_) => Function, + ItemEnum::Trait(_) => Trait, + ItemEnum::TraitAlias(_) => TraitAlias, + ItemEnum::Method(_) => Method, + ItemEnum::Impl(_) => Impl, + ItemEnum::Typedef(_) => Typedef, + ItemEnum::OpaqueTy(_) => OpaqueTy, + ItemEnum::Constant(_) => Constant, + ItemEnum::Static(_) => Static, + ItemEnum::Macro(_) => Macro, + ItemEnum::ProcMacro(_) => ProcMacro, + ItemEnum::PrimitiveType(_) => PrimitiveType, + ItemEnum::ForeignType => ForeignType, + ItemEnum::ExternCrate { .. } => ExternCrate, + ItemEnum::AssocConst { .. } => AssocConst, + ItemEnum::AssocType { .. } => AssocType, + } + } + + pub fn from_summary(s: &ItemSummary) -> Self { + use Kind::*; + match s.kind { + ItemKind::AssocConst => AssocConst, + ItemKind::AssocType => AssocType, + ItemKind::Constant => Constant, + ItemKind::Enum => Enum, + ItemKind::ExternCrate => ExternCrate, + ItemKind::ForeignType => ForeignType, + ItemKind::Function => Function, + ItemKind::Impl => Impl, + ItemKind::Import => Import, + ItemKind::Keyword => Keyword, + ItemKind::Macro => Macro, + ItemKind::Method => Method, + ItemKind::Module => Module, + ItemKind::OpaqueTy => OpaqueTy, + ItemKind::Primitive => Primitive, + ItemKind::ProcAttribute => ProcAttribute, + ItemKind::ProcDerive => ProcDerive, + ItemKind::Static => Static, + ItemKind::Struct => Struct, + ItemKind::StructField => StructField, + ItemKind::Trait => Trait, + ItemKind::TraitAlias => TraitAlias, + ItemKind::Typedef => Typedef, + ItemKind::Union => Union, + ItemKind::Variant => Variant, + } } } diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 2bb63bc3a44..b0e12479f92 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -8,7 +8,7 @@ use rustdoc_json_types::{ TypeBindingKind, Typedef, Union, Variant, WherePredicate, }; -use crate::{item_kind::can_appear_in_mod, Error}; +use crate::{item_kind::Kind, Error}; #[derive(Debug)] pub struct Validator<'a> { @@ -329,63 +329,59 @@ impl<'a> Validator<'a> { } } - fn add_field_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); + 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) { + self.add_id(id); + } else { + self.fail_expecting(id, expected); + } } else { - self.fail(id, "Expecting field"); + self.fail(id, "Not found") } } + fn add_field_id(&mut self, id: &'a Id) { + self.add_id_checked(id, Kind::is_struct_field, "StructField"); + } + fn add_mod_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::Module(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting module"); - } + self.add_id_checked(id, Kind::is_module, "Module"); } - fn add_impl_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting impl"); - } + self.add_id_checked(id, Kind::is_impl, "Impl"); } fn add_variant_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if let ItemEnum::StructField(_) = item.inner { - self.add_id(id); - } else { - self.fail(id, "Expecting variant"); - } + self.add_id_checked(id, Kind::is_variant, "Variant"); } /// Add an Id that appeared in a trait fn add_trait_item_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if !can_appear_in_mod(&item.inner) { - self.fail(id, "Expecting item that can appear in trait"); - } else { - self.add_id(id); - } + self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item"); } /// Add an Id that appeared in a mod fn add_mod_item_id(&mut self, id: &'a Id) { - let item = &self.krate.index[id]; - if can_appear_in_mod(&item.inner) { - self.add_id(id); - } else { - self.fail(id, "Expecting item that can appear in trait"); - } + self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item") } - fn fail(&mut self, id: &Id, msg: &str) { - self.errs.push(Error { id: id.clone(), message: msg.to_string() }); + fn fail_expecting(&mut self, id: &Id, expected: &str) { + let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong. + self.fail(id, format!("Expected {expected} but found {kind:?}")); + } + + fn fail(&mut self, id: &Id, message: impl Into) { + self.errs.push(Error { id: id.clone(), message: message.into() }); + } + + fn kind_of(&mut self, id: &Id) -> Option { + if let Some(item) = self.krate.index.get(id) { + Some(Kind::from_item(item)) + } else if let Some(summary) = self.krate.paths.get(id) { + Some(Kind::from_summary(summary)) + } else { + None + } } }