]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/utils/inspector.rs
Auto merge of #3680 - g-bartoszek:needless-bool-else-if-brackets, r=oli-obk
[rust.git] / clippy_lints / src / utils / inspector.rs
1 //! checks for attributes
2
3 use crate::utils::get_attr;
4 use rustc::hir;
5 use rustc::hir::print;
6 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
7 use rustc::{declare_tool_lint, lint_array};
8 use syntax::ast::Attribute;
9
10 /// **What it does:** Dumps every ast/hir node which has the `#[clippy::dump]`
11 /// 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_clippy_lint! {
27     pub DEEP_CODE_INSPECTION,
28     internal_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.ident.name);
53         match item.vis.node {
54             hir::VisibilityKind::Public => println!("public"),
55             hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
56             hir::VisibilityKind::Restricted { ref path, .. } => println!(
57                 "visible in module `{}`",
58                 print::to_string(print::NO_ANN, |s| s.print_path(path, false))
59             ),
60             hir::VisibilityKind::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             hir::ImplItemKind::Existential(_) => println!("existential type"),
73         }
74     }
75     // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx
76     // hir::TraitItem) {
77     // if !has_attr(&item.attrs) {
78     // return;
79     // }
80     // }
81     //
82     // fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx
83     // hir::Variant, _:
84     // &hir::Generics) {
85     // if !has_attr(&var.node.attrs) {
86     // return;
87     // }
88     // }
89     //
90     // fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx
91     // hir::StructField) {
92     // if !has_attr(&field.attrs) {
93     // return;
94     // }
95     // }
96     //
97
98     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
99         if !has_attr(&expr.attrs) {
100             return;
101         }
102         print_expr(cx, expr, 0);
103     }
104
105     fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
106         if !has_attr(&arm.attrs) {
107             return;
108         }
109         for pat in &arm.pats {
110             print_pat(cx, pat, 1);
111         }
112         if let Some(ref guard) = arm.guard {
113             println!("guard:");
114             print_guard(cx, guard, 1);
115         }
116         println!("body:");
117         print_expr(cx, &arm.body, 1);
118     }
119
120     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
121         if !has_attr(stmt.node.attrs()) {
122             return;
123         }
124         match stmt.node {
125             hir::StmtKind::Local(ref local) => {
126                 println!("local variable of type {}", cx.tables.node_id_to_type(local.hir_id));
127                 println!("pattern:");
128                 print_pat(cx, &local.pat, 0);
129                 if let Some(ref e) = local.init {
130                     println!("init expression:");
131                     print_expr(cx, e, 0);
132                 }
133             },
134             hir::StmtKind::Item(_) => println!("item decl"),
135             hir::StmtKind::Expr(ref e) | hir::StmtKind::Semi(ref e) => print_expr(cx, e, 0),
136         }
137     }
138     // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx
139     // hir::ForeignItem) {
140     // if !has_attr(&item.attrs) {
141     // return;
142     // }
143     // }
144     //
145 }
146
147 fn has_attr(attrs: &[Attribute]) -> bool {
148     get_attr(attrs, "dump").count() > 0
149 }
150
151 #[allow(clippy::similar_names)]
152 fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr, indent: usize) {
153     let ind = "  ".repeat(indent);
154     println!("{}+", ind);
155     println!("{}ty: {}", ind, cx.tables.expr_ty(expr));
156     println!("{}adjustments: {:?}", ind, cx.tables.adjustments().get(expr.hir_id));
157     match expr.node {
158         hir::ExprKind::Box(ref e) => {
159             println!("{}Box", ind);
160             print_expr(cx, e, indent + 1);
161         },
162         hir::ExprKind::Array(ref v) => {
163             println!("{}Array", ind);
164             for e in v {
165                 print_expr(cx, e, indent + 1);
166             }
167         },
168         hir::ExprKind::Call(ref func, ref args) => {
169             println!("{}Call", ind);
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::ExprKind::MethodCall(ref path, _, ref args) => {
178             println!("{}MethodCall", ind);
179             println!("{}method name: {}", ind, path.ident.name);
180             for arg in args {
181                 print_expr(cx, arg, indent + 1);
182             }
183         },
184         hir::ExprKind::Tup(ref v) => {
185             println!("{}Tup", ind);
186             for e in v {
187                 print_expr(cx, e, indent + 1);
188             }
189         },
190         hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
191             println!("{}Binary", ind);
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::ExprKind::Unary(op, ref inner) => {
199             println!("{}Unary", ind);
200             println!("{}op: {:?}", ind, op);
201             print_expr(cx, inner, indent + 1);
202         },
203         hir::ExprKind::Lit(ref lit) => {
204             println!("{}Lit", ind);
205             println!("{}{:?}", ind, lit);
206         },
207         hir::ExprKind::Cast(ref e, ref target) => {
208             println!("{}Cast", ind);
209             print_expr(cx, e, indent + 1);
210             println!("{}target type: {:?}", ind, target);
211         },
212         hir::ExprKind::Type(ref e, ref target) => {
213             println!("{}Type", ind);
214             print_expr(cx, e, indent + 1);
215             println!("{}target type: {:?}", ind, target);
216         },
217         hir::ExprKind::If(ref e, _, ref els) => {
218             println!("{}If", ind);
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::ExprKind::While(ref cond, _, _) => {
227             println!("{}While", ind);
228             println!("{}condition:", ind);
229             print_expr(cx, cond, indent + 1);
230         },
231         hir::ExprKind::Loop(..) => {
232             println!("{}Loop", ind);
233         },
234         hir::ExprKind::Match(ref cond, _, ref source) => {
235             println!("{}Match", ind);
236             println!("{}condition:", ind);
237             print_expr(cx, cond, indent + 1);
238             println!("{}source: {:?}", ind, source);
239         },
240         hir::ExprKind::Closure(ref clause, _, _, _, _) => {
241             println!("{}Closure", ind);
242             println!("{}clause: {:?}", ind, clause);
243         },
244         hir::ExprKind::Yield(ref sub) => {
245             println!("{}Yield", ind);
246             print_expr(cx, sub, indent + 1);
247         },
248         hir::ExprKind::Block(_, _) => {
249             println!("{}Block", ind);
250         },
251         hir::ExprKind::Assign(ref lhs, ref rhs) => {
252             println!("{}Assign", ind);
253             println!("{}lhs:", ind);
254             print_expr(cx, lhs, indent + 1);
255             println!("{}rhs:", ind);
256             print_expr(cx, rhs, indent + 1);
257         },
258         hir::ExprKind::AssignOp(ref binop, ref lhs, ref rhs) => {
259             println!("{}AssignOp", ind);
260             println!("{}op: {:?}", ind, binop.node);
261             println!("{}lhs:", ind);
262             print_expr(cx, lhs, indent + 1);
263             println!("{}rhs:", ind);
264             print_expr(cx, rhs, indent + 1);
265         },
266         hir::ExprKind::Field(ref e, ident) => {
267             println!("{}Field", ind);
268             println!("{}field name: {}", ind, ident.name);
269             println!("{}struct expr:", ind);
270             print_expr(cx, e, indent + 1);
271         },
272         hir::ExprKind::Index(ref arr, ref idx) => {
273             println!("{}Index", ind);
274             println!("{}array expr:", ind);
275             print_expr(cx, arr, indent + 1);
276             println!("{}index expr:", ind);
277             print_expr(cx, idx, indent + 1);
278         },
279         hir::ExprKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
280             println!("{}Resolved Path, {:?}", ind, ty);
281             println!("{}path: {:?}", ind, path);
282         },
283         hir::ExprKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
284             println!("{}Relative Path, {:?}", ind, ty);
285             println!("{}seg: {:?}", ind, seg);
286         },
287         hir::ExprKind::AddrOf(ref muta, ref e) => {
288             println!("{}AddrOf", ind);
289             println!("mutability: {:?}", muta);
290             print_expr(cx, e, indent + 1);
291         },
292         hir::ExprKind::Break(_, ref e) => {
293             println!("{}Break", ind);
294             if let Some(ref e) = *e {
295                 print_expr(cx, e, indent + 1);
296             }
297         },
298         hir::ExprKind::Continue(_) => println!("{}Again", ind),
299         hir::ExprKind::Ret(ref e) => {
300             println!("{}Ret", ind);
301             if let Some(ref e) = *e {
302                 print_expr(cx, e, indent + 1);
303             }
304         },
305         hir::ExprKind::InlineAsm(_, ref input, ref output) => {
306             println!("{}InlineAsm", ind);
307             println!("{}inputs:", ind);
308             for e in input {
309                 print_expr(cx, e, indent + 1);
310             }
311             println!("{}outputs:", ind);
312             for e in output {
313                 print_expr(cx, e, indent + 1);
314             }
315         },
316         hir::ExprKind::Struct(ref path, ref fields, ref base) => {
317             println!("{}Struct", ind);
318             println!("{}path: {:?}", ind, path);
319             for field in fields {
320                 println!("{}field \"{}\":", ind, field.ident.name);
321                 print_expr(cx, &field.expr, indent + 1);
322             }
323             if let Some(ref base) = *base {
324                 println!("{}base:", ind);
325                 print_expr(cx, base, indent + 1);
326             }
327         },
328         hir::ExprKind::Repeat(ref val, ref anon_const) => {
329             println!("{}Repeat", ind);
330             println!("{}value:", ind);
331             print_expr(cx, val, indent + 1);
332             println!("{}repeat count:", ind);
333             print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
334         },
335         hir::ExprKind::Err => {
336             println!("{}Err", ind);
337         },
338     }
339 }
340
341 fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) {
342     let did = cx.tcx.hir().local_def_id(item.id);
343     println!("item `{}`", item.ident.name);
344     match item.vis.node {
345         hir::VisibilityKind::Public => println!("public"),
346         hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
347         hir::VisibilityKind::Restricted { ref path, .. } => println!(
348             "visible in module `{}`",
349             print::to_string(print::NO_ANN, |s| s.print_path(path, false))
350         ),
351         hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
352     }
353     match item.node {
354         hir::ItemKind::ExternCrate(ref _renamed_from) => {
355             let def_id = cx.tcx.hir().local_def_id(item.id);
356             if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(def_id) {
357                 let source = cx.tcx.used_crate_source(crate_id);
358                 if let Some(ref src) = source.dylib {
359                     println!("extern crate dylib source: {:?}", src.0);
360                 }
361                 if let Some(ref src) = source.rlib {
362                     println!("extern crate rlib source: {:?}", src.0);
363                 }
364             } else {
365                 println!("weird extern crate without a crate id");
366             }
367         },
368         hir::ItemKind::Use(ref path, ref kind) => println!("{:?}, {:?}", path, kind),
369         hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
370         hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
371         hir::ItemKind::Fn(..) => {
372             let item_ty = cx.tcx.type_of(did);
373             println!("function of type {:#?}", item_ty);
374         },
375         hir::ItemKind::Mod(..) => println!("module"),
376         hir::ItemKind::ForeignMod(ref fm) => println!("foreign module with abi: {}", fm.abi),
377         hir::ItemKind::GlobalAsm(ref asm) => println!("global asm: {:?}", asm),
378         hir::ItemKind::Ty(..) => {
379             println!("type alias for {:?}", cx.tcx.type_of(did));
380         },
381         hir::ItemKind::Existential(..) => {
382             println!("existential type with real type {:?}", cx.tcx.type_of(did));
383         },
384         hir::ItemKind::Enum(..) => {
385             println!("enum definition of type {:?}", cx.tcx.type_of(did));
386         },
387         hir::ItemKind::Struct(..) => {
388             println!("struct definition of type {:?}", cx.tcx.type_of(did));
389         },
390         hir::ItemKind::Union(..) => {
391             println!("union definition of type {:?}", cx.tcx.type_of(did));
392         },
393         hir::ItemKind::Trait(..) => {
394             println!("trait decl");
395             if cx.tcx.trait_is_auto(did) {
396                 println!("trait is auto");
397             } else {
398                 println!("trait is not auto");
399             }
400         },
401         hir::ItemKind::TraitAlias(..) => {
402             println!("trait alias");
403         },
404         hir::ItemKind::Impl(_, _, _, _, Some(ref _trait_ref), _, _) => {
405             println!("trait impl");
406         },
407         hir::ItemKind::Impl(_, _, _, _, None, _, _) => {
408             println!("impl");
409         },
410     }
411 }
412
413 #[allow(clippy::similar_names)]
414 fn print_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, indent: usize) {
415     let ind = "  ".repeat(indent);
416     println!("{}+", ind);
417     match pat.node {
418         hir::PatKind::Wild => println!("{}Wild", ind),
419         hir::PatKind::Binding(ref mode, _, ident, ref inner) => {
420             println!("{}Binding", ind);
421             println!("{}mode: {:?}", ind, mode);
422             println!("{}name: {}", ind, ident.name);
423             if let Some(ref inner) = *inner {
424                 println!("{}inner:", ind);
425                 print_pat(cx, inner, indent + 1);
426             }
427         },
428         hir::PatKind::Struct(ref path, ref fields, ignore) => {
429             println!("{}Struct", ind);
430             println!(
431                 "{}name: {}",
432                 ind,
433                 print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))
434             );
435             println!("{}ignore leftover fields: {}", ind, ignore);
436             println!("{}fields:", ind);
437             for field in fields {
438                 println!("{}  field name: {}", ind, field.node.ident.name);
439                 if field.node.is_shorthand {
440                     println!("{}  in shorthand notation", ind);
441                 }
442                 print_pat(cx, &field.node.pat, indent + 1);
443             }
444         },
445         hir::PatKind::TupleStruct(ref path, ref fields, opt_dots_position) => {
446             println!("{}TupleStruct", ind);
447             println!(
448                 "{}path: {}",
449                 ind,
450                 print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))
451             );
452             if let Some(dot_position) = opt_dots_position {
453                 println!("{}dot position: {}", ind, dot_position);
454             }
455             for field in fields {
456                 print_pat(cx, field, indent + 1);
457             }
458         },
459         hir::PatKind::Path(hir::QPath::Resolved(ref ty, ref path)) => {
460             println!("{}Resolved Path, {:?}", ind, ty);
461             println!("{}path: {:?}", ind, path);
462         },
463         hir::PatKind::Path(hir::QPath::TypeRelative(ref ty, ref seg)) => {
464             println!("{}Relative Path, {:?}", ind, ty);
465             println!("{}seg: {:?}", ind, seg);
466         },
467         hir::PatKind::Tuple(ref pats, opt_dots_position) => {
468             println!("{}Tuple", ind);
469             if let Some(dot_position) = opt_dots_position {
470                 println!("{}dot position: {}", ind, dot_position);
471             }
472             for field in pats {
473                 print_pat(cx, field, indent + 1);
474             }
475         },
476         hir::PatKind::Box(ref inner) => {
477             println!("{}Box", ind);
478             print_pat(cx, inner, indent + 1);
479         },
480         hir::PatKind::Ref(ref inner, ref muta) => {
481             println!("{}Ref", ind);
482             println!("{}mutability: {:?}", ind, muta);
483             print_pat(cx, inner, indent + 1);
484         },
485         hir::PatKind::Lit(ref e) => {
486             println!("{}Lit", ind);
487             print_expr(cx, e, indent + 1);
488         },
489         hir::PatKind::Range(ref l, ref r, ref range_end) => {
490             println!("{}Range", ind);
491             print_expr(cx, l, indent + 1);
492             print_expr(cx, r, indent + 1);
493             match *range_end {
494                 hir::RangeEnd::Included => println!("{} end included", ind),
495                 hir::RangeEnd::Excluded => println!("{} end excluded", ind),
496             }
497         },
498         hir::PatKind::Slice(ref first_pats, ref range, ref last_pats) => {
499             println!("{}Slice [a, b, ..i, y, z]", ind);
500             println!("[a, b]:");
501             for pat in first_pats {
502                 print_pat(cx, pat, indent + 1);
503             }
504             println!("i:");
505             if let Some(ref pat) = *range {
506                 print_pat(cx, pat, indent + 1);
507             }
508             println!("[y, z]:");
509             for pat in last_pats {
510                 print_pat(cx, pat, indent + 1);
511             }
512         },
513     }
514 }
515
516 fn print_guard(cx: &LateContext<'_, '_>, guard: &hir::Guard, indent: usize) {
517     let ind = "  ".repeat(indent);
518     println!("{}+", ind);
519     match guard {
520         hir::Guard::If(expr) => {
521             println!("{}If", ind);
522             print_expr(cx, expr, indent + 1);
523         },
524     }
525 }