1 //! checks for attributes
3 use clippy_utils::get_attr;
4 use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
6 use rustc_lint::{LateContext, LateLintPass, LintContext};
7 use rustc_session::Session;
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
10 declare_clippy_lint! {
12 /// Dumps every ast/hir node which has the `#[clippy::dump]`
25 /// visibility inherited from outer item
26 /// extern crate dylib source: "/path/to/foo.so"
28 pub DEEP_CODE_INSPECTION,
30 "helper to dump info about code"
33 declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
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())) {
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())) {
47 println!("impl item `{}`", item.ident.name);
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))
55 hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
57 if item.defaultness.is_default() {
61 hir::ImplItemKind::Const(_, body_id) => {
62 println!("associated constant");
63 print_expr(cx, &cx.tcx.hir().body(body_id).value, 1);
65 hir::ImplItemKind::Fn(..) => println!("method"),
66 hir::ImplItemKind::TyAlias(_) => println!("associated type"),
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)) {
74 print_expr(cx, expr, 0);
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)) {
81 print_pat(cx, arm.pat, 1);
82 if let Some(ref guard) = arm.guard {
84 print_guard(cx, guard, 1);
87 print_expr(cx, arm.body, 1);
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)) {
95 hir::StmtKind::Local(local) => {
96 println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
98 print_pat(cx, local.pat, 0);
99 if let Some(e) = local.init {
100 println!("init expression:");
101 print_expr(cx, e, 0);
104 hir::StmtKind::Item(_) => println!("item decl"),
105 hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0),
110 fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
111 get_attr(sess, attrs, "dump").count() > 0
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));
121 "{}adjustments: {:?}",
123 cx.typeck_results().adjustments().get(expr.hir_id)
126 hir::ExprKind::Box(e) => {
127 println!("{}Box", ind);
128 print_expr(cx, e, indent + 1);
130 hir::ExprKind::Array(v) => {
131 println!("{}Array", ind);
133 print_expr(cx, e, indent + 1);
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);
142 print_expr(cx, arg, indent + 1);
145 hir::ExprKind::Let(pat, expr, _) => {
146 print_pat(cx, pat, indent + 1);
147 print_expr(cx, expr, indent + 1);
149 hir::ExprKind::MethodCall(path, _, args, _) => {
150 println!("{}MethodCall", ind);
151 println!("{}method name: {}", ind, path.ident.name);
153 print_expr(cx, arg, indent + 1);
156 hir::ExprKind::Tup(v) => {
157 println!("{}Tup", ind);
159 print_expr(cx, e, indent + 1);
162 hir::ExprKind::Binary(op, lhs, rhs) => {
163 println!("{}Binary", ind);
164 println!("{}op: {:?}", ind, op.node);
165 println!("{}lhs:", ind);
166 print_expr(cx, lhs, indent + 1);
167 println!("{}rhs:", ind);
168 print_expr(cx, rhs, indent + 1);
170 hir::ExprKind::Unary(op, inner) => {
171 println!("{}Unary", ind);
172 println!("{}op: {:?}", ind, op);
173 print_expr(cx, inner, indent + 1);
175 hir::ExprKind::Lit(ref lit) => {
176 println!("{}Lit", ind);
177 println!("{}{:?}", ind, lit);
179 hir::ExprKind::Cast(e, target) => {
180 println!("{}Cast", ind);
181 print_expr(cx, e, indent + 1);
182 println!("{}target type: {:?}", ind, target);
184 hir::ExprKind::Type(e, target) => {
185 println!("{}Type", ind);
186 print_expr(cx, e, indent + 1);
187 println!("{}target type: {:?}", ind, target);
189 hir::ExprKind::Loop(..) => {
190 println!("{}Loop", ind);
192 hir::ExprKind::If(cond, _, ref else_opt) => {
193 println!("{}If", ind);
194 println!("{}condition:", ind);
195 print_expr(cx, cond, indent + 1);
196 if let Some(els) = *else_opt {
197 println!("{}else:", ind);
198 print_expr(cx, els, indent + 1);
201 hir::ExprKind::Match(cond, _, ref source) => {
202 println!("{}Match", ind);
203 println!("{}condition:", ind);
204 print_expr(cx, cond, indent + 1);
205 println!("{}source: {:?}", ind, source);
207 hir::ExprKind::Closure(ref clause, _, _, _, _) => {
208 println!("{}Closure", ind);
209 println!("{}clause: {:?}", ind, clause);
211 hir::ExprKind::Yield(sub, _) => {
212 println!("{}Yield", ind);
213 print_expr(cx, sub, indent + 1);
215 hir::ExprKind::Block(_, _) => {
216 println!("{}Block", ind);
218 hir::ExprKind::Assign(lhs, rhs, _) => {
219 println!("{}Assign", ind);
220 println!("{}lhs:", ind);
221 print_expr(cx, lhs, indent + 1);
222 println!("{}rhs:", ind);
223 print_expr(cx, rhs, indent + 1);
225 hir::ExprKind::AssignOp(ref binop, lhs, rhs) => {
226 println!("{}AssignOp", ind);
227 println!("{}op: {:?}", ind, binop.node);
228 println!("{}lhs:", ind);
229 print_expr(cx, lhs, indent + 1);
230 println!("{}rhs:", ind);
231 print_expr(cx, rhs, indent + 1);
233 hir::ExprKind::Field(e, ident) => {
234 println!("{}Field", ind);
235 println!("{}field name: {}", ind, ident.name);
236 println!("{}struct expr:", ind);
237 print_expr(cx, e, indent + 1);
239 hir::ExprKind::Index(arr, idx) => {
240 println!("{}Index", ind);
241 println!("{}array expr:", ind);
242 print_expr(cx, arr, indent + 1);
243 println!("{}index expr:", ind);
244 print_expr(cx, idx, indent + 1);
246 hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
247 println!("{}Resolved Path, {:?}", ind, ty);
248 println!("{}path: {:?}", ind, path);
250 hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
251 println!("{}Relative Path, {:?}", ind, ty);
252 println!("{}seg: {:?}", ind, seg);
254 hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
255 println!("{}Lang Item Path, {:?}", ind, lang_item.name());
257 hir::ExprKind::AddrOf(kind, ref muta, e) => {
258 println!("{}AddrOf", ind);
259 println!("kind: {:?}", kind);
260 println!("mutability: {:?}", muta);
261 print_expr(cx, e, indent + 1);
263 hir::ExprKind::Break(_, ref e) => {
264 println!("{}Break", ind);
265 if let Some(e) = *e {
266 print_expr(cx, e, indent + 1);
269 hir::ExprKind::Continue(_) => println!("{}Again", ind),
270 hir::ExprKind::Ret(ref e) => {
271 println!("{}Ret", ind);
272 if let Some(e) = *e {
273 print_expr(cx, e, indent + 1);
276 hir::ExprKind::InlineAsm(asm) => {
277 println!("{}InlineAsm", ind);
278 println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
279 println!("{}options: {:?}", ind, asm.options);
280 println!("{}operands:", ind);
281 for (op, _op_sp) in asm.operands {
283 hir::InlineAsmOperand::In { expr, .. }
284 | hir::InlineAsmOperand::InOut { expr, .. }
285 | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1),
286 hir::InlineAsmOperand::Out { expr, .. } => {
287 if let Some(expr) = expr {
288 print_expr(cx, expr, indent + 1);
291 hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
292 print_expr(cx, in_expr, indent + 1);
293 if let Some(out_expr) = out_expr {
294 print_expr(cx, out_expr, indent + 1);
297 hir::InlineAsmOperand::Const { anon_const } => {
298 println!("{}anon_const:", ind);
299 print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
304 hir::ExprKind::LlvmInlineAsm(asm) => {
305 let inputs = &asm.inputs_exprs;
306 let outputs = &asm.outputs_exprs;
307 println!("{}LlvmInlineAsm", ind);
308 println!("{}inputs:", ind);
309 for e in inputs.iter() {
310 print_expr(cx, e, indent + 1);
312 println!("{}outputs:", ind);
313 for e in outputs.iter() {
314 print_expr(cx, e, indent + 1);
317 hir::ExprKind::Struct(path, fields, ref base) => {
318 println!("{}Struct", ind);
319 println!("{}path: {:?}", ind, path);
320 for field in fields {
321 println!("{}field \"{}\":", ind, field.ident.name);
322 print_expr(cx, field.expr, indent + 1);
324 if let Some(base) = *base {
325 println!("{}base:", ind);
326 print_expr(cx, base, indent + 1);
329 hir::ExprKind::ConstBlock(ref anon_const) => {
330 println!("{}ConstBlock", ind);
331 println!("{}anon_const:", ind);
332 print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
334 hir::ExprKind::Repeat(val, ref anon_const) => {
335 println!("{}Repeat", ind);
336 println!("{}value:", ind);
337 print_expr(cx, val, indent + 1);
338 println!("{}repeat count:", ind);
339 print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
341 hir::ExprKind::Err => {
342 println!("{}Err", ind);
344 hir::ExprKind::DropTemps(e) => {
345 println!("{}DropTemps", ind);
346 print_expr(cx, e, indent + 1);
351 fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
352 let did = item.def_id;
353 println!("item `{}`", item.ident.name);
354 match item.vis.node {
355 hir::VisibilityKind::Public => println!("public"),
356 hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
357 hir::VisibilityKind::Restricted { path, .. } => println!(
358 "visible in module `{}`",
359 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
361 hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
364 hir::ItemKind::ExternCrate(ref _renamed_from) => {
365 if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(did) {
366 let source = cx.tcx.used_crate_source(crate_id);
367 if let Some(ref src) = source.dylib {
368 println!("extern crate dylib source: {:?}", src.0);
370 if let Some(ref src) = source.rlib {
371 println!("extern crate rlib source: {:?}", src.0);
374 println!("weird extern crate without a crate id");
377 hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind),
378 hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
379 hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
380 hir::ItemKind::Fn(..) => {
381 let item_ty = cx.tcx.type_of(did);
382 println!("function of type {:#?}", item_ty);
384 hir::ItemKind::Macro(ref macro_def) => {
385 if macro_def.macro_rules {
386 println!("macro introduced by `macro_rules!`");
388 println!("macro introduced by `macro`");
391 hir::ItemKind::Mod(..) => println!("module"),
392 hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
393 hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),
394 hir::ItemKind::TyAlias(..) => {
395 println!("type alias for {:?}", cx.tcx.type_of(did));
397 hir::ItemKind::OpaqueTy(..) => {
398 println!("existential type with real type {:?}", cx.tcx.type_of(did));
400 hir::ItemKind::Enum(..) => {
401 println!("enum definition of type {:?}", cx.tcx.type_of(did));
403 hir::ItemKind::Struct(..) => {
404 println!("struct definition of type {:?}", cx.tcx.type_of(did));
406 hir::ItemKind::Union(..) => {
407 println!("union definition of type {:?}", cx.tcx.type_of(did));
409 hir::ItemKind::Trait(..) => {
410 println!("trait decl");
411 if cx.tcx.trait_is_auto(did.to_def_id()) {
412 println!("trait is auto");
414 println!("trait is not auto");
417 hir::ItemKind::TraitAlias(..) => {
418 println!("trait alias");
420 hir::ItemKind::Impl(hir::Impl {
421 of_trait: Some(ref _trait_ref),
424 println!("trait impl");
426 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) => {
432 #[allow(clippy::similar_names)]
433 #[allow(clippy::too_many_lines)]
434 fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
435 let ind = " ".repeat(indent);
436 println!("{}+", ind);
438 hir::PatKind::Wild => println!("{}Wild", ind),
439 hir::PatKind::Binding(ref mode, .., ident, ref inner) => {
440 println!("{}Binding", ind);
441 println!("{}mode: {:?}", ind, mode);
442 println!("{}name: {}", ind, ident.name);
443 if let Some(inner) = *inner {
444 println!("{}inner:", ind);
445 print_pat(cx, inner, indent + 1);
448 hir::PatKind::Or(fields) => {
449 println!("{}Or", ind);
450 for field in fields {
451 print_pat(cx, field, indent + 1);
454 hir::PatKind::Struct(ref path, fields, ignore) => {
455 println!("{}Struct", ind);
459 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
461 println!("{}ignore leftover fields: {}", ind, ignore);
462 println!("{}fields:", ind);
463 for field in fields {
464 println!("{} field name: {}", ind, field.ident.name);
465 if field.is_shorthand {
466 println!("{} in shorthand notation", ind);
468 print_pat(cx, field.pat, indent + 1);
471 hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
472 println!("{}TupleStruct", ind);
476 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
478 if let Some(dot_position) = opt_dots_position {
479 println!("{}dot position: {}", ind, dot_position);
481 for field in fields {
482 print_pat(cx, field, indent + 1);
485 hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
486 println!("{}Resolved Path, {:?}", ind, ty);
487 println!("{}path: {:?}", ind, path);
489 hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
490 println!("{}Relative Path, {:?}", ind, ty);
491 println!("{}seg: {:?}", ind, seg);
493 hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
494 println!("{}Lang Item Path, {:?}", ind, lang_item.name());
496 hir::PatKind::Tuple(pats, opt_dots_position) => {
497 println!("{}Tuple", ind);
498 if let Some(dot_position) = opt_dots_position {
499 println!("{}dot position: {}", ind, dot_position);
502 print_pat(cx, field, indent + 1);
505 hir::PatKind::Box(inner) => {
506 println!("{}Box", ind);
507 print_pat(cx, inner, indent + 1);
509 hir::PatKind::Ref(inner, ref muta) => {
510 println!("{}Ref", ind);
511 println!("{}mutability: {:?}", ind, muta);
512 print_pat(cx, inner, indent + 1);
514 hir::PatKind::Lit(e) => {
515 println!("{}Lit", ind);
516 print_expr(cx, e, indent + 1);
518 hir::PatKind::Range(ref l, ref r, ref range_end) => {
519 println!("{}Range", ind);
520 if let Some(expr) = l {
521 print_expr(cx, expr, indent + 1);
523 if let Some(expr) = r {
524 print_expr(cx, expr, indent + 1);
527 hir::RangeEnd::Included => println!("{} end included", ind),
528 hir::RangeEnd::Excluded => println!("{} end excluded", ind),
531 hir::PatKind::Slice(first_pats, ref range, last_pats) => {
532 println!("{}Slice [a, b, ..i, y, z]", ind);
534 for pat in first_pats {
535 print_pat(cx, pat, indent + 1);
538 if let Some(pat) = *range {
539 print_pat(cx, pat, indent + 1);
542 for pat in last_pats {
543 print_pat(cx, pat, indent + 1);
549 fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
550 let ind = " ".repeat(indent);
551 println!("{}+", ind);
553 hir::Guard::If(expr) => {
554 println!("{}If", ind);
555 print_expr(cx, expr, indent + 1);
557 hir::Guard::IfLet(pat, expr) => {
558 println!("{}IfLet", ind);
559 print_pat(cx, pat, indent + 1);
560 print_expr(cx, expr, indent + 1);