1 use crate::ast;
2 use proc_macro2::Ident;
3 use syn;
4 
5 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
6 pub enum ImportedTypeKind {
7     /// The definition of an imported type.
8     Definition,
9     /// A reference to an imported type.
10     Reference,
11 }
12 
13 impl<T> ImportedTypes for Option<T>
14 where
15     T: ImportedTypes,
16 {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),17     fn imported_types<F>(&self, f: &mut F)
18     where
19         F: FnMut(&Ident, ImportedTypeKind),
20     {
21         if let Some(inner) = self {
22             inner.imported_types(f);
23         }
24     }
25 }
26 
27 /// Iterate over definitions of and references to imported types in the AST.
28 pub trait ImportedTypes {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind)29     fn imported_types<F>(&self, f: &mut F)
30     where
31         F: FnMut(&Ident, ImportedTypeKind);
32 }
33 
34 /// Iterate over definitions of imported types in the AST.
35 pub trait ImportedTypeDefinitions {
imported_type_definitions<F>(&self, f: &mut F) where F: FnMut(&Ident)36     fn imported_type_definitions<F>(&self, f: &mut F)
37     where
38         F: FnMut(&Ident);
39 }
40 
41 impl<T> ImportedTypeDefinitions for T
42 where
43     T: ImportedTypes,
44 {
imported_type_definitions<F>(&self, f: &mut F) where F: FnMut(&Ident),45     fn imported_type_definitions<F>(&self, f: &mut F)
46     where
47         F: FnMut(&Ident),
48     {
49         self.imported_types(&mut |id, kind| {
50             if let ImportedTypeKind::Definition = kind {
51                 f(id);
52             }
53         });
54     }
55 }
56 
57 /// Iterate over references to imported types in the AST.
58 pub trait ImportedTypeReferences {
imported_type_references<F>(&self, f: &mut F) where F: FnMut(&Ident)59     fn imported_type_references<F>(&self, f: &mut F)
60     where
61         F: FnMut(&Ident);
62 }
63 
64 impl<T> ImportedTypeReferences for T
65 where
66     T: ImportedTypes,
67 {
imported_type_references<F>(&self, f: &mut F) where F: FnMut(&Ident),68     fn imported_type_references<F>(&self, f: &mut F)
69     where
70         F: FnMut(&Ident),
71     {
72         self.imported_types(&mut |id, kind| {
73             if let ImportedTypeKind::Reference = kind {
74                 f(id);
75             }
76         });
77     }
78 }
79 
80 impl<'a, T: ImportedTypes> ImportedTypes for &'a T {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),81     fn imported_types<F>(&self, f: &mut F)
82     where
83         F: FnMut(&Ident, ImportedTypeKind),
84     {
85         (*self).imported_types(f)
86     }
87 }
88 
89 impl ImportedTypes for ast::Program {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),90     fn imported_types<F>(&self, f: &mut F)
91     where
92         F: FnMut(&Ident, ImportedTypeKind),
93     {
94         self.imports.imported_types(f);
95         self.consts.imported_types(f);
96         self.dictionaries.imported_types(f);
97     }
98 }
99 
100 impl<T> ImportedTypes for Vec<T>
101 where
102     T: ImportedTypes,
103 {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),104     fn imported_types<F>(&self, f: &mut F)
105     where
106         F: FnMut(&Ident, ImportedTypeKind),
107     {
108         for x in self {
109             x.imported_types(f);
110         }
111     }
112 }
113 
114 impl ImportedTypes for ast::Import {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),115     fn imported_types<F>(&self, f: &mut F)
116     where
117         F: FnMut(&Ident, ImportedTypeKind),
118     {
119         self.kind.imported_types(f)
120     }
121 }
122 
123 impl ImportedTypes for ast::ImportKind {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),124     fn imported_types<F>(&self, f: &mut F)
125     where
126         F: FnMut(&Ident, ImportedTypeKind),
127     {
128         match self {
129             ast::ImportKind::Static(s) => s.imported_types(f),
130             ast::ImportKind::Function(fun) => fun.imported_types(f),
131             ast::ImportKind::Type(ty) => ty.imported_types(f),
132             ast::ImportKind::Enum(enm) => enm.imported_types(f),
133         }
134     }
135 }
136 
137 impl ImportedTypes for ast::ImportStatic {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),138     fn imported_types<F>(&self, f: &mut F)
139     where
140         F: FnMut(&Ident, ImportedTypeKind),
141     {
142         self.ty.imported_types(f);
143     }
144 }
145 
146 impl ImportedTypes for syn::Type {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),147     fn imported_types<F>(&self, f: &mut F)
148     where
149         F: FnMut(&Ident, ImportedTypeKind),
150     {
151         match self {
152             syn::Type::Reference(ref r) => r.imported_types(f),
153             syn::Type::Path(ref p) => p.imported_types(f),
154             _ => {}
155         }
156     }
157 }
158 
159 impl ImportedTypes for syn::TypeReference {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),160     fn imported_types<F>(&self, f: &mut F)
161     where
162         F: FnMut(&Ident, ImportedTypeKind),
163     {
164         self.elem.imported_types(f);
165     }
166 }
167 
168 impl ImportedTypes for syn::TypePath {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),169     fn imported_types<F>(&self, f: &mut F)
170     where
171         F: FnMut(&Ident, ImportedTypeKind),
172     {
173         self.qself.imported_types(f);
174         self.path.imported_types(f);
175     }
176 }
177 
178 impl ImportedTypes for syn::QSelf {
imported_types<F>(&self, _: &mut F) where F: FnMut(&Ident, ImportedTypeKind),179     fn imported_types<F>(&self, _: &mut F)
180     where
181         F: FnMut(&Ident, ImportedTypeKind),
182     {
183         // TODO
184     }
185 }
186 
187 impl ImportedTypes for syn::Path {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),188     fn imported_types<F>(&self, f: &mut F)
189     where
190         F: FnMut(&Ident, ImportedTypeKind),
191     {
192         for seg in self.segments.iter() {
193             seg.arguments.imported_types(f);
194         }
195         f(
196             &self.segments.last().unwrap().ident,
197             ImportedTypeKind::Reference,
198         );
199     }
200 }
201 
202 impl ImportedTypes for syn::PathArguments {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),203     fn imported_types<F>(&self, f: &mut F)
204     where
205         F: FnMut(&Ident, ImportedTypeKind),
206     {
207         match self {
208             syn::PathArguments::AngleBracketed(data) => {
209                 for arg in data.args.iter() {
210                     arg.imported_types(f);
211                 }
212             }
213             //TOCHECK
214             syn::PathArguments::Parenthesized(data) => {
215                 for input in data.inputs.iter() {
216                     input.imported_types(f);
217                 }
218                 // TODO do we need to handle output here?
219                 // https://docs.rs/syn/0.14.0/syn/struct.ParenthesizedGenericArguments.html
220             }
221             syn::PathArguments::None => {}
222         }
223     }
224 }
225 
226 impl ImportedTypes for syn::GenericArgument {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),227     fn imported_types<F>(&self, f: &mut F)
228     where
229         F: FnMut(&Ident, ImportedTypeKind),
230     {
231         match self {
232             syn::GenericArgument::Lifetime(_) => {}
233             syn::GenericArgument::Type(ty) => ty.imported_types(f),
234             syn::GenericArgument::Binding(_) => {}    // TODO
235             syn::GenericArgument::Const(_) => {}      // TODO
236             syn::GenericArgument::Constraint(_) => {} // TODO
237         }
238     }
239 }
240 
241 impl ImportedTypes for ast::ImportFunction {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),242     fn imported_types<F>(&self, f: &mut F)
243     where
244         F: FnMut(&Ident, ImportedTypeKind),
245     {
246         self.function.imported_types(f);
247         self.kind.imported_types(f);
248     }
249 }
250 
251 impl ImportedTypes for ast::ImportFunctionKind {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),252     fn imported_types<F>(&self, f: &mut F)
253     where
254         F: FnMut(&Ident, ImportedTypeKind),
255     {
256         match self {
257             ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
258             ast::ImportFunctionKind::Normal => {}
259         }
260     }
261 }
262 
263 impl ImportedTypes for ast::Function {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),264     fn imported_types<F>(&self, f: &mut F)
265     where
266         F: FnMut(&Ident, ImportedTypeKind),
267     {
268         self.arguments.imported_types(f);
269         if let Some(ref r) = self.ret {
270             r.imported_types(f);
271         }
272     }
273 }
274 
275 impl ImportedTypes for syn::FnArg {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),276     fn imported_types<F>(&self, f: &mut F)
277     where
278         F: FnMut(&Ident, ImportedTypeKind),
279     {
280         match self {
281             syn::FnArg::Receiver(_) => {}
282             syn::FnArg::Typed(p) => p.imported_types(f),
283         }
284     }
285 }
286 
287 impl ImportedTypes for syn::PatType {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),288     fn imported_types<F>(&self, f: &mut F)
289     where
290         F: FnMut(&Ident, ImportedTypeKind),
291     {
292         self.ty.imported_types(f)
293     }
294 }
295 
296 impl ImportedTypes for ast::ImportType {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),297     fn imported_types<F>(&self, f: &mut F)
298     where
299         F: FnMut(&Ident, ImportedTypeKind),
300     {
301         f(&self.rust_name, ImportedTypeKind::Definition);
302         for class in self.extends.iter() {
303             class.imported_types(f);
304         }
305     }
306 }
307 
308 impl ImportedTypes for ast::ImportEnum {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),309     fn imported_types<F>(&self, f: &mut F)
310     where
311         F: FnMut(&Ident, ImportedTypeKind),
312     {
313         f(&self.name, ImportedTypeKind::Definition);
314     }
315 }
316 
317 impl ImportedTypes for ast::Const {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),318     fn imported_types<F>(&self, f: &mut F)
319     where
320         F: FnMut(&Ident, ImportedTypeKind),
321     {
322         self.ty.imported_types(f);
323     }
324 }
325 
326 impl ImportedTypes for ast::Dictionary {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),327     fn imported_types<F>(&self, f: &mut F)
328     where
329         F: FnMut(&Ident, ImportedTypeKind),
330     {
331         f(&self.name, ImportedTypeKind::Definition);
332         for field in self.fields.iter() {
333             field.imported_types(f);
334         }
335     }
336 }
337 
338 impl ImportedTypes for ast::DictionaryField {
imported_types<F>(&self, f: &mut F) where F: FnMut(&Ident, ImportedTypeKind),339     fn imported_types<F>(&self, f: &mut F)
340     where
341         F: FnMut(&Ident, ImportedTypeKind),
342     {
343         self.ty.imported_types(f);
344     }
345 }
346 
347 /// Remove any methods, statics, &c, that reference types that are *not*
348 /// defined.
349 pub trait RemoveUndefinedImports {
remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool where F: Fn(&Ident) -> bool350     fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
351     where
352         F: Fn(&Ident) -> bool;
353 }
354 
355 impl RemoveUndefinedImports for ast::Program {
remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool where F: Fn(&Ident) -> bool,356     fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
357     where
358         F: Fn(&Ident) -> bool,
359     {
360         let mut changed = self.imports.remove_undefined_imports(is_defined);
361         changed = self.consts.remove_undefined_imports(is_defined) || changed;
362 
363         for dictionary in self.dictionaries.iter_mut() {
364             let num_required =
365                 |dict: &ast::Dictionary| dict.fields.iter().filter(|f| f.required).count();
366             let before = num_required(dictionary);
367             changed = dictionary.fields.remove_undefined_imports(is_defined) || changed;
368 
369             // If a required field was removed we can no longer construct this
370             // dictionary so disable the constructor.
371             if before != num_required(dictionary) {
372                 dictionary.ctor = false;
373             }
374         }
375 
376         changed
377     }
378 }
379 
380 impl<T> RemoveUndefinedImports for Vec<T>
381 where
382     T: ImportedTypeReferences,
383 {
remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool where F: Fn(&Ident) -> bool,384     fn remove_undefined_imports<F>(&mut self, is_defined: &F) -> bool
385     where
386         F: Fn(&Ident) -> bool,
387     {
388         let before = self.len();
389         self.retain(|x| {
390             let mut all_defined = true;
391             x.imported_type_references(&mut |id| {
392                 if all_defined {
393                     if !is_defined(id) {
394                         log::info!("removing due to {} not being defined", id);
395                         all_defined = false;
396                     }
397                 }
398             });
399             all_defined
400         });
401         before != self.len()
402     }
403 }
404