]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/inspector.rs
TyCtxt::map is now called TyCtxt::hir
[rust.git] / clippy_lints / src / utils / inspector.rs
1 #![allow(print_stdout, use_debug)]
2
3 //! checks for attributes
4
5 use rustc::lint::*;
6 use rustc::hir;
7 use rustc::hir::print;
8 use syntax::ast::Attribute;
9 use syntax::attr;
10
11 /// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]` attribute
12 ///
13 /// **Example:**
14 /// ```rust
15 /// #[clippy_dump]
16 /// extern crate foo;
17 /// ```
18 ///
19 /// prints
20 ///
21 /// ```
22 /// item `foo`
23 /// visibility inherited from outer item
24 /// extern crate dylib source: "/path/to/foo.so"
25 /// ```
26 declare_lint! {
27     pub DEEP_CODE_INSPECTION,
28     Warn,
29     "helper to dump info about code"
30 }
31
32 pub struct Pass;
33
34 impl LintPass for Pass {
35     fn get_lints(&self) -> LintArray {
36         lint_array!(DEEP_CODE_INSPECTION)
37     }
38 }
39
40 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
41     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
42         if !has_attr(&item.attrs) {
43             return;
44         }
45         print_item(cx, item);
46     }
47
48     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
49         if !has_attr(&item.attrs) {
50             return;
51         }
52         println!("impl item `{}`", item.name);
53         match item.vis {
54             hir::Visibility::Public => println!("public"),
55             hir::Visibility::Crate => println!("visible crate wide"),
56             hir::Visibility::Restricted { ref path, .. } => {
57                 println!("visible in module `{}`",
58                          print::to_string(print::NO_ANN, |s| s.print_path(path, false)))
59             },
60             hir::Visibility::Inherited => println!("visibility inherited from outer item"),
61         }
62         if item.defaultness.is_default() {
63             println!("default");
64         }
65         match item.node {
66             hir::ImplItemKind::Const(_, body_id) => {
67                 println!("associated constant");
68                 print_expr(cx, &cx.tcx.hir.body(body_id).value, 1);
69             },
70             hir::ImplItemKind::Method(..) => println!("method"),
71             hir::ImplItemKind::Type(_) => println!("associated type"),
72         }
73     }
74     // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
75     // if !has_attr(&item.attrs) {
76     // return;
77     // }
78     // }
79     //
80     // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _:
81     // &hir::Generics) {
82     // if !has_attr(&var.node.attrs) {
83     // return;
84     // }
85     // }
86     //
87     // fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
88     // if !has_attr(&field.attrs) {
89     // return;
90     // }
91     // }
92     //
93
94     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
95         if !has_attr(&expr.attrs) {
96             return;
97         }
98         print_expr(cx, expr, 0);
99     }
100
101     fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
102         if !has_attr(&arm.attrs) {
103             return;
104         }
105         for pat in &arm.pats {
106             print_pat(cx, pat, 1);
107         }
108         if let Some(ref guard) = arm.guard {
109             println!("guard:");
110             print_expr(cx, guard, 1);
111         }
112         println!("body:");
113         print_expr(cx, &arm.body, 1);
114     }
115
116     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
117         if !has_attr(stmt.node.attrs()) {
118             return;
119         }
120         match stmt.node {
121             hir::StmtDecl(ref decl, _) => print_decl(cx, decl),
122             hir::StmtExpr(ref e, _) |
123             hir::StmtSemi(ref e, _) => print_expr(cx, e, 0),
124         }
125     }
126     // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) {
127     // if !has_attr(&item.attrs) {
128     // return;
129     // }
130     // }
131     //
132 }
133
134 fn has_attr(attrs: &[Attribute]) -> bool {
135     attr::contains_name(attrs, "clippy_dump")
136 }
137
138 fn print_decl(cx: &LateContext, decl: &hir::Decl) {
139     match decl.node {
140         hir::DeclLocal(ref local) => {
141             println!("local variable of type {}", cx.tables.node_id_to_type(local.id));
142             println!("pattern:");
143             print_pat(cx, &local.pat, 0);
144             if let Some(ref e) = local.init {
145                 println!("init expression:");
146                 print_expr(cx, e, 0);
147             }
148         },
149         hir::DeclItem(_) => println!("item decl"),
150     }
151 }
152
153 fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) {
154     let ind = "  ".repeat(indent);
155     let ty = cx.tables.node_id_to_type(expr.id);
156     println!("{}+", ind);
157     match expr.node {
158         hir::ExprBox(ref e) => {
159             println!("{}Box, {}", ind, ty);
160             print_expr(cx, e, indent + 1);
161         },
162         hir::ExprArray(ref v) => {
163             println!("{}Array, {}", ind, ty);
164             for e in v {
165                 print_expr(cx, e, indent + 1);
166             }
167         },
168         hir::ExprCall(ref func, ref args) => {
169             println!("{}Call, {}", ind, ty);
170             println!("{}function:", ind);
171             print_expr(cx, func, indent + 1);
172             println!("{}arguments:", ind);
173             for arg in args {
174                 print_expr(cx, arg, indent + 1);
175             }
176         },
177         hir::ExprMethodCall(ref name, _, ref args) => {
178             println!("{}MethodCall, {}", ind, ty);
179             println!("{}method name: {}", ind, name.node);
180             for arg in args {
181                 print_expr(cx, arg, indent + 1);
182             }
183         },
184         hir::ExprTup(ref v) => {
185             println!("{}Tup, {}", ind, ty);
186             for e in v {
187                 print_expr(cx, e, indent + 1);
188             }
189         },
190         hir::ExprBinary(op, ref lhs, ref rhs) => {
191             println!("{}Binary, {}", ind, ty);
192             println!("{}op: {:?}", ind, op.node);
193             println!("{}lhs:", ind);
194             print_expr(cx, lhs, indent + 1);
195             println!("{}rhs:", ind);
196             print_expr(cx, rhs, indent + 1);
197         },
198         hir::ExprUnary(op, ref inner) => {
199             println!("{}Unary, {}", ind, ty);
200             println!("{}op: {:?}", ind, op);
201             print_expr(cx, inner, indent + 1);
202         },
203         hir::ExprLit(ref lit) => {
204             println!("{}Lit, {}", ind, ty);
205             println!("{}{:?}", ind, lit);
206         },
207         hir::ExprCast(ref e, ref target) => {
208             println!("{}Cast, {}", ind, ty);
209             print_expr(cx, e, indent + 1);
210             println!("{}target type: {:?}", ind, target);
211         },
212         hir::ExprType(ref e, ref target) => {
213             println!("{}Type, {}", ind, ty);
214             print_expr(cx, e, indent + 1);
215             println!("{}target type: {:?}", ind, target);
216         },
217         hir::ExprIf(ref e, _, ref els) => {
218             println!("{}If, {}", ind, ty);
219             println!("{}condition:", ind);
220             print_expr(cx, e, indent + 1);
221             if let Some(ref els) = *els {
222                 println!("{}else:", ind);
223                 print_expr(cx, els, indent + 1);
224             }
225         },
226         hir::ExprWhile(ref cond, _, _) => {
227             println!("{}While, {}", ind, ty);
228             println!("{}condition:", ind);
229             print_expr(cx, cond, indent + 1);
230         },
231         hir::ExprLoop(..) => {
232             println!("{}Loop, {}", ind, ty);
233         },
234         hir::ExprMatch(ref cond, _, ref source) => {
235             println!("{}Match, {}", ind, ty);
236             println!("{}condition:", ind);
237             print_expr(cx, cond, indent + 1);
238             println!("{}source: {:?}", ind, source);
239         },
240         hir::ExprClosure(ref clause, _, _, _) => {
241             println!("{}Closure, {}", ind, ty);
242             println!("{}clause: {:?}", ind, clause);
243         },
244         hir::ExprBlock(_) => {
245             println!("{}Block, {}", ind, ty);
246         },
247         hir::ExprAssign(ref lhs, ref rhs) => {
248             println!("{}Assign, {}", ind, ty);
249             println!("{}lhs:", ind);
250             print_expr(cx, lhs, indent + 1);
251             println!("{}rhs:", ind);
252             print_expr(cx, rhs, indent + 1);
253         },
254         hir::ExprAssignOp(ref binop, ref lhs, ref rhs) => {
255             println!("{}AssignOp, {}", ind, ty);
256             println!("{}op: {:?}", ind, binop.node);
257             println!("{}lhs:", ind);
258             print_expr(cx, lhs, indent + 1);
259             println!("{}rhs:", ind);
260             print_expr(cx, rhs, indent + 1);
261         },
262         hir::ExprField(ref e, ref name) => {
263             println!("{}Field, {}", ind, ty);
264             println!("{}field name: {}", ind, name.node);
265             println!("{}struct expr:", ind);
266             print_expr(cx, e, indent + 1);
267         },
268         hir::ExprTupField(ref e, ref idx) => {
269             println!("{}TupField, {}", ind, ty);
270             println!("{}field index: {}", ind, idx.node);
271             println!("{}tuple expr:", ind);
272             print_expr(cx, e, indent + 1);
273         },
274         hir::ExprIndex(ref arr, ref idx) => {
275             println!("{}Index, {}", ind, ty);
276             println!("{}array expr:", ind);
277             print_expr(cx, arr, indent + 1);
278             println!("{}index expr:", ind);
279             print_expr(cx, idx, indent + 1);
280         },
281         hir::ExprPath(hir::QPath::Resolved(ref ty, ref path)) => {
282             println!("{}Resolved Path, {:?}", ind, ty);
283             println!("{}path: {:?}", ind, path);
284         },
285         hir::ExprPath(hir::QPath::TypeRelative(ref ty, ref seg)) => {
286             println!("{}Relative Path, {:?}", ind, ty);
287             println!("{}seg: {:?}", ind, seg);
288         },
289         hir::ExprAddrOf(ref muta, ref e) => {
290             println!("{}AddrOf, {}", ind, ty);
291             println!("mutability: {:?}", muta);
292             print_expr(cx, e, indent + 1);
293         },
294         hir::ExprBreak(_, ref e) => {
295             println!("{}Break, {}", ind, ty);
296             if let Some(ref e) = *e {
297                 print_expr(cx, e, indent + 1);
298             }
299         },
300         hir::ExprAgain(_) => println!("{}Again, {}", ind, ty),
301         hir::ExprRet(ref e) => {
302             println!("{}Ret, {}", ind, ty);
303             if let Some(ref e) = *e {
304                 print_expr(cx, e, indent + 1);
305             }
306         },
307         hir::ExprInlineAsm(_, ref input, ref output) => {
308             println!("{}InlineAsm, {}", ind, ty);
309             println!("{}inputs:", ind);
310             for e in input {
311                 print_expr(cx, e, indent + 1);
312             }
313             println!("{}outputs:", ind);
314             for e in output {
315                 print_expr(cx, e, indent + 1);
316             }
317         },
318         hir::ExprStruct(ref path, ref fields, ref base) => {
319             println!("{}Struct, {}", ind, ty);
320             println!("{}path: {:?}", ind, path);
321             for field in fields {
322                 println!("{}field \"{}\":", ind, field.name.node);
323                 print_expr(cx, &field.expr, indent + 1);
324             }
325             if let Some(ref base) = *base {
326                 println!("{}base:", ind);
327                 print_expr(cx, base, indent + 1);
328             }
329         },
330         hir::ExprRepeat(ref val, body_id) => {
331             println!("{}Repeat, {}", ind, ty);
332             println!("{}value:", ind);
333             print_expr(cx, val, indent + 1);
334             println!("{}repeat count:", ind);
335             print_expr(cx, &cx.tcx.hir.body(body_id).value, indent + 1);
336         },
337     }
338 }
339
340 fn print_item(cx: &LateContext, item: &hir::Item) {
341     let did = cx.tcx.hir.local_def_id(item.id);
342     println!("item `{}`", item.name);
343     match item.vis {
344         hir::Visibility::Public => println!("public"),
345         hir::Visibility::Crate => println!("visible crate wide"),
346         hir::Visibility::Restricted { ref path, .. } => {
347             println!("visible in module `{}`",
348                      print::to_string(print::NO_ANN, |s| s.print_path(path, false)))
349         },
350         hir::Visibility::Inherited => println!("visibility inherited from outer item"),
351     }
352     match item.node {
353         hir::ItemExternCrate(ref _renamed_from) => {
354             if let Some(crate_id) = cx.tcx.sess.cstore.extern_mod_stmt_cnum(item.id) {
355                 let source = cx.tcx.sess.cstore.used_crate_source(crate_id);
356                 if let Some(src) = source.dylib {
357                     println!("extern crate dylib source: {:?}", src.0);
358                 }
359                 if let Some(src) = source.rlib {
360                     println!("extern crate rlib source: {:?}", src.0);
361                 }
362             } else {
363                 println!("weird extern crate without a crate id");
364             }
365         },
366         hir::ItemUse(ref path, ref kind) => println!("{:?}, {:?}", path, kind),
367         hir::ItemStatic(..) => println!("static item of type {:#?}", cx.tcx.item_type(did)),
368         hir::ItemConst(..) => println!("const item of type {:#?}", cx.tcx.item_type(did)),
369         hir::ItemFn(..) => {
370             let item_ty = cx.tcx.item_type(did);
371             println!("function of type {:#?}", item_ty);
372         },
373         hir::ItemMod(..) => println!("module"),
374         hir::ItemForeignMod(ref fm) => println!("foreign module with abi: {}", fm.abi),
375         hir::ItemTy(..) => {
376             println!("type alias for {:?}", cx.tcx.item_type(did));
377         },
378         hir::ItemEnum(..) => {
379             println!("enum definition of type {:?}", cx.tcx.item_type(did));
380         },
381         hir::ItemStruct(..) => {
382             println!("struct definition of type {:?}", cx.tcx.item_type(did));
383         },
384         hir::ItemUnion(..) => {
385             println!("union definition of type {:?}", cx.tcx.item_type(did));
386         },
387         hir::ItemTrait(..) => {
388             println!("trait decl");
389             if cx.tcx.trait_has_default_impl(did) {
390                 println!("trait has a default impl");
391             } else {
392                 println!("trait has no default impl");
393             }
394         },
395         hir::ItemDefaultImpl(_, ref _trait_ref) => {
396             println!("default impl");
397         },
398         hir::ItemImpl(_, _, _, Some(ref _trait_ref), _, _) => {
399             println!("trait impl");
400         },
401         hir::ItemImpl(_, _, _, None, _, _) => {
402             println!("impl");
403         },
404     }
405 }
406
407 fn print_pat(cx: &LateContext, pat: &hir::Pat, indent: usize) {
408     let ind = "  ".repeat(indent);
409     println!("{}+", ind);
410     match pat.node {
411         hir::PatKind::Wild => println!("{}Wild", ind),
412         hir::PatKind::Binding(ref mode, _, ref name, ref inner) => {
413             println!("{}Binding", ind);
414             println!("{}mode: {:?}", ind, mode);
415             println!("{}name: {}", ind, name.node);
416             if let Some(ref inner) = *inner {
417                 println!("{}inner:", ind);
418                 print_pat(cx, inner, indent + 1);
419             }
420         },
421         hir::PatKind::Struct(ref path, ref fields, ignore) => {
422             println!("{}Struct", ind);
423             println!("{}name: {}",
424                      ind,
425                      print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)));
426             println!("{}ignore leftover fields: {}", ind, ignore);
427             println!("{}fields:", ind);
428             for field in fields {
429                 println!("{}  field name: {}", ind, field.node.name);
430                 if field.node.is_shorthand {
431                     println!("{}  in shorthand notation", ind);
432                 }
433                 print_pat(cx, &field.node.pat, indent + 1);
434             }
435         },
436         hir::PatKind::TupleStruct(ref path, ref fields, opt_dots_position) => {
437             println!("{}TupleStruct", ind);
438             println!("{}path: {}",
439                      ind,
440                      print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)));
441             if let Some(dot_position) = opt_dots_position {
442                 println!("{}dot position: {}", ind, dot_position);
443             }
444             for field in fields {
445                 print_pat(cx, field, indent + 1);
446             }
447         },
448         hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
449             println!("{}Resolved Path, {:?}", ind, ty);
450             println!("{}path: {:?}", ind, path);
451         },
452         hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
453             println!("{}Relative Path, {:?}", ind, ty);
454             println!("{}seg: {:?}", ind, seg);
455         },
456         hir::PatKind::Tuple(ref pats, opt_dots_position) => {
457             println!("{}Tuple", ind);
458             if let Some(dot_position) = opt_dots_position {
459                 println!("{}dot position: {}", ind, dot_position);
460             }
461             for field in pats {
462                 print_pat(cx, field, indent + 1);
463             }
464         },
465         hir::PatKind::Box(ref inner) => {
466             println!("{}Box", ind);
467             print_pat(cx, inner, indent + 1);
468         },
469         hir::PatKind::Ref(ref inner, ref muta) => {
470             println!("{}Ref", ind);
471             println!("{}mutability: {:?}", ind, muta);
472             print_pat(cx, inner, indent + 1);
473         },
474         hir::PatKind::Lit(ref e) => {
475             println!("{}Lit", ind);
476             print_expr(cx, e, indent + 1);
477         },
478         hir::PatKind::Range(ref l, ref r, ref range_end) => {
479             println!("{}Range", ind);
480             print_expr(cx, l, indent + 1);
481             print_expr(cx, r, indent + 1);
482             match *range_end {
483                 hir::RangeEnd::Included => println!("{} end included", ind),
484                 hir::RangeEnd::Excluded => println!("{} end excluded", ind),
485             }
486         },
487         hir::PatKind::Slice(ref first_pats, ref range, ref last_pats) => {
488             println!("{}Slice [a, b, ..i, y, z]", ind);
489             println!("[a, b]:");
490             for pat in first_pats {
491                 print_pat(cx, pat, indent + 1);
492             }
493             println!("i:");
494             if let Some(ref pat) = *range {
495                 print_pat(cx, pat, indent + 1);
496             }
497             println!("[y, z]:");
498             for pat in last_pats {
499                 print_pat(cx, pat, indent + 1);
500             }
501         },
502     }
503 }