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(hir::Let { pat, init, ty, .. }) => {
146 print_pat(cx, pat, indent + 1);
147 if let Some(ty) = ty {
148 println!("{} type annotation: {:?}", ind, ty);
150 print_expr(cx, init, indent + 1);
152 hir::ExprKind::MethodCall(path, _, args, _) => {
153 println!("{}MethodCall", ind);
154 println!("{}method name: {}", ind, path.ident.name);
156 print_expr(cx, arg, indent + 1);
159 hir::ExprKind::Tup(v) => {
160 println!("{}Tup", ind);
162 print_expr(cx, e, indent + 1);
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);
173 hir::ExprKind::Unary(op, inner) => {
174 println!("{}Unary", ind);
175 println!("{}op: {:?}", ind, op);
176 print_expr(cx, inner, indent + 1);
178 hir::ExprKind::Lit(ref lit) => {
179 println!("{}Lit", ind);
180 println!("{}{:?}", ind, lit);
182 hir::ExprKind::Cast(e, target) => {
183 println!("{}Cast", ind);
184 print_expr(cx, e, indent + 1);
185 println!("{}target type: {:?}", ind, target);
187 hir::ExprKind::Type(e, target) => {
188 println!("{}Type", ind);
189 print_expr(cx, e, indent + 1);
190 println!("{}target type: {:?}", ind, target);
192 hir::ExprKind::Loop(..) => {
193 println!("{}Loop", ind);
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);
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);
210 hir::ExprKind::Closure(ref clause, _, _, _, _) => {
211 println!("{}Closure", ind);
212 println!("{}clause: {:?}", ind, clause);
214 hir::ExprKind::Yield(sub, _) => {
215 println!("{}Yield", ind);
216 print_expr(cx, sub, indent + 1);
218 hir::ExprKind::Block(_, _) => {
219 println!("{}Block", ind);
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);
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);
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);
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);
249 hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
250 println!("{}Resolved Path, {:?}", ind, ty);
251 println!("{}path: {:?}", ind, path);
253 hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
254 println!("{}Relative Path, {:?}", ind, ty);
255 println!("{}seg: {:?}", ind, seg);
257 hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
258 println!("{}Lang Item Path, {:?}", ind, lang_item.name());
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);
266 hir::ExprKind::Break(_, ref e) => {
267 println!("{}Break", ind);
268 if let Some(e) = *e {
269 print_expr(cx, e, indent + 1);
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);
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 {
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);
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);
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);
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);
314 if let Some(base) = *base {
315 println!("{}base:", ind);
316 print_expr(cx, base, indent + 1);
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);
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);
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)
336 hir::ExprKind::Err => {
337 println!("{}Err", ind);
339 hir::ExprKind::DropTemps(e) => {
340 println!("{}DropTemps", ind);
341 print_expr(cx, e, indent + 1);
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))
356 hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
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);
365 if let Some(ref src) = source.rlib {
366 println!("extern crate rlib source: {:?}", src.0);
369 println!("weird extern crate without a crate id");
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);
379 hir::ItemKind::Macro(ref macro_def) => {
380 if macro_def.macro_rules {
381 println!("macro introduced by `macro_rules!`");
383 println!("macro introduced by `macro`");
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));
392 hir::ItemKind::OpaqueTy(..) => {
393 println!("existential type with real type {:?}", cx.tcx.type_of(did));
395 hir::ItemKind::Enum(..) => {
396 println!("enum definition of type {:?}", cx.tcx.type_of(did));
398 hir::ItemKind::Struct(..) => {
399 println!("struct definition of type {:?}", cx.tcx.type_of(did));
401 hir::ItemKind::Union(..) => {
402 println!("union definition of type {:?}", cx.tcx.type_of(did));
404 hir::ItemKind::Trait(..) => {
405 println!("trait decl");
406 if cx.tcx.trait_is_auto(did.to_def_id()) {
407 println!("trait is auto");
409 println!("trait is not auto");
412 hir::ItemKind::TraitAlias(..) => {
413 println!("trait alias");
415 hir::ItemKind::Impl(hir::Impl {
416 of_trait: Some(ref _trait_ref),
419 println!("trait impl");
421 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) => {
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);
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);
443 hir::PatKind::Or(fields) => {
444 println!("{}Or", ind);
445 for field in fields {
446 print_pat(cx, field, indent + 1);
449 hir::PatKind::Struct(ref path, fields, ignore) => {
450 println!("{}Struct", ind);
454 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
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);
463 print_pat(cx, field.pat, indent + 1);
466 hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
467 println!("{}TupleStruct", ind);
471 rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
473 if let Some(dot_position) = opt_dots_position {
474 println!("{}dot position: {}", ind, dot_position);
476 for field in fields {
477 print_pat(cx, field, indent + 1);
480 hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
481 println!("{}Resolved Path, {:?}", ind, ty);
482 println!("{}path: {:?}", ind, path);
484 hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
485 println!("{}Relative Path, {:?}", ind, ty);
486 println!("{}seg: {:?}", ind, seg);
488 hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
489 println!("{}Lang Item Path, {:?}", ind, lang_item.name());
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);
497 print_pat(cx, field, indent + 1);
500 hir::PatKind::Box(inner) => {
501 println!("{}Box", ind);
502 print_pat(cx, inner, indent + 1);
504 hir::PatKind::Ref(inner, ref muta) => {
505 println!("{}Ref", ind);
506 println!("{}mutability: {:?}", ind, muta);
507 print_pat(cx, inner, indent + 1);
509 hir::PatKind::Lit(e) => {
510 println!("{}Lit", ind);
511 print_expr(cx, e, indent + 1);
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);
518 if let Some(expr) = r {
519 print_expr(cx, expr, indent + 1);
522 hir::RangeEnd::Included => println!("{} end included", ind),
523 hir::RangeEnd::Excluded => println!("{} end excluded", ind),
526 hir::PatKind::Slice(first_pats, ref range, last_pats) => {
527 println!("{}Slice [a, b, ..i, y, z]", ind);
529 for pat in first_pats {
530 print_pat(cx, pat, indent + 1);
533 if let Some(pat) = *range {
534 print_pat(cx, pat, indent + 1);
537 for pat in last_pats {
538 print_pat(cx, pat, indent + 1);
544 fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
545 let ind = " ".repeat(indent);
546 println!("{}+", ind);
548 hir::Guard::If(expr) => {
549 println!("{}If", ind);
550 print_expr(cx, expr, indent + 1);
552 hir::Guard::IfLet(pat, expr) => {
553 println!("{}IfLet", ind);
554 print_pat(cx, pat, indent + 1);
555 print_expr(cx, expr, indent + 1);