Skip to content

Commit bb1911d

Browse files
committed
jsondoclint: Add Kind abstraction
1 parent a7a4fe9 commit bb1911d

File tree

2 files changed

+213
-66
lines changed

2 files changed

+213
-66
lines changed
Lines changed: 178 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,180 @@
1-
use rustdoc_json_types::ItemEnum;
2-
3-
pub(crate) fn can_appear_in_mod(kind: &ItemEnum) -> bool {
4-
match kind {
5-
ItemEnum::Module(_) => true,
6-
ItemEnum::ExternCrate { .. } => true,
7-
ItemEnum::Import(_) => true,
8-
ItemEnum::Union(_) => true,
9-
ItemEnum::Struct(_) => true,
10-
ItemEnum::StructField(_) => false, // Only in structs or variants
11-
ItemEnum::Enum(_) => true,
12-
ItemEnum::Variant(_) => false, // Only in enums
13-
ItemEnum::Function(_) => true,
14-
ItemEnum::Trait(_) => true,
15-
ItemEnum::TraitAlias(_) => true,
16-
ItemEnum::Method(_) => false, // Only in traits
17-
ItemEnum::Impl(_) => true,
18-
ItemEnum::Typedef(_) => true,
19-
ItemEnum::OpaqueTy(_) => todo!("IDK"), // On
20-
ItemEnum::Constant(_) => true,
21-
ItemEnum::Static(_) => true,
22-
ItemEnum::ForeignType => todo!("IDK"),
23-
ItemEnum::Macro(_) => true,
24-
ItemEnum::ProcMacro(_) => true,
25-
ItemEnum::PrimitiveType(_) => todo!("IDK"),
26-
ItemEnum::AssocConst { .. } => false, // Trait Only
27-
ItemEnum::AssocType { .. } => false, // Trait only
1+
use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary};
2+
3+
// We want a univeral way to represent an `ItemEnum` or `ItemKind`
4+
5+
#[derive(Debug)]
6+
pub(crate) enum Kind {
7+
Module,
8+
ExternCrate,
9+
Import,
10+
Struct,
11+
StructField,
12+
Union,
13+
Enum,
14+
Variant,
15+
Function,
16+
Typedef,
17+
OpaqueTy,
18+
Constant,
19+
Trait,
20+
TraitAlias,
21+
Method,
22+
Impl,
23+
Static,
24+
ForeignType,
25+
Macro,
26+
ProcAttribute,
27+
ProcDerive,
28+
AssocConst,
29+
AssocType,
30+
Primitive,
31+
Keyword,
32+
// Not in ItemKind
33+
ProcMacro,
34+
PrimitiveType,
35+
}
36+
37+
impl Kind {
38+
pub fn can_appear_in_mod(self) -> bool {
39+
use Kind::*;
40+
match self {
41+
Module => true,
42+
ExternCrate => true,
43+
Import => true,
44+
Union => true,
45+
Struct => true,
46+
Enum => true,
47+
Function => true,
48+
Trait => true,
49+
TraitAlias => true,
50+
Impl => true,
51+
Typedef => true,
52+
Constant => true,
53+
Static => true,
54+
Macro => true,
55+
ProcMacro => true,
56+
57+
ForeignType => todo!("IDK"),
58+
Keyword => todo!("IDK"),
59+
OpaqueTy => todo!("IDK"),
60+
Primitive => todo!("IDK"),
61+
PrimitiveType => todo!("IDK"),
62+
ProcAttribute => todo!("IDK"),
63+
ProcDerive => todo!("IDK"),
64+
65+
// Only in traits
66+
AssocConst => false,
67+
AssocType => false,
68+
Method => false,
69+
70+
StructField => false, // Only in structs or variants
71+
Variant => false, // Only in enums
72+
}
73+
}
74+
75+
pub fn can_appear_in_trait(self) -> bool {
76+
match self {
77+
Kind::AssocConst => true,
78+
Kind::AssocType => true,
79+
Kind::Method => true,
80+
81+
Kind::Module => false,
82+
Kind::ExternCrate => false,
83+
Kind::Import => false,
84+
Kind::Struct => false,
85+
Kind::StructField => false,
86+
Kind::Union => false,
87+
Kind::Enum => false,
88+
Kind::Variant => false,
89+
Kind::Function => false,
90+
Kind::Typedef => false,
91+
Kind::OpaqueTy => false,
92+
Kind::Constant => false,
93+
Kind::Trait => false,
94+
Kind::TraitAlias => false,
95+
Kind::Impl => false,
96+
Kind::Static => false,
97+
Kind::ForeignType => false,
98+
Kind::Macro => false,
99+
Kind::ProcAttribute => false,
100+
Kind::ProcDerive => false,
101+
Kind::Primitive => false,
102+
Kind::Keyword => false,
103+
Kind::ProcMacro => false,
104+
Kind::PrimitiveType => false,
105+
}
106+
}
107+
108+
pub fn is_struct_field(self) -> bool {
109+
matches!(self, Kind::StructField)
110+
}
111+
pub fn is_module(self) -> bool {
112+
matches!(self, Kind::Module)
113+
}
114+
pub fn is_impl(self) -> bool {
115+
matches!(self, Kind::Impl)
116+
}
117+
pub fn is_variant(self) -> bool {
118+
matches!(self, Kind::Variant)
119+
}
120+
121+
pub fn from_item(i: &Item) -> Self {
122+
use Kind::*;
123+
match i.inner {
124+
ItemEnum::Module(_) => Module,
125+
ItemEnum::Import(_) => Import,
126+
ItemEnum::Union(_) => Union,
127+
ItemEnum::Struct(_) => Struct,
128+
ItemEnum::StructField(_) => StructField,
129+
ItemEnum::Enum(_) => Enum,
130+
ItemEnum::Variant(_) => Variant,
131+
ItemEnum::Function(_) => Function,
132+
ItemEnum::Trait(_) => Trait,
133+
ItemEnum::TraitAlias(_) => TraitAlias,
134+
ItemEnum::Method(_) => Method,
135+
ItemEnum::Impl(_) => Impl,
136+
ItemEnum::Typedef(_) => Typedef,
137+
ItemEnum::OpaqueTy(_) => OpaqueTy,
138+
ItemEnum::Constant(_) => Constant,
139+
ItemEnum::Static(_) => Static,
140+
ItemEnum::Macro(_) => Macro,
141+
ItemEnum::ProcMacro(_) => ProcMacro,
142+
ItemEnum::PrimitiveType(_) => PrimitiveType,
143+
ItemEnum::ForeignType => ForeignType,
144+
ItemEnum::ExternCrate { .. } => ExternCrate,
145+
ItemEnum::AssocConst { .. } => AssocConst,
146+
ItemEnum::AssocType { .. } => AssocType,
147+
}
148+
}
149+
150+
pub fn from_summary(s: &ItemSummary) -> Self {
151+
use Kind::*;
152+
match s.kind {
153+
ItemKind::AssocConst => AssocConst,
154+
ItemKind::AssocType => AssocType,
155+
ItemKind::Constant => Constant,
156+
ItemKind::Enum => Enum,
157+
ItemKind::ExternCrate => ExternCrate,
158+
ItemKind::ForeignType => ForeignType,
159+
ItemKind::Function => Function,
160+
ItemKind::Impl => Impl,
161+
ItemKind::Import => Import,
162+
ItemKind::Keyword => Keyword,
163+
ItemKind::Macro => Macro,
164+
ItemKind::Method => Method,
165+
ItemKind::Module => Module,
166+
ItemKind::OpaqueTy => OpaqueTy,
167+
ItemKind::Primitive => Primitive,
168+
ItemKind::ProcAttribute => ProcAttribute,
169+
ItemKind::ProcDerive => ProcDerive,
170+
ItemKind::Static => Static,
171+
ItemKind::Struct => Struct,
172+
ItemKind::StructField => StructField,
173+
ItemKind::Trait => Trait,
174+
ItemKind::TraitAlias => TraitAlias,
175+
ItemKind::Typedef => Typedef,
176+
ItemKind::Union => Union,
177+
ItemKind::Variant => Variant,
178+
}
28179
}
29180
}

src/tools/jsondoclint/src/validator.rs

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustdoc_json_types::{
88
TypeBindingKind, Typedef, Union, Variant, WherePredicate,
99
};
1010

11-
use crate::{item_kind::can_appear_in_mod, Error};
11+
use crate::{item_kind::Kind, Error};
1212

1313
#[derive(Debug)]
1414
pub struct Validator<'a> {
@@ -329,63 +329,59 @@ impl<'a> Validator<'a> {
329329
}
330330
}
331331

