about summary refs log tree commit diff
diff options
context:
space:
mode:
authorxFrednet <xFrednet@gmail.com>2022-04-15 11:37:58 +0200
committerxFrednet <xFrednet@gmail.com>2022-04-18 00:51:28 +0200
commitccedc64e3abc53795106d2fba027f59c06905eb4 (patch)
treede54101e1e6df0fa51e0378466c8ebc4a08612a2
parentb6645d022e492a20da31123f8aff5b5af3eb31c9 (diff)
downloadrust-ccedc64e3abc53795106d2fba027f59c06905eb4.tar.gz
rust-ccedc64e3abc53795106d2fba027f59c06905eb4.zip
Add `#[clippy::print_hir]` attribute for debugging
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/utils/dump_hir.rs55
-rw-r--r--clippy_lints/src/utils/inspector.rs555
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs2
-rw-r--r--clippy_lints/src/utils/mod.rs2
-rw-r--r--doc/adding_lints.md14
6 files changed, 72 insertions, 558 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 604bd44c6c5..c5d02ca278e 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -501,7 +501,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
-        store.register_late_pass(|| Box::new(utils::inspector::DeepCodeInspector));
         store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
         store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
         store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
@@ -513,6 +512,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
+    store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|| Box::new(utils::author::Author));
     store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
     store.register_late_pass(|| Box::new(serde_api::SerdeApi));
