Skip to content

Commit 88d83b6

Browse files
authored
short_circuit_statement: handle macros and parenthesis better (rust-lang#14047)
- The lint no longer triggers if one of the operands in the boolean expression comes from a macro expansion. - Parenthesis are now removed inside the generated block if they are no longer necessary. - Error markers have been added. changelog: [`short_circuit_statement`]: better handling of macros and better looking suggestions
2 parents 396de57 + 7f162fa commit 88d83b6

File tree

4 files changed

+108
-13
lines changed

4 files changed

+108
-13
lines changed

clippy_lints/src/misc.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
216216
);
217217
}
218218
if let StmtKind::Semi(expr) = stmt.kind
219-
&& let ExprKind::Binary(ref binop, a, b) = expr.kind
220-
&& (binop.node == BinOpKind::And || binop.node == BinOpKind::Or)
221-
&& let Some(sugg) = Sugg::hir_opt(cx, a)
219+
&& let ExprKind::Binary(binop, a, b) = &expr.kind
220+
&& matches!(binop.node, BinOpKind::And | BinOpKind::Or)
221+
&& !stmt.span.from_expansion()
222+
&& expr.span.eq_ctxt(stmt.span)
222223
{
223224
span_lint_hir_and_then(
224225
cx,
@@ -227,13 +228,11 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
227228
stmt.span,
228229
"boolean short circuit operator in statement may be clearer using an explicit test",
229230
|diag| {
230-
let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
231-
diag.span_suggestion(
232-
stmt.span,
233-
"replace it with",
234-
format!("if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."),),
235-
Applicability::MachineApplicable, // snippet
236-
);
231+
let mut app = Applicability::MachineApplicable;
232+
let test = Sugg::hir_with_context(cx, a, expr.span.ctxt(), "_", &mut app);
233+
let test = if binop.node == BinOpKind::Or { !test } else { test };
234+
let then = Sugg::hir_with_context(cx, b, expr.span.ctxt(), "_", &mut app);
235+
diag.span_suggestion(stmt.span, "replace it with", format!("if {test} {{ {then}; }}"), app);
237236
},
238237
);
239238
}

tests/ui/short_circuit_statement.fixed

+36
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,35 @@
33

44
fn main() {
55
if f() { g(); }
6+
//~^ ERROR: boolean short circuit operator in statement
67
if !f() { g(); }
8+
//~^ ERROR: boolean short circuit operator in statement
79
if 1 != 2 { g(); }
10+
//~^ ERROR: boolean short circuit operator in statement
11+
if f() || g() { H * 2; }
12+
//~^ ERROR: boolean short circuit operator in statement
13+
if !(f() || g()) { H * 2; }
14+
//~^ ERROR: boolean short circuit operator in statement
15+
16+
macro_rules! mac {
17+
($f:ident or $g:ident) => {
18+
$f() || $g()
19+
};
20+
($f:ident and $g:ident) => {
21+
$f() && $g()
22+
};
23+
() => {
24+
f() && g()
25+
};
26+
}
27+
28+
if mac!() { mac!(); }
29+
//~^ ERROR: boolean short circuit operator in statement
30+
if !mac!() { mac!(); }
31+
//~^ ERROR: boolean short circuit operator in statement
32+
33+
// Do not lint if the expression comes from a macro
34+
mac!();
835
}
936

1037
fn f() -> bool {
@@ -14,3 +41,12 @@ fn f() -> bool {
1441
fn g() -> bool {
1542
false
1643
}
44+
45+
struct H;
46+
47+
impl std::ops::Mul<u32> for H {
48+
type Output = bool;
49+
fn mul(self, other: u32) -> Self::Output {
50+
true
51+
}
52+
}

tests/ui/short_circuit_statement.rs

+36
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,35 @@
33

44
fn main() {
55
f() && g();
6+
//~^ ERROR: boolean short circuit operator in statement
67
f() || g();
8+
//~^ ERROR: boolean short circuit operator in statement
79
1 == 2 || g();
10+
//~^ ERROR: boolean short circuit operator in statement
11+
(f() || g()) && (H * 2);
12+
//~^ ERROR: boolean short circuit operator in statement
13+
(f() || g()) || (H * 2);
14+
//~^ ERROR: boolean short circuit operator in statement
15+
16+
macro_rules! mac {
17+
($f:ident or $g:ident) => {
18+
$f() || $g()
19+
};
20+
($f:ident and $g:ident) => {
21+
$f() && $g()
22+
};
23+
() => {
24+
f() && g()
25+
};
26+
}
27+
28+
mac!() && mac!();
29+
//~^ ERROR: boolean short circuit operator in statement
30+
mac!() || mac!();
31+
//~^ ERROR: boolean short circuit operator in statement
32+
33+
// Do not lint if the expression comes from a macro
34+
mac!();
835
}
936

1037
fn f() -> bool {
@@ -14,3 +41,12 @@ fn f() -> bool {
1441
fn g() -> bool {
1542
false
1643
}
44+
45+
struct H;
46+
47+
impl std::ops::Mul<u32> for H {
48+
type Output = bool;
49+
fn mul(self, other: u32) -> Self::Output {
50+
true
51+
}
52+
}

tests/ui/short_circuit_statement.stderr

+27-3
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,40 @@ LL | f() && g();
88
= help: to override `-D warnings` add `#[allow(clippy::short_circuit_statement)]`
99

1010
error: boolean short circuit operator in statement may be clearer using an explicit test
11-
--> tests/ui/short_circuit_statement.rs:6:5
11+
--> tests/ui/short_circuit_statement.rs:7:5
1212
|
1313
LL | f() || g();
1414
| ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }`
1515

1616
error: boolean short circuit operator in statement may be clearer using an explicit test
17-
--> tests/ui/short_circuit_statement.rs:7:5
17+
--> tests/ui/short_circuit_statement.rs:9:5
1818
|
1919
LL | 1 == 2 || g();
2020
| ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }`
2121

22-
error: aborting due to 3 previous errors
22+
error: boolean short circuit operator in statement may be clearer using an explicit test
23+
--> tests/ui/short_circuit_statement.rs:11:5
24+
|
25+
LL | (f() || g()) && (H * 2);
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if f() || g() { H * 2; }`
27+
28+
error: boolean short circuit operator in statement may be clearer using an explicit test
29+
--> tests/ui/short_circuit_statement.rs:13:5
30+
|
31+
LL | (f() || g()) || (H * 2);
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if !(f() || g()) { H * 2; }`
33+
34+
error: boolean short circuit operator in statement may be clearer using an explicit test
35+
--> tests/ui/short_circuit_statement.rs:28:5
36+
|
37+
LL | mac!() && mac!();
38+
| ^^^^^^^^^^^^^^^^^ help: replace it with: `if mac!() { mac!(); }`
39+
40+
error: boolean short circuit operator in statement may be clearer using an explicit test
41+
--> tests/ui/short_circuit_statement.rs:30:5
42+
|
43+
LL | mac!() || mac!();
44+
| ^^^^^^^^^^^^^^^^^ help: replace it with: `if !mac!() { mac!(); }`
45+
46+
error: aborting due to 7 previous errors
2347

0 commit comments

Comments
 (0)