]> git.lizzy.rs Git - rust.git/blob - src/tools/jsondoclint/src/validator.rs
jsondoclint: Tree Walk Validator
[rust.git] / src / tools / jsondoclint / src / validator.rs
1 use std::collections::HashSet;
2 use std::hash::Hash;
3
4 use rustdoc_json_types::{
5     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
6     GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Method, Module, OpaqueTy,
7     Path, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
8     TypeBindingKind, Typedef, Union, Variant, WherePredicate,
9 };
10
11 use crate::{item_kind::can_appear_in_mod, Error};
12
13 #[derive(Debug)]
14 pub struct Validator<'a> {
15     pub(crate) errs: Vec<Error>,
16     krate: &'a Crate,
17     seen_ids: HashSet<&'a Id>,
18     todo: HashSet<&'a Id>,
19 }
20
21 fn set_remove<T: Hash + Eq + Clone>(set: &mut HashSet<T>) -> Option<T> {
22     if let Some(id) = set.iter().next() {
23         let id = id.clone();
24         set.take(&id)
25     } else {
26         None
27     }
28 }
29
30 impl<'a> Validator<'a> {
31     pub fn new(krate: &'a Crate) -> Self {
32         Self { krate, errs: Vec::new(), seen_ids: HashSet::new(), todo: HashSet::new() }
33     }
34
35     pub fn check_crate(&mut self) {
36         let root = &self.krate.root;
37         self.add_mod_id(root);
38         while let Some(id) = set_remove(&mut self.todo) {
39             self.seen_ids.insert(id);
40             self.check_item(id);
41         }
42     }
43
44     fn check_item(&mut self, id: &'a Id) {
45         let item = &self.krate.index[id];
46         match &item.inner {
47             ItemEnum::Import(x) => self.check_import(x),
48             ItemEnum::Union(x) => self.check_union(x),
49             ItemEnum::Struct(x) => self.check_struct(x),
50             ItemEnum::StructField(x) => self.check_struct_field(x),
51             ItemEnum::Enum(x) => self.check_enum(x),
52             ItemEnum::Variant(x) => self.check_variant(x),
53             ItemEnum::Function(x) => self.check_function(x),
54             ItemEnum::Trait(x) => self.check_trait(x),
55             ItemEnum::TraitAlias(x) => self.check_trait_alias(x),
56             ItemEnum::Method(x) => self.check_method(x),
57             ItemEnum::Impl(x) => self.check_impl(x),
58             ItemEnum::Typedef(x) => self.check_typedef(x),
59             ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x),
60             ItemEnum::Constant(x) => self.check_constant(x),
61             ItemEnum::Static(x) => self.check_static(x),
62             ItemEnum::ForeignType => todo!(),
63             ItemEnum::Macro(x) => self.check_macro(x),
64             ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
65             ItemEnum::PrimitiveType(x) => self.check_primitive_type(x),
66             ItemEnum::Module(x) => self.check_module(x),
67
68             ItemEnum::ExternCrate { .. } => todo!(),
69             ItemEnum::AssocConst { .. } => todo!(),
70             ItemEnum::AssocType { .. } => todo!(),
71         }
72     }
73
74     // Core checkers
75     fn check_module(&mut self, module: &'a Module) {
76         module.items.iter().for_each(|i| self.add_mod_item_id(i));
77     }
78
79     fn check_import(&mut self, x: &'a Import) {
80         if x.glob {
81             self.add_mod_id(x.id.as_ref().unwrap());
82         } else if let Some(id) = &x.id {
83             self.add_mod_item_id(id);
84         }
85     }
86
87     fn check_union(&mut self, x: &'a Union) {
88         self.check_generics(&x.generics);
89         x.fields.iter().for_each(|i| self.add_field_id(i));
90         x.impls.iter().for_each(|i| self.add_impl_id(i));
91     }
92
93     fn check_struct(&mut self, x: &'a Struct) {
94         self.check_generics(&x.generics);
95         match &x.kind {
96             StructKind::Unit => {}
97             StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)),
98             StructKind::Plain { fields, fields_stripped: _ } => {
99                 fields.iter().for_each(|f| self.add_field_id(f))
100             }
101         }
102         x.impls.iter().for_each(|i| self.add_impl_id(i));
103     }
104
105     fn check_struct_field(&mut self, x: &'a Type) {
106         self.check_type(x);
107     }
108
109     fn check_enum(&mut self, x: &'a Enum) {
110         self.check_generics(&x.generics);
111         x.variants.iter().for_each(|i| self.add_variant_id(i));
112         x.impls.iter().for_each(|i| self.add_impl_id(i));
113     }
114
115     fn check_variant(&mut self, x: &'a Variant) {
116         match x {
117             Variant::Plain(_discriminant) => {} // TODO: Check discriminant value parses
118             Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
119             Variant::Struct { fields, fields_stripped: _ } => {
120                 fields.iter().for_each(|f| self.add_field_id(f))
121             }
122         }
123     }
124
125     fn check_function(&mut self, x: &'a Function) {
126         self.check_generics(&x.generics);
127         self.check_fn_decl(&x.decl);
128     }
129
130     fn check_trait(&mut self, x: &'a Trait) {
131         self.check_generics(&x.generics);
132         x.items.iter().for_each(|i| self.add_trait_item_id(i));
133         x.bounds.iter().for_each(|i| self.check_generic_bound(i));
134         x.implementations.iter().for_each(|i| self.add_impl_id(i));
135     }
136
137     fn check_trait_alias(&mut self, x: &'a TraitAlias) {
138         self.check_generics(&x.generics);
139         x.params.iter().for_each(|i| self.check_generic_bound(i));
140     }
141
142     fn check_method(&mut self, x: &'a Method) {
143         self.check_fn_decl(&x.decl);
144         self.check_generics(&x.generics);
145     }
146
147     fn check_impl(&mut self, x: &'a Impl) {
148         self.check_generics(&x.generics);
149         if let Some(path) = &x.trait_ {
150             self.check_path(path); // TODO: Check is trait.
151         }
152         self.check_type(&x.for_);
153         x.items.iter().for_each(|i| self.add_trait_item_id(i));
154         if let Some(blanket_impl) = &x.blanket_impl {
155             self.check_type(blanket_impl)
156         }
157     }
158
159     fn check_typedef(&mut self, x: &'a Typedef) {
160         self.check_generics(&x.generics);
161         self.check_type(&x.type_);
162     }
163
164     fn check_opaque_ty(&mut self, x: &'a OpaqueTy) {
165         x.bounds.iter().for_each(|b| self.check_generic_bound(b));
166         self.check_generics(&x.generics);
167     }
168
169     fn check_constant(&mut self, x: &'a Constant) {
170         self.check_type(&x.type_);
171     }
172
173     fn check_static(&mut self, x: &'a Static) {
174         self.check_type(&x.type_);
175     }
176
177     fn check_macro(&mut self, _: &'a str) {
178         // TODO
179     }
180
181     fn check_proc_macro(&mut self, _: &'a ProcMacro) {
182         // TODO
183     }
184
185     fn check_primitive_type(&mut self, _: &'a str) {
186         // TODO
187     }
188
189     fn check_generics(&mut self, x: &'a Generics) {
190         x.params.iter().for_each(|p| self.check_generic_param_def(p));
191         x.where_predicates.iter().for_each(|w| self.check_where_predicate(w));
192     }
193
194     fn check_type(&mut self, x: &'a Type) {
195         match x {
196             Type::ResolvedPath(path) => self.check_path(path),
197             Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
198             Type::Generic(_) => {}
199             Type::Primitive(_) => {}
200             Type::FunctionPointer(fp) => self.check_function_pointer(&**fp),
201             Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)),
202             Type::Slice(inner) => self.check_type(&**inner),
203             Type::Array { type_, len: _ } => self.check_type(&**type_),
204             Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)),
205             Type::Infer => {}
206             Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_),
207             Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_),
208             Type::QualifiedPath { name: _, args, self_type, trait_ } => {
209                 self.check_generic_args(&**args);
210                 self.check_type(&**self_type);
211                 self.check_path(trait_);
212             }
213         }
214     }
215
216     fn check_fn_decl(&mut self, x: &'a FnDecl) {
217         x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty));
218         if let Some(output) = &x.output {
219             self.check_type(output);
220         }
221     }
222
223     fn check_generic_bound(&mut self, x: &'a GenericBound) {
224         match x {
225             GenericBound::TraitBound { trait_, generic_params, modifier: _ } => {
226                 self.check_path(trait_);
227                 generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
228             }
229             GenericBound::Outlives(_) => todo!(),
230         }
231     }
232
233     fn check_path(&mut self, x: &'a Path) {
234         self.add_id(&x.id); // TODO: What kinds are allowed here.
235         if let Some(args) = &x.args {
236             self.check_generic_args(&**args);
237         }
238     }
239
240     fn check_generic_args(&mut self, x: &'a GenericArgs) {
241         match x {
242             GenericArgs::AngleBracketed { args, bindings } => {
243                 args.iter().for_each(|arg| self.check_generic_arg(arg));
244                 bindings.iter().for_each(|bind| self.check_type_binding(bind));
245             }
246             GenericArgs::Parenthesized { inputs, output } => {
247                 inputs.iter().for_each(|ty| self.check_type(ty));
248                 if let Some(o) = output {
249                     self.check_type(o);
250                 }
251             }
252         }
253     }
254
255     fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) {
256         match &gpd.kind {
257             rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {}
258             rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => {
259                 bounds.iter().for_each(|b| self.check_generic_bound(b));
260                 if let Some(ty) = default {
261                     self.check_type(ty);
262                 }
263             }
264             rustdoc_json_types::GenericParamDefKind::Const { type_, default: _ } => {
265                 self.check_type(type_)
266             }
267         }
268     }
269
270     fn check_generic_arg(&mut self, arg: &'a GenericArg) {
271         match arg {
272             GenericArg::Lifetime(_) => {}
273             GenericArg::Type(ty) => self.check_type(ty),
274             GenericArg::Const(c) => self.check_constant(c),
275             GenericArg::Infer => {}
276         }
277     }
278
279     fn check_type_binding(&mut self, bind: &'a TypeBinding) {
280         self.check_generic_args(&bind.args);
281         match &bind.binding {
282             TypeBindingKind::Equality(term) => self.check_term(term),
283             TypeBindingKind::Constraint(bounds) => {
284                 bounds.iter().for_each(|b| self.check_generic_bound(b))
285             }
286         }
287     }
288
289     fn check_term(&mut self, term: &'a Term) {
290         match term {
291             Term::Type(ty) => self.check_type(ty),
292             Term::Constant(con) => self.check_constant(con),
293         }
294     }
295
296     fn check_where_predicate(&mut self, w: &'a WherePredicate) {
297         match w {
298             WherePredicate::BoundPredicate { type_, bounds, generic_params } => {
299                 self.check_type(type_);
300                 bounds.iter().for_each(|b| self.check_generic_bound(b));
301                 generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
302             }
303             WherePredicate::RegionPredicate { lifetime: _, bounds } => {
304                 bounds.iter().for_each(|b| self.check_generic_bound(b));
305             }
306             WherePredicate::EqPredicate { lhs, rhs } => {
307                 self.check_type(lhs);
308                 self.check_term(rhs);
309             }
310         }
311     }
312
313     fn check_dyn_trait(&mut self, dyn_trait: &'a DynTrait) {
314         for pt in &dyn_trait.traits {
315             self.check_path(&pt.trait_);
316             pt.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
317         }
318     }
319
320     fn check_function_pointer(&mut self, fp: &'a FunctionPointer) {
321         self.check_fn_decl(&fp.decl);
322         fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
323     }
324
325     // Aux functions
326     fn add_id(&mut self, id: &'a Id) {
327         if !self.seen_ids.contains(id) {
328             self.todo.insert(id);
329         }
330     }
331
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);
336         } else {
337             self.fail(id, "Expecting field");
338         }
339     }
340
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         }
348     }
349
350     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         }
357     }
358
359     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         }
366     }
367
368     /// Add an Id that appeared in a trait
369     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         }
376     }
377
378     /// Add an Id that appeared in a mod
379     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         }
386     }
387
388     fn fail(&mut self, id: &Id, msg: &str) {
389         self.errs.push(Error { id: id.clone(), message: msg.to_string() });
390     }
391 }