332-
fn add_field_id(&mut self, id: &'a Id) {
333-
let item = &self.krate.index[id];
334-
if let ItemEnum::StructField(_) = item.inner {
335-
self.add_id(id);
332+
fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
333+
if let Some(kind) = self.kind_of(id) {
334+
if valid(kind) {
335+
self.add_id(id);
336+
} else {
337+
self.fail_expecting(id, expected);
338+
}
336339
} else {
337-
self.fail(id, "Expecting field");
340+
self.fail(id, "Not found")
338341
}
339342
}
340343

341-
fn add_mod_id(&mut self, id: &'a Id) {
342-
let item = &self.krate.index[id];
343-
if let ItemEnum::Module(_) = item.inner {
344-
self.add_id(id);
345-
} else {
346-
self.fail(id, "Expecting module");
347-
}
344+
fn add_field_id(&mut self, id: &'a Id) {
345+
self.add_id_checked(id, Kind::is_struct_field, "StructField");
348346
}
349347

348+
fn add_mod_id(&mut self, id: &'a Id) {
349+
self.add_id_checked(id, Kind::is_module, "Module");
350+
}
350351
fn add_impl_id(&mut self, id: &'a Id) {
351-
let item = &self.krate.index[id];
352-
if let ItemEnum::StructField(_) = item.inner {
353-
self.add_id(id);
354-
} else {
355-
self.fail(id, "Expecting impl");
356-
}
352+
self.add_id_checked(id, Kind::is_impl, "Impl");
357353
}
358354

359355
fn add_variant_id(&mut self, id: &'a Id) {
360-
let item = &self.krate.index[id];
361-
if let ItemEnum::StructField(_) = item.inner {
362-
self.add_id(id);
363-
} else {
364-
self.fail(id, "Expecting variant");
365-
}
356+
self.add_id_checked(id, Kind::is_variant, "Variant");
366357
}
367358

368359
/// Add an Id that appeared in a trait
369360
fn add_trait_item_id(&mut self, id: &'a Id) {
370-
let item = &self.krate.index[id];
371-
if !can_appear_in_mod(&item.inner) {
372-
self.fail(id, "Expecting item that can appear in trait");
373-
} else {
374-
self.add_id(id);
375-
}
361+
self.add_id_checked(id, Kind::can_appear_in_trait, "Trait inner item");
376362
}
377363

378364
/// Add an Id that appeared in a mod
379365
fn add_mod_item_id(&mut self, id: &'a Id) {
380-
let item = &self.krate.index[id];
381-
if can_appear_in_mod(&item.inner) {
382-
self.add_id(id);
383-
} else {
384-
self.fail(id, "Expecting item that can appear in trait");
385-
}
366+
self.add_id_checked(id, Kind::can_appear_in_mod, "Module inner item")
367+
}
368+
369+
fn fail_expecting(&mut self, id: &Id, expected: &str) {
370+
let kind = self.kind_of(id).unwrap(); // We know it has a kind, as it's wrong.
371+
self.fail(id, format!("Expected {expected} but found {kind:?}"));
386372
}
387373

388-
fn fail(&mut self, id: &Id, msg: &str) {
389-
self.errs.push(Error { id: id.clone(), message: msg.to_string() });
374+
fn fail(&mut self, id: &Id, message: impl Into<String>) {
375+
self.errs.push(Error { id: id.clone(), message: message.into() });
376+
}
377+
378+
fn kind_of(&mut self, id: &Id) -> Option<Kind> {
379+
if let Some(item) = self.krate.index.get(id) {
380+
Some(Kind::from_item(item))
381+
} else if let Some(summary) = self.krate.paths.get(id) {
382+
Some(Kind::from_summary(summary))
383+
} else {
384+
None
385+
}
390386
}
391387
}

0 commit comments

Comments
 (0)