]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/dbg_macro.rs
Auto merge of #101709 - nnethercote:simplify-visitors-more, r=cjgillot
[rust.git] / clippy_lints / src / dbg_macro.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::macros::root_macro_call_first_node;
3 use clippy_utils::source::snippet_with_applicability;
4 use clippy_utils::{is_in_cfg_test, is_in_test_function};
5 use rustc_errors::Applicability;
6 use rustc_hir::{Expr, ExprKind};
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
9 use rustc_span::sym;
10
11 declare_clippy_lint! {
12     /// ### What it does
13     /// Checks for usage of dbg!() macro.
14     ///
15     /// ### Why is this bad?
16     /// `dbg!` macro is intended as a debugging tool. It
17     /// should not be in version control.
18     ///
19     /// ### Example
20     /// ```rust,ignore
21     /// dbg!(true)
22     /// ```
23     ///
24     /// Use instead:
25     /// ```rust,ignore
26     /// true
27     /// ```
28     #[clippy::version = "1.34.0"]
29     pub DBG_MACRO,
30     restriction,
31     "`dbg!` macro is intended as a debugging tool"
32 }
33
34 #[derive(Copy, Clone)]
35 pub struct DbgMacro {
36     allow_dbg_in_tests: bool,
37 }
38
39 impl_lint_pass!(DbgMacro => [DBG_MACRO]);
40
41 impl DbgMacro {
42     pub fn new(allow_dbg_in_tests: bool) -> Self {
43         DbgMacro { allow_dbg_in_tests }
44     }
45 }
46
47 impl LateLintPass<'_> for DbgMacro {
48     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
49         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
50         if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
51             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
52             if self.allow_dbg_in_tests
53                 && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id))
54             {
55                 return;
56             }
57             let mut applicability = Applicability::MachineApplicable;
58             let suggestion = match expr.peel_drop_temps().kind {
59                 // dbg!()
60                 ExprKind::Block(_, _) => String::new(),
61                 // dbg!(1)
62                 ExprKind::Match(val, ..) => {
63                     snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string()
64                 },
65                 // dbg!(2, 3)
66                 ExprKind::Tup(
67                     [
68                         Expr {
69                             kind: ExprKind::Match(first, ..),
70                             ..
71                         },
72                         ..,
73                         Expr {
74                             kind: ExprKind::Match(last, ..),
75                             ..
76                         },
77                     ],
78                 ) => {
79                     let snippet = snippet_with_applicability(
80                         cx,
81                         first.span.source_callsite().to(last.span.source_callsite()),
82                         "..",
83                         &mut applicability,
84                     );
85                     format!("({snippet})")
86                 },
87                 _ => return,
88             };
89
90             span_lint_and_sugg(
91                 cx,
92                 DBG_MACRO,
93                 macro_call.span,
94                 "`dbg!` macro is intended as a debugging tool",
95                 "ensure to avoid having uses of it in version control",
96                 suggestion,
97                 applicability,
98             );
99         }
100     }
101 }