]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/utils/inspector.rs
fd3e51c2b32c3716f630e2c314f8a0a13213f07e
[rust.git] / src / tools / clippy / clippy_lints / src / utils / inspector.rs
1 //! checks for attributes
2
3 use clippy_utils::get_attr;
4 use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
5 use rustc_hir as hir;
6 use rustc_lint::{LateContext, LateLintPass, LintContext};
7 use rustc_session::Session;
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
9
10 declare_clippy_lint! {
11     /// ### What it does
12     /// Dumps every ast/hir node which has the `#[clippy::dump]`
13     /// attribute
14     ///
15     /// ### Example
16     /// ```rust,ignore
17     /// #[clippy::dump]
18     /// extern crate foo;
19     /// ```
20     ///
21     /// prints
22     ///
23     /// ```text
24     /// item `foo`
25     /// visibility inherited from outer item
26     /// extern crate dylib source: "/path/to/foo.so"
27     /// ```
28     pub DEEP_CODE_INSPECTION,
29     internal_warn,
30     "helper to dump info about code"
31 }
32
33 declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
34
35 impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
36     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
37         if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
38             return;
39         }
40         print_item(cx, item);
41     }
42
43     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
44         if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
45             return;
46         }
47         println!("impl item `{}`", item.ident.name);
48         match item.vis.node {
49             hir::VisibilityKind::Public => println!("public"),
50             hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
51             hir::VisibilityKind::Restricted { path, .. } => println!(
52                 "visible in module `{}`",
53                 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
54             ),
55             hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
56         }
57         if item.defaultness.is_default() {
58             println!("default");
59         }
60         match item.kind {
61             hir::ImplItemKind::Const(_, body_id) => {
62                 println!("associated constant");
63                 print_expr(cx, &cx.tcx.hir().body(body_id).value, 1);
64             },
65             hir::ImplItemKind::Fn(..) => println!("method"),
66             hir::ImplItemKind::TyAlias(_) => println!("associated type"),
67         }
68     }
69
70     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
71         if !has_attr(cx.sess(), cx.tcx.hir().attrs(expr.hir_id)) {
72             return;
73         }
74         print_expr(cx, expr, 0);
75     }
76
77     fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
78         if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) {
79             return;
80         }
81         print_pat(cx, arm.pat, 1);
82         if let Some(ref guard) = arm.guard {
83             println!("guard:");
84             print_guard(cx, guard, 1);
85         }
86         println!("body:");
87         print_expr(cx, arm.body, 1);
88     }
89
90     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
91         if !has_attr(cx.sess(), cx.tcx.hir().attrs(stmt.hir_id)) {
92             return;
93         }
94         match stmt.kind {
95             hir::StmtKind::Local(local) => {
96                 println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
97                 println!("pattern:");
98                 print_pat(cx, local.pat, 0);
99                 if let Some(e) = local.init {
100                     println!("init expression:");
101                     print_expr(cx, e, 0);
102                 }
103             },
104             hir::StmtKind::Item(_) => println!("item decl"),
105             hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0),
106         }
107     }
108 }
109
110 fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
111     get_attr(sess, attrs, "dump").count() > 0
112 }
113
114 #[allow(clippy::similar_names)]
115 #[allow(clippy::too_many_lines)]
116 fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
117     let ind = "  ".repeat(indent);
118     println!("{}+", ind);
119     println!("{}ty: {}", ind, cx.typeck_results().expr_ty(expr));
120     println!(
121         "{}adjustments: {:?}",
122         ind,
123         cx.typeck_results().adjustments().get(expr.hir_id)
124     );
125     match expr.kind {
126         hir::ExprKind::Box(e) => {
127             println!("{}Box", ind);
128             print_expr(cx, e, indent + 1);
129         },
130         hir::ExprKind::Array(v) => {
131             println!("{}Array", ind);
132             for e in v {
133                 print_expr(cx, e, indent + 1);
134             }
135         },
136         hir::ExprKind::Call(func, args) => {
137             println!("{}Call", ind);
138             println!("{}function:", ind);
139             print_expr(cx, func, indent + 1);
140             println!("{}arguments:", ind);
141             for arg in args {
142                 print_expr(cx, arg, indent + 1);
143             }
144         },
145         hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
146             print_pat(cx, pat, indent + 1);
147             if let Some(ty) = ty {
148                 println!("{}  type annotation: {:?}", ind, ty);
149             }
150             print_expr(cx, init, indent + 1);
151         },
152         hir::ExprKind::MethodCall(path, _, args, _) => {
153             println!("{}MethodCall", ind);
154             println!("{}method name: {}", ind, path.ident.name);
155             for arg in args {
156                 print_expr(cx, arg, indent + 1);
157             }
158         },
159         hir::ExprKind::Tup(v) => {
160             println!("{}Tup", ind);
161             for e in v {
162                 print_expr(cx, e, indent + 1);
163             }
164         },
165         hir::ExprKind::Binary(op, lhs, rhs) => {
166             println!("{}Binary", ind);
167             println!("{}op: {:?}", ind, op.node);
168             println!("{}lhs:", ind);
169             print_expr(cx, lhs, indent + 1);
170             println!("{}rhs:", ind);
171             print_expr(cx, rhs, indent + 1);
172         },
173         hir::ExprKind::Unary(op, inner) => {
174             println!("{}Unary", ind);
175             println!("{}op: {:?}", ind, op);
176             print_expr(cx, inner, indent + 1);
177         },
178         hir::ExprKind::Lit(ref lit) => {
179             println!("{}Lit", ind);
180             println!("{}{:?}", ind, lit);
181         },
182         hir::ExprKind::Cast(e, target) => {
183             println!("{}Cast", ind);
184             print_expr(cx, e, indent + 1);
185             println!("{}target type: {:?}", ind, target);
186         },
187         hir::ExprKind::Type(e, target) => {
188             println!("{}Type", ind);
189             print_expr(cx, e, indent + 1);
190             println!("{}target type: {:?}", ind, target);
191         },
192         hir::ExprKind::Loop(..) => {
193             println!("{}Loop", ind);
194         },
195         hir::ExprKind::If(cond, _, ref else_opt) => {
196             println!("{}If", ind);
197             println!("{}condition:", ind);
198             print_expr(cx, cond, indent + 1);
199             if let Some(els) = *else_opt {
200                 println!("{}else:", ind);
201                 print_expr(cx, els, indent + 1);
202             }
203         },
204         hir::ExprKind::Match(cond, _, ref source) => {
205             println!("{}Match", ind);
206             println!("{}condition:", ind);
207             print_expr(cx, cond, indent + 1);
208             println!("{}source: {:?}", ind, source);
209         },
210         hir::ExprKind::Closure(ref clause, _, _, _, _) => {
211             println!("{}Closure", ind);
212             println!("{}clause: {:?}", ind, clause);
213         },
214         hir::ExprKind::Yield(sub, _) => {
215             println!("{}Yield", ind);
216             print_expr(cx, sub, indent + 1);
217         },
218         hir::ExprKind::Block(_, _) => {
219             println!("{}Block", ind);
220         },
221         hir::ExprKind::Assign(lhs, rhs, _) => {
222             println!("{}Assign", ind);
223             println!("{}lhs:", ind);
224             print_expr(cx, lhs, indent + 1);
225             println!("{}rhs:", ind);
226             print_expr(cx, rhs, indent + 1);
227         },
228         hir::ExprKind::AssignOp(ref binop, lhs, rhs) => {
229             println!("{}AssignOp", ind);
230             println!("{}op: {:?}", ind, binop.node);
231             println!("{}lhs:", ind);
232             print_expr(cx, lhs, indent + 1);
233             println!("{}rhs:", ind);
234             print_expr(cx, rhs, indent + 1);
235         },
236         hir::ExprKind::Field(e, ident) => {
237             println!("{}Field", ind);
238             println!("{}field name: {}", ind, ident.name);
239             println!("{}struct expr:", ind);
240             print_expr(cx, e, indent + 1);
241         },
242         hir::ExprKind::Index(arr, idx) => {
243             println!("{}Index", ind);
244             println!("{}array expr:", ind);
245             print_expr(cx, arr, indent + 1);
246             println!("{}index expr:", ind);
247             print_expr(cx, idx, indent + 1);
248         },
249         hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
250             println!("{}Resolved Path, {:?}", ind, ty);
251             println!("{}path: {:?}", ind, path);
252         },
253         hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
254             println!("{}Relative Path, {:?}", ind, ty);
255             println!("{}seg: {:?}", ind, seg);
256         },
257         hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
258             println!("{}Lang Item Path, {:?}", ind, lang_item.name());
259         },
260         hir::ExprKind::AddrOf(kind, ref muta, e) => {
261             println!("{}AddrOf", ind);
262             println!("kind: {:?}", kind);
263             println!("mutability: {:?}", muta);
264             print_expr(cx, e, indent + 1);
265         },
266         hir::ExprKind::Break(_, ref e) => {
267             println!("{}Break", ind);
268             if let Some(e) = *e {
269                 print_expr(cx, e, indent + 1);
270             }
271         },
272         hir::ExprKind::Continue(_) => println!("{}Again", ind),
273         hir::ExprKind::Ret(ref e) => {
274             println!("{}Ret", ind);
275             if let Some(e) = *e {
276                 print_expr(cx, e, indent + 1);
277             }
278         },
279         hir::ExprKind::InlineAsm(asm) => {
280             println!("{}InlineAsm", ind);
281             println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
282             println!("{}options: {:?}", ind, asm.options);
283             println!("{}operands:", ind);
284             for (op, _op_sp) in asm.operands {
285                 match op {
286                     hir::InlineAsmOperand::In { expr, .. }
287                     | hir::InlineAsmOperand::InOut { expr, .. }
288                     | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1),
289                     hir::InlineAsmOperand::Out { expr, .. } => {
290                         if let Some(expr) = expr {
291                             print_expr(cx, expr, indent + 1);
292                         }
293                     },
294                     hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
295                         print_expr(cx, in_expr, indent + 1);
296                         if let Some(out_expr) = out_expr {
297                             print_expr(cx, out_expr, indent + 1);
298                         }
299                     },
300                     hir::InlineAsmOperand::Const { anon_const } => {
301                         println!("{}anon_const:", ind);
302                         print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
303                     },
304                 }
305             }
306         },
307         hir::ExprKind::Struct(path, fields, ref base) => {
308             println!("{}Struct", ind);
309             println!("{}path: {:?}", ind, path);
310             for field in fields {
311                 println!("{}field \"{}\":", ind, field.ident.name);
312                 print_expr(cx, field.expr, indent + 1);
313             }
314             if let Some(base) = *base {
315                 println!("{}base:", ind);
316                 print_expr(cx, base, indent + 1);
317             }
318         },
319         hir::ExprKind::ConstBlock(ref anon_const) => {
320             println!("{}ConstBlock", ind);
321             println!("{}anon_const:", ind);
322             print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
323         },
324         hir::ExprKind::Repeat(val, length) => {
325             println!("{}Repeat", ind);
326             println!("{}value:", ind);
327             print_expr(cx, val, indent + 1);
328             println!("{}repeat count:", ind);
329             match length {
330                 hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
331                 hir::ArrayLen::Body(anon_const) => {
332                     print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1)
333                 }
334             }
335         },
336         hir::ExprKind::Err => {
337             println!("{}Err", ind);
338         },
339         hir::ExprKind::DropTemps(e) => {
340             println!("{}DropTemps", ind);
341             print_expr(cx, e, indent + 1);
342         },
343     }
344 }
345
346 fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
347     let did = item.def_id;
348     println!("item `{}`", item.ident.name);
349     match item.vis.node {
350         hir::VisibilityKind::Public => println!("public"),
351         hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
352         hir::VisibilityKind::Restricted { path, .. } => println!(
353             "visible in module `{}`",
354             rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
355         ),
356         hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
357     }
358     match item.kind {
359         hir::ItemKind::ExternCrate(ref _renamed_from) => {
360             if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(did) {
361                 let source = cx.tcx.used_crate_source(crate_id);
362                 if let Some(ref src) = source.dylib {
363                     println!("extern crate dylib source: {:?}", src.0);
364                 }
365                 if let Some(ref src) = source.rlib {
366                     println!("extern crate rlib source: {:?}", src.0);
367                 }
368             } else {
369                 println!("weird extern crate without a crate id");
370             }
371         },
372         hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind),
373         hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
374         hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
375         hir::ItemKind::Fn(..) => {
376             let item_ty = cx.tcx.type_of(did);
377             println!("function of type {:#?}", item_ty);
378         },
379         hir::ItemKind::Macro(ref macro_def) => {
380             if macro_def.macro_rules {
381                 println!("macro introduced by `macro_rules!`");
382             } else {
383                 println!("macro introduced by `macro`");
384             }
385         },
386         hir::ItemKind::Mod(..) => println!("module"),
387         hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
388         hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),
389         hir::ItemKind::TyAlias(..) => {
390             println!("type alias for {:?}", cx.tcx.type_of(did));
391         },
392         hir::ItemKind::OpaqueTy(..) => {
393             println!("existential type with real type {:?}", cx.tcx.type_of(did));
394         },
395         hir::ItemKind::Enum(..) => {
396             println!("enum definition of type {:?}", cx.tcx.type_of(did));
397         },
398         hir::ItemKind::Struct(..) => {
399             println!("struct definition of type {:?}", cx.tcx.type_of(did));
400         },
401         hir::ItemKind::Union(..) => {
402             println!("union definition of type {:?}", cx.tcx.type_of(did));
403         },
404         hir::ItemKind::Trait(..) => {
405             println!("trait decl");
406             if cx.tcx.trait_is_auto(did.to_def_id()) {
407                 println!("trait is auto");
408             } else {
409                 println!("trait is not auto");
410             }
411         },
412         hir::ItemKind::TraitAlias(..) => {
413             println!("trait alias");
414         },
415         hir::ItemKind::Impl(hir::Impl {
416             of_trait: Some(ref _trait_ref),
417             ..
418         }) => {
419             println!("trait impl");
420         },
421         hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) => {
422             println!("impl");
423         },
424     }
425 }
426
427 #[allow(clippy::similar_names)]
428 #[allow(clippy::too_many_lines)]
429 fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
430     let ind = "  ".repeat(indent);
431     println!("{}+", ind);
432     match pat.kind {
433         hir::PatKind::Wild => println!("{}Wild", ind),
434         hir::PatKind::Binding(ref mode, .., ident, ref inner) => {
435             println!("{}Binding", ind);
436             println!("{}mode: {:?}", ind, mode);
437             println!("{}name: {}", ind, ident.name);
438             if let Some(inner) = *inner {
439                 println!("{}inner:", ind);
440                 print_pat(cx, inner, indent + 1);
441             }
442         },
443         hir::PatKind::Or(fields) => {
444             println!("{}Or", ind);
445             for field in fields {
446                 print_pat(cx, field, indent + 1);
447             }
448         },
449         hir::PatKind::Struct(ref path, fields, ignore) => {
450             println!("{}Struct", ind);
451             println!(
452                 "{}name: {}",
453                 ind,
454                 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
455             );
456             println!("{}ignore leftover fields: {}", ind, ignore);
457             println!("{}fields:", ind);
458             for field in fields {
459                 println!("{}  field name: {}", ind, field.ident.name);
460                 if field.is_shorthand {
461                     println!("{}  in shorthand notation", ind);
462                 }
463                 print_pat(cx, field.pat, indent + 1);
464             }
465         },
466         hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
467             println!("{}TupleStruct", ind);
468             println!(
469                 "{}path: {}",
470                 ind,
471                 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
472             );
473             if let Some(dot_position) = opt_dots_position {
474                 println!("{}dot position: {}", ind, dot_position);
475             }
476             for field in fields {
477                 print_pat(cx, field, indent + 1);
478             }
479         },
480         hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
481             println!("{}Resolved Path, {:?}", ind, ty);
482             println!("{}path: {:?}", ind, path);
483         },
484         hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
485             println!("{}Relative Path, {:?}", ind, ty);
486             println!("{}seg: {:?}", ind, seg);
487         },
488         hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
489             println!("{}Lang Item Path, {:?}", ind, lang_item.name());
490         },
491         hir::PatKind::Tuple(pats, opt_dots_position) => {
492             println!("{}Tuple", ind);
493             if let Some(dot_position) = opt_dots_position {
494                 println!("{}dot position: {}", ind, dot_position);
495             }
496             for field in pats {
497                 print_pat(cx, field, indent + 1);
498             }
499         },
500         hir::PatKind::Box(inner) => {
501             println!("{}Box", ind);
502             print_pat(cx, inner, indent + 1);
503         },
504         hir::PatKind::Ref(inner, ref muta) => {
505             println!("{}Ref", ind);
506             println!("{}mutability: {:?}", ind, muta);
507             print_pat(cx, inner, indent + 1);
508         },
509         hir::PatKind::Lit(e) => {
510             println!("{}Lit", ind);
511             print_expr(cx, e, indent + 1);
512         },
513         hir::PatKind::Range(ref l, ref r, ref range_end) => {
514             println!("{}Range", ind);
515             if let Some(expr) = l {
516                 print_expr(cx, expr, indent + 1);
517             }
518             if let Some(expr) = r {
519                 print_expr(cx, expr, indent + 1);
520             }
521             match *range_end {
522                 hir::RangeEnd::Included => println!("{} end included", ind),
523                 hir::RangeEnd::Excluded => println!("{} end excluded", ind),
524             }
525         },
526         hir::PatKind::Slice(first_pats, ref range, last_pats) => {
527             println!("{}Slice [a, b, ..i, y, z]", ind);
528             println!("[a, b]:");
529             for pat in first_pats {
530                 print_pat(cx, pat, indent + 1);
531             }
532             println!("i:");
533             if let Some(pat) = *range {
534                 print_pat(cx, pat, indent + 1);
535             }
536             println!("[y, z]:");
537             for pat in last_pats {
538                 print_pat(cx, pat, indent + 1);
539             }
540         },
541     }
542 }
543
544 fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
545     let ind = "  ".repeat(indent);
546     println!("{}+", ind);
547     match guard {
548         hir::Guard::If(expr) => {
549             println!("{}If", ind);
550             print_expr(cx, expr, indent + 1);
551         },
552         hir::Guard::IfLet(pat, expr) => {
553             println!("{}IfLet", ind);
554             print_pat(cx, pat, indent + 1);
555             print_expr(cx, expr, indent + 1);
556         },
557     }
558 }