jsondoclint: Add Kind abstraction

This commit is contained in:
Nixon Enraght-Moony 2022-08-24 19:44:32 +01:00
parent a7a4fe9ffa
commit bb1911db39
2 changed files with 212 additions and 65 deletions

View File

@ -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,
}
}
}

View File

@ -8,7 +8,7 @@
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 @@ fn add_id(&mut self, id: &'a Id) {
}
}
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<String>) {
self.errs.push(Error { id: id.clone(), message: message.into() });
}
fn kind_of(&mut self, id: &Id) -> Option<Kind> {
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
}
}
}