Skip to content

Commit f0be0ee

Browse files
committed
handle nested macros and add tests for them
1 parent cc607fe commit f0be0ee

File tree

3 files changed

+85
-23
lines changed

3 files changed

+85
-23
lines changed

clippy_lints/src/dbg_macro.rs

+36-15
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node;
33
use clippy_utils::source::snippet_with_applicability;
44
use clippy_utils::{is_in_cfg_test, is_in_test_function};
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind};
6+
use rustc_hir::{Expr, ExprKind, Node};
77
use rustc_lint::{LateContext, LateLintPass, LintContext};
88
use rustc_session::{declare_tool_lint, impl_lint_pass};
9-
use rustc_span::{sym, Span};
9+
use rustc_span::{sym, BytePos, Pos, Span};
1010

1111
declare_clippy_lint! {
1212
/// ### What it does
@@ -31,9 +31,29 @@ declare_clippy_lint! {
3131
"`dbg!` macro is intended as a debugging tool"
3232
}
3333

34-
fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Span {
35-
let span = cx.sess().source_map().span_extend_to_next_char(span, ';', true);
36-
span.with_hi(span.hi() + rustc_span::BytePos(1))
34+
/// Gets the span of the statement up to the next semicolon, if and only if the next
35+
/// non-whitespace character actually is a semicolon.
36+
/// E.g.
37+
/// ```rust,ignore
38+
///
39+
/// dbg!();
40+
/// ^^^^^^^ this span is returned
41+
///
42+
/// foo!(dbg!());
43+
/// no span is returned
44+
/// ```
45+
fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> {
46+
let sm = cx.sess().source_map();
47+
let sf = sm.lookup_source_file(span.hi());
48+
let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?;
49+
let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?;
50+
51+
if src.as_bytes()[first_non_whitespace] == b';' {
52+
let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1);
53+
Some(span.with_hi(hi))
54+
} else {
55+
None
56+
}
3757
}
3858

3959
#[derive(Copy, Clone)]
@@ -62,16 +82,17 @@ impl LateLintPass<'_> for DbgMacro {
6282
let mut applicability = Applicability::MachineApplicable;
6383

6484
let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
65-
ExprKind::Block(..) => match cx.tcx.hir().find_parent(expr.hir_id) {
66-
// dbg!() as a standalone statement, suggest removing the whole statement entirely
67-
Some(Node::Stmt(
68-
stmt @ Stmt {
69-
kind: StmtKind::Semi(_),
70-
..
71-
},
72-
)) => (span_including_semi(cx, stmt.span.source_callsite()), String::new()),
73-
// empty dbg!() in arbitrary position (e.g. `foo(dbg!())`), suggest replacing with `foo(())`
74-
_ => (macro_call.span, String::from("()")),
85+
// dbg!()
86+
ExprKind::Block(..) => {
87+
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
88+
// remove the whole statement.
89+
if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id)
90+
&& let Some(span) = span_including_semi(cx, stmt.span.source_callsite())
91+
{
92+
(span, String::new())
93+
} else {
94+
(macro_call.span, String::from("()"))
95+
}
7596
},
7697
// dbg!(1)
7798
ExprKind::Match(val, ..) => (

tests/ui/dbg_macro.rs

+19
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,29 @@ fn main() {
2323
}
2424

2525
fn issue9914() {
26+
macro_rules! foo {
27+
($x:expr) => {
28+
$x;
29+
};
30+
}
31+
macro_rules! foo2 {
32+
($x:expr) => {
33+
$x;
34+
};
35+
}
36+
macro_rules! expand_to_dbg {
37+
() => {
38+
dbg!();
39+
};
40+
}
41+
2642
dbg!();
2743
#[allow(clippy::let_unit_value)]
2844
let _ = dbg!();
2945
bar(dbg!());
46+
foo!(dbg!());
47+
foo2!(foo!(dbg!()));
48+
expand_to_dbg!();
3049
}
3150

3251
mod issue7274 {

tests/ui/dbg_macro.stderr

+30-8
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ LL | (1, 2, 3, 4, 5);
9999
| ~~~~~~~~~~~~~~~
100100

101101
error: the `dbg!` macro is intended as a debugging tool
102-
--> $DIR/dbg_macro.rs:26:5
102+
--> $DIR/dbg_macro.rs:42:5
103103
|
104104
LL | dbg!();
105105
| ^^^^^^^
@@ -111,7 +111,7 @@ LL +
111111
|
112112

113113
error: the `dbg!` macro is intended as a debugging tool
114-
--> $DIR/dbg_macro.rs:28:13
114+
--> $DIR/dbg_macro.rs:44:13
115115
|
116116
LL | let _ = dbg!();
117117
| ^^^^^^
@@ -122,7 +122,7 @@ LL | let _ = ();
122122
| ~~
123123

124124
error: the `dbg!` macro is intended as a debugging tool
125-
--> $DIR/dbg_macro.rs:29:9
125+
--> $DIR/dbg_macro.rs:45:9
126126
|
127127
LL | bar(dbg!());
128128
| ^^^^^^
@@ -133,7 +133,29 @@ LL | bar(());
133133
| ~~
134134

135135
error: the `dbg!` macro is intended as a debugging tool
136-
--> $DIR/dbg_macro.rs:49:9
136+
--> $DIR/dbg_macro.rs:46:10
137+
|
138+
LL | foo!(dbg!());
139+
| ^^^^^^
140+
|
141+
help: remove the invocation before committing it to a version control system
142+
|
143+
LL | foo!(());
144+
| ~~
145+
146+
error: the `dbg!` macro is intended as a debugging tool
147+
--> $DIR/dbg_macro.rs:47:16
148+
|
149+
LL | foo2!(foo!(dbg!()));
150+
| ^^^^^^
151+
|
152+
help: remove the invocation before committing it to a version control system
153+
|
154+
LL | foo2!(foo!(()));
155+
| ~~
156+
157+
error: the `dbg!` macro is intended as a debugging tool
158+
--> $DIR/dbg_macro.rs:68:9
137159
|
138160
LL | dbg!(2);
139161
| ^^^^^^^
@@ -144,7 +166,7 @@ LL | 2;
144166
| ~
145167

146168
error: the `dbg!` macro is intended as a debugging tool
147-
--> $DIR/dbg_macro.rs:55:5
169+
--> $DIR/dbg_macro.rs:74:5
148170
|
149171
LL | dbg!(1);
150172
| ^^^^^^^
@@ -155,7 +177,7 @@ LL | 1;
155177
| ~
156178

157179
error: the `dbg!` macro is intended as a debugging tool
158-
--> $DIR/dbg_macro.rs:60:5
180+
--> $DIR/dbg_macro.rs:79:5
159181
|
160182
LL | dbg!(1);
161183
| ^^^^^^^
@@ -166,7 +188,7 @@ LL | 1;
166188
| ~
167189

168190
error: the `dbg!` macro is intended as a debugging tool
169-
--> $DIR/dbg_macro.rs:66:9
191+
--> $DIR/dbg_macro.rs:85:9
170192
|
171193
LL | dbg!(1);
172194
| ^^^^^^^
@@ -176,5 +198,5 @@ help: remove the invocation before committing it to a version control system
176198
LL | 1;
177199
| ~
178200

179-
error: aborting due to 16 previous errors
201+
error: aborting due to 18 previous errors
180202

0 commit comments

Comments
 (0)