diff --git a/clippy_lints/src/utils/dump_hir.rs b/clippy_lints/src/utils/dump_hir.rs
new file mode 100644
index 00000000000..01efc527a8c
--- /dev/null
+++ b/clippy_lints/src/utils/dump_hir.rs
@@ -0,0 +1,55 @@
+use clippy_utils::get_attr;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// It formats the attached node with `{:#?}` and writes the result to the
+    /// standard output. This is intended for debugging.
+    ///
+    /// ### Examples
+    /// ```rs
+    /// #[clippy::dump]
+    /// use std::mem;
+    ///
+    /// #[clippy::dump]
+    /// fn foo(input: u32) -> u64 {
+    ///     input as u64
+    /// }
+    /// ```
+    pub DUMP_HIR,
+    internal_warn,
+    "helper to dump info about code"
+}
+
+declare_lint_pass!(DumpHir => [DUMP_HIR]);
+
+impl<'tcx> LateLintPass<'tcx> for DumpHir {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+        if has_attr(cx, item.hir_id()) {
+            println!("{item:#?}");
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if has_attr(cx, expr.hir_id) {
+            println!("{expr:#?}");
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
+        match stmt.kind {
+            hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) if has_attr(cx, e.hir_id) => return,
+            _ => {},
+        }
+        if has_attr(cx, stmt.hir_id) {
+            println!("{stmt:#?}");
+        }
+    }
+}
+
+fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
+    let attrs = cx.tcx.hir().attrs(hir_id);
+    get_attr(cx.sess(), attrs, "dump").count() > 0
+}
diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs
deleted file mode 100644
index dc48ea3f4f9..00000000000
--- a/clippy_lints/src/utils/inspector.rs
+++ /dev/null
@@ -1,555 +0,0 @@
-//! checks for attributes
-
-use clippy_utils::get_attr;
-use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece};
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::Session;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Dumps every ast/hir node which has the `#[clippy::dump]`
-    /// attribute
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// #[clippy::dump]
-    /// extern crate foo;
-    /// ```
-    ///
-    /// prints
-    ///
-    /// ```text
-    /// item `foo`
-    /// visibility inherited from outer item
-    /// extern crate dylib source: "/path/to/foo.so"
-    /// ```
-    pub DEEP_CODE_INSPECTION,
-    internal_warn,
-    "helper to dump info about code"
-}
-
-declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
-
-impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
-            return;
-        }
-        print_item(cx, item);
-    }
-
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(item.hir_id())) {
-            return;
-        }
-        println!("impl item `{}`", item.ident.name);
-        match item.vis.node {
-            hir::VisibilityKind::Public => println!("public"),
-            hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-            hir::VisibilityKind::Restricted { path, .. } => println!(
-                "visible in module `{}`",
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
-            ),
-            hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
-        }
-        match item.kind {
-            hir::ImplItemKind::Const(_, body_id) => {
-                println!("associated constant");
-                print_expr(cx, &cx.tcx.hir().body(body_id).value, 1);
-            },
-            hir::ImplItemKind::Fn(..) => println!("method"),
-            hir::ImplItemKind::TyAlias(_) => println!("associated type"),
-        }
-    }
-
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(expr.hir_id)) {
-            return;
-        }
-        print_expr(cx, expr, 0);
-    }
-
-    fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(arm.hir_id)) {
-            return;
-        }
-        print_pat(cx, arm.pat, 1);
-        if let Some(ref guard) = arm.guard {
-            println!("guard:");
-            print_guard(cx, guard, 1);
-        }
-        println!("body:");
-        print_expr(cx, arm.body, 1);
-    }
-
-    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
-        if !has_attr(cx.sess(), cx.tcx.hir().attrs(stmt.hir_id)) {
-            return;
-        }
-        match stmt.kind {
-            hir::StmtKind::Local(local) => {
-                println!("local variable of type {}", cx.typeck_results().node_type(local.hir_id));
-                println!("pattern:");
-                print_pat(cx, local.pat, 0);
-                if let Some(e) = local.init {
-                    println!("init expression:");
-                    print_expr(cx, e, 0);
-                }
-            },
-            hir::StmtKind::Item(_) => println!("item decl"),
-            hir::StmtKind::Expr(e) | hir::StmtKind::Semi(e) => print_expr(cx, e, 0),
-        }
-    }
-}
-
-fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
-    get_attr(sess, attrs, "dump").count() > 0
-}
-
-#[allow(clippy::similar_names)]
-#[allow(clippy::too_many_lines)]
-fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    println!("{}ty: {}", ind, cx.typeck_results().expr_ty(expr));
-    println!(
-        "{}adjustments: {:?}",
-        ind,
-        cx.typeck_results().adjustments().get(expr.hir_id)
-    );
-    match expr.kind {
-        hir::ExprKind::Box(e) => {
-            println!("{}Box", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Array(v) => {
-            println!("{}Array", ind);
-            for e in v {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Call(func, args) => {
-            println!("{}Call", ind);
-            println!("{}function:", ind);
-            print_expr(cx, func, indent + 1);
-            println!("{}arguments:", ind);
-            for arg in args {
-                print_expr(cx, arg, indent + 1);
-            }
-        },
-        hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
-            print_pat(cx, pat, indent + 1);
-            if let Some(ty) = ty {
-                println!("{}  type annotation: {:?}", ind, ty);
-            }
-            print_expr(cx, init, indent + 1);
-        },
-        hir::ExprKind::MethodCall(path, args, _) => {
-            println!("{}MethodCall", ind);
-            println!("{}method name: {}", ind, path.ident.name);
-            for arg in args {
-                print_expr(cx, arg, indent + 1);
-            }
-        },
-        hir::ExprKind::Tup(v) => {
-            println!("{}Tup", ind);
-            for e in v {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Binary(op, lhs, rhs) => {
-            println!("{}Binary", ind);
-            println!("{}op: {:?}", ind, op.node);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::Unary(op, inner) => {
-            println!("{}Unary", ind);
-            println!("{}op: {:?}", ind, op);
-            print_expr(cx, inner, indent + 1);
-        },
-        hir::ExprKind::Lit(ref lit) => {
-            println!("{}Lit", ind);
-            println!("{}{:?}", ind, lit);
-        },
-        hir::ExprKind::Cast(e, target) => {
-            println!("{}Cast", ind);
-            print_expr(cx, e, indent + 1);
-            println!("{}target type: {:?}", ind, target);
-        },
-        hir::ExprKind::Type(e, target) => {
-            println!("{}Type", ind);
-            print_expr(cx, e, indent + 1);
-            println!("{}target type: {:?}", ind, target);
-        },
-        hir::ExprKind::Loop(..) => {
-            println!("{}Loop", ind);
-        },
-        hir::ExprKind::If(cond, _, ref else_opt) => {
-            println!("{}If", ind);
-            println!("{}condition:", ind);
-            print_expr(cx, cond, indent + 1);
-            if let Some(els) = *else_opt {
-                println!("{}else:", ind);
-                print_expr(cx, els, indent + 1);
-            }
-        },
-        hir::ExprKind::Match(cond, _, ref source) => {
-            println!("{}Match", ind);
-            println!("{}condition:", ind);
-            print_expr(cx, cond, indent + 1);
-            println!("{}source: {:?}", ind, source);
-        },
-        hir::ExprKind::Closure(ref clause, _, _, _, _) => {
-            println!("{}Closure", ind);
-            println!("{}clause: {:?}", ind, clause);
-        },
-        hir::ExprKind::Yield(sub, _) => {
-            println!("{}Yield", ind);
-            print_expr(cx, sub, indent + 1);
-        },
-        hir::ExprKind::Block(_, _) => {
-            println!("{}Block", ind);
-        },
-        hir::ExprKind::Assign(lhs, rhs, _) => {
-            println!("{}Assign", ind);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::AssignOp(ref binop, lhs, rhs) => {
-            println!("{}AssignOp", ind);
-            println!("{}op: {:?}", ind, binop.node);
-            println!("{}lhs:", ind);
-            print_expr(cx, lhs, indent + 1);
-            println!("{}rhs:", ind);
-            print_expr(cx, rhs, indent + 1);
-        },
-        hir::ExprKind::Field(e, ident) => {
-            println!("{}Field", ind);
-            println!("{}field name: {}", ind, ident.name);
-            println!("{}struct expr:", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Index(arr, idx) => {
-            println!("{}Index", ind);
-            println!("{}array expr:", ind);
-            print_expr(cx, arr, indent + 1);
-            println!("{}index expr:", ind);
-            print_expr(cx, idx, indent + 1);
-        },
-        hir::ExprKind::Path(hir::QPath::Resolved(ref ty, path)) => {
-            println!("{}Resolved Path, {:?}", ind, ty);
-            println!("{}path: {:?}", ind, path);
-        },
-        hir::ExprKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
-            println!("{}Relative Path, {:?}", ind, ty);
-            println!("{}seg: {:?}", ind, seg);
-        },
-        hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
-            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
-        },
-        hir::ExprKind::AddrOf(kind, ref muta, e) => {
-            println!("{}AddrOf", ind);
-            println!("kind: {:?}", kind);
-            println!("mutability: {:?}", muta);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::ExprKind::Break(_, ref e) => {
-            println!("{}Break", ind);
-            if let Some(e) = *e {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::Continue(_) => println!("{}Again", ind),
-        hir::ExprKind::Ret(ref e) => {
-            println!("{}Ret", ind);
-            if let Some(e) = *e {
-                print_expr(cx, e, indent + 1);
-            }
-        },
-        hir::ExprKind::InlineAsm(asm) => {
-            println!("{}InlineAsm", ind);
-            println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template));
-            println!("{}options: {:?}", ind, asm.options);
-            println!("{}operands:", ind);
-            for (op, _op_sp) in asm.operands {
-                match op {
-                    hir::InlineAsmOperand::In { expr, .. }
-                    | hir::InlineAsmOperand::InOut { expr, .. }
-                    | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1),
-                    hir::InlineAsmOperand::Out { expr, .. } => {
-                        if let Some(expr) = expr {
-                            print_expr(cx, expr, indent + 1);
-                        }
-                    },
-                    hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                        print_expr(cx, in_expr, indent + 1);
-                        if let Some(out_expr) = out_expr {
-                            print_expr(cx, out_expr, indent + 1);
-                        }
-                    },
-                    hir::InlineAsmOperand::Const { anon_const } => {
-                        println!("{}anon_const:", ind);
-                        print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-                    },
-                }
-            }
-        },
-        hir::ExprKind::Struct(path, fields, ref base) => {
-            println!("{}Struct", ind);
-            println!("{}path: {:?}", ind, path);
-            for field in fields {
-                println!("{}field \"{}\":", ind, field.ident.name);
-                print_expr(cx, field.expr, indent + 1);
-            }
-            if let Some(base) = *base {
-                println!("{}base:", ind);
-                print_expr(cx, base, indent + 1);
-            }
-        },
-        hir::ExprKind::ConstBlock(ref anon_const) => {
-            println!("{}ConstBlock", ind);
-            println!("{}anon_const:", ind);
-            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-        },
-        hir::ExprKind::Repeat(val, length) => {
-            println!("{}Repeat", ind);
-            println!("{}value:", ind);
-            print_expr(cx, val, indent + 1);
-            println!("{}repeat count:", ind);
-            match length {
-                hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
-                hir::ArrayLen::Body(anon_const) => {
-                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
-                },
-            }
-        },
-        hir::ExprKind::Err => {
-            println!("{}Err", ind);
-        },
-        hir::ExprKind::DropTemps(e) => {
-            println!("{}DropTemps", ind);
-            print_expr(cx, e, indent + 1);
-        },
-    }
-}
-
-fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
-    let did = item.def_id;
-    println!("item `{}`", item.ident.name);
-    match item.vis.node {
-        hir::VisibilityKind::Public => println!("public"),
-        hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
-        hir::VisibilityKind::Restricted { path, .. } => println!(
-            "visible in module `{}`",
-            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(path, false))
-        ),
-        hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
-    }
-    match item.kind {
-        hir::ItemKind::ExternCrate(ref _renamed_from) => {
-            if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(did) {
-                let source = cx.tcx.used_crate_source(crate_id);
-                if let Some(ref src) = source.dylib {
-                    println!("extern crate dylib source: {:?}", src.0);
-                }
-                if let Some(ref src) = source.rlib {
-                    println!("extern crate rlib source: {:?}", src.0);
-                }
-            } else {
-                println!("weird extern crate without a crate id");
-            }
-        },
-        hir::ItemKind::Use(path, ref kind) => println!("{:?}, {:?}", path, kind),
-        hir::ItemKind::Static(..) => println!("static item of type {:#?}", cx.tcx.type_of(did)),
-        hir::ItemKind::Const(..) => println!("const item of type {:#?}", cx.tcx.type_of(did)),
-        hir::ItemKind::Fn(..) => {
-            let item_ty = cx.tcx.type_of(did);
-            println!("function of type {:#?}", item_ty);
-        },
-        hir::ItemKind::Macro(ref macro_def, _) => {
-            if macro_def.macro_rules {
-                println!("macro introduced by `macro_rules!`");
-            } else {
-                println!("macro introduced by `macro`");
-            }
-        },
-        hir::ItemKind::Mod(..) => println!("module"),
-        hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
-        hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),
-        hir::ItemKind::TyAlias(..) => {
-            println!("type alias for {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::OpaqueTy(..) => {
-            println!("existential type with real type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Enum(..) => {
-            println!("enum definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Struct(..) => {
-            println!("struct definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Union(..) => {
-            println!("union definition of type {:?}", cx.tcx.type_of(did));
-        },
-        hir::ItemKind::Trait(..) => {
-            println!("trait decl");
-            if cx.tcx.trait_is_auto(did.to_def_id()) {
-                println!("trait is auto");
-            } else {
-                println!("trait is not auto");
-            }
-        },
-        hir::ItemKind::TraitAlias(..) => {
-            println!("trait alias");
-        },
-        hir::ItemKind::Impl(hir::Impl {
-            of_trait: Some(ref _trait_ref),
-            ..
-        }) => {
-            println!("trait impl");
-        },
-        hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) => {
-            println!("impl");
-        },
-    }
-}
-
-#[allow(clippy::similar_names)]
-#[allow(clippy::too_many_lines)]
-fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    match pat.kind {
-        hir::PatKind::Wild => println!("{}Wild", ind),
-        hir::PatKind::Binding(ref mode, .., ident, ref inner) => {
-            println!("{}Binding", ind);
-            println!("{}mode: {:?}", ind, mode);
-            println!("{}name: {}", ind, ident.name);
-            if let Some(inner) = *inner {
-                println!("{}inner:", ind);
-                print_pat(cx, inner, indent + 1);
-            }
-        },
-        hir::PatKind::Or(fields) => {
-            println!("{}Or", ind);
-            for field in fields {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Struct(ref path, fields, ignore) => {
-            println!("{}Struct", ind);
-            println!(
-                "{}name: {}",
-                ind,
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-            );
-            println!("{}ignore leftover fields: {}", ind, ignore);
-            println!("{}fields:", ind);
-            for field in fields {
-                println!("{}  field name: {}", ind, field.ident.name);
-                if field.is_shorthand {
-                    println!("{}  in shorthand notation", ind);
-                }
-                print_pat(cx, field.pat, indent + 1);
-            }
-        },
-        hir::PatKind::TupleStruct(ref path, fields, opt_dots_position) => {
-            println!("{}TupleStruct", ind);
-            println!(
-                "{}path: {}",
-                ind,
-                rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-            );
-            if let Some(dot_position) = opt_dots_position {
-                println!("{}dot position: {}", ind, dot_position);
-            }
-            for field in fields {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Path(hir::QPath::Resolved(ref ty, path)) => {
-            println!("{}Resolved Path, {:?}", ind, ty);
-            println!("{}path: {:?}", ind, path);
-        },
-        hir::PatKind::Path(hir::QPath::TypeRelative(ty, seg)) => {
-            println!("{}Relative Path, {:?}", ind, ty);
-            println!("{}seg: {:?}", ind, seg);
-        },
-        hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
-            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
-        },
-        hir::PatKind::Tuple(pats, opt_dots_position) => {
-            println!("{}Tuple", ind);
-            if let Some(dot_position) = opt_dots_position {
-                println!("{}dot position: {}", ind, dot_position);
-            }
-            for field in pats {
-                print_pat(cx, field, indent + 1);
-            }
-        },
-        hir::PatKind::Box(inner) => {
-            println!("{}Box", ind);
-            print_pat(cx, inner, indent + 1);
-        },
-        hir::PatKind::Ref(inner, ref muta) => {
-            println!("{}Ref", ind);
-            println!("{}mutability: {:?}", ind, muta);
-            print_pat(cx, inner, indent + 1);
-        },
-        hir::PatKind::Lit(e) => {
-            println!("{}Lit", ind);
-            print_expr(cx, e, indent + 1);
-        },
-        hir::PatKind::Range(ref l, ref r, ref range_end) => {
-            println!("{}Range", ind);
-            if let Some(expr) = l {
-                print_expr(cx, expr, indent + 1);
-            }
-            if let Some(expr) = r {
-                print_expr(cx, expr, indent + 1);
-            }
-            match *range_end {
-                hir::RangeEnd::Included => println!("{} end included", ind),
-                hir::RangeEnd::Excluded => println!("{} end excluded", ind),
-            }
-        },
-        hir::PatKind::Slice(first_pats, ref range, last_pats) => {
-            println!("{}Slice [a, b, ..i, y, z]", ind);
-            println!("[a, b]:");
-            for pat in first_pats {
-                print_pat(cx, pat, indent + 1);
-            }
-            println!("i:");
-            if let Some(pat) = *range {
-                print_pat(cx, pat, indent + 1);
-            }
-            println!("[y, z]:");
-            for pat in last_pats {
-                print_pat(cx, pat, indent + 1);
-            }
-        },
-    }
-}
-
-fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
-    let ind = "  ".repeat(indent);
-    println!("{}+", ind);
-    match guard {
-        hir::Guard::If(expr) => {
-            println!("{}If", ind);
-            print_expr(cx, expr, indent + 1);
-        },
-        hir::Guard::IfLet(pat, expr) => {
-            println!("{}IfLet", ind);
-            print_pat(cx, pat, indent + 1);
-            print_expr(cx, expr, indent + 1);
-        },
-    }
-}
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index ca03b8010dd..9c75f786479 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -33,7 +33,7 @@ use std::path::Path;
 /// This is the output file of the lint collector.
 const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
 /// These lints are excluded from the export.
-const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
+const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
 /// These groups will be ignored by the lint group matcher. This is useful for collections like
 /// `clippy::all`
 const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index dc385ebacba..787e9fd982c 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -1,5 +1,5 @@
 pub mod author;
 pub mod conf;
-pub mod inspector;
+pub mod dump_hir;
 #[cfg(feature = "internal")]
 pub mod internal_lints;
diff --git a/doc/adding_lints.md b/doc/adding_lints.md
index cf16a1d5d3d..307cf2f3a90 100644
--- a/doc/adding_lints.md
+++ b/doc/adding_lints.md
@@ -22,6 +22,7 @@ because that's clearly a non-descriptive name.
   - [Adding the lint logic](#adding-the-lint-logic)
   - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv)
   - [Author lint](#author-lint)
+  - [Print HIR lint](#print-hir-lint)
   - [Documentation](#documentation)
   - [Running rustfmt](#running-rustfmt)
   - [Debugging](#debugging)
@@ -484,6 +485,19 @@ you are implementing your lint.
 
 [author_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=9a12cb60e5c6ad4e3003ac6d5e63cf55
 
+## Print HIR lint
+
+To implement a lint, it's helpful to first understand the internal representation
+that rustc uses. Clippy has the `#[clippy::dump]` attribute that prints the
+[_High-Level Intermediate Representation (HIR)_] of the item, statement, or 
+expression that the attribute is attached to. To attach the attribute to expressions
+you often need to enable `#![feature(stmt_expr_attributes)]`.
+
+[Here][print_hir_example] you can find an example, just select _Tools_ and run _Clippy_.
+
+[_High-Level Intermediate Representation (HIR)_]: https://rustc-dev-guide.rust-lang.org/hir.html
+[print_hir_example]: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=daf14db3a7f39ca467cd1b86c34b9afb
+
 ## Documentation
 
 The final thing before submitting our PR is to add some documentation to our