Skip to content

Commit 59bca09

Browse files
committed
don't lint on if let
don't lint on `if let`
1 parent b2bdc37 commit 59bca09

File tree

4 files changed

+109
-25
lines changed

4 files changed

+109
-25
lines changed

clippy_lints/src/needless_if.rs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, source::snippet_with_applicability};
22
use rustc_errors::Applicability;
3-
use rustc_hir::{Expr, ExprKind, Node};
3+
use rustc_hir::{
4+
intravisit::{walk_expr, Visitor},
5+
Expr, ExprKind, Node,
6+
};
47
use rustc_lint::{LateContext, LateLintPass, LintContext};
58
use rustc_middle::lint::in_external_macro;
69
use rustc_session::{declare_lint_pass, declare_tool_lint};
710

811
declare_clippy_lint! {
912
/// ### What it does
10-
/// Checks for empty `if` statements with no else branch.
13+
/// Checks for empty `if` branches with no else branch.
1114
///
1215
/// ### Why is this bad?
1316
/// It can be entirely omitted, and often the condition too.
1417
///
1518
/// ### Known issues
16-
/// This will only suggest to remove the `if` statement, not the condition. Other lints such as
17-
/// `no_effect` will take care of removing the condition if it's unnecessary.
19+
/// This will usually only suggest to remove the `if` statement, not the condition. Other lints
20+
/// such as `no_effect` will take care of removing the condition if it's unnecessary.
1821
///
1922
/// ### Example
2023
/// ```rust,ignore
@@ -42,9 +45,6 @@ impl LateLintPass<'_> for NeedlessIf {
4245
&& else_expr.is_none()
4346
&& !in_external_macro(cx.sess(), expr.span)
4447
{
45-
let mut app = Applicability::MachineApplicable;
46-
let snippet = snippet_with_applicability(cx, if_expr.span, "{ ... }", &mut app);
47-
4848
// Ignore `else if`
4949
if let Some(parent_id) = cx.tcx.hir().opt_parent_id(expr.hir_id)
5050
&& let Some(Node::Expr(Expr {
@@ -56,19 +56,48 @@ impl LateLintPass<'_> for NeedlessIf {
5656
return;
5757
}
5858

59-
if is_from_proc_macro(cx, expr) {
59+
if is_any_if_let(if_expr) || is_from_proc_macro(cx, expr) {
6060
return;
6161
}
6262

63+
let mut app = Applicability::MachineApplicable;
64+
let snippet = snippet_with_applicability(cx, if_expr.span, "{ ... }", &mut app);
65+
6366
span_lint_and_sugg(
6467
cx,
6568
NEEDLESS_IF,
6669
expr.span,
67-
"this if branch is empty",
70+
"this `if` branch is empty",
6871
"you can remove it",
69-
format!("{snippet};"),
70-
Applicability::MachineApplicable,
72+
if if_expr.can_have_side_effects() {
73+
format!("{snippet};")
74+
} else {
75+
String::new()
76+
},
77+
app,
7178
);
7279
}
7380
}
7481
}
82+
83+
/// Returns true if any `Expr` contained within this `Expr` is a `Let`, else false.
84+
///
85+
/// Really wish `Expr` had a `walk` method...
86+
fn is_any_if_let(expr: &Expr<'_>) -> bool {
87+
let mut v = IsAnyLetVisitor(false);
88+
89+
v.visit_expr(expr);
90+
v.0
91+
}
92+
93+
struct IsAnyLetVisitor(bool);
94+
95+
impl Visitor<'_> for IsAnyLetVisitor {
96+
fn visit_expr(&mut self, expr: &Expr<'_>) {
97+
if matches!(expr.kind, ExprKind::Let(..)) {
98+
self.0 = true;
99+
}
100+
101+
walk_expr(self, expr);
102+
}
103+
}

tests/ui/needless_if.fixed

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//@run-rustfix
22
//@aux-build:proc_macros.rs
3+
#![feature(let_chains)]
34
#![allow(
45
clippy::blocks_in_if_conditions,
56
clippy::if_same_then_else,
67
clippy::ifs_same_cond,
78
clippy::needless_else,
89
clippy::no_effect,
10+
clippy::nonminimal_bool,
911
unused
1012
)]
1113
#![warn(clippy::needless_if)]
@@ -14,21 +16,39 @@ extern crate proc_macros;
1416
use proc_macros::external;
1517
use proc_macros::with_span;
1618

19+
fn no_side_effects() -> bool {
20+
true
21+
}
22+
23+
fn has_side_effects(a: &mut u32) -> bool {
24+
*a = 1;
25+
true
26+
}
27+
1728
fn main() {
1829
// Lint
19-
(true);
30+
31+
// Do not remove the condition
32+
no_side_effects();
33+
let mut x = 0;
34+
has_side_effects(&mut x);
35+
assert_eq!(x, 1);
2036
// Do not lint
2137
if (true) {
2238
} else {
2339
}
40+
{
41+
return;
42+
};
2443
// Do not lint if `else if` is present
2544
if (true) {
2645
} else if (true) {
2746
}
28-
// Ensure clippy does not bork this up, other cases should be added
29-
{
30-
return;
31-
};
47+
// Do not lint if any `let` is present
48+
if let true = true {}
49+
if let true = true && true {}
50+
if true && let true = true {}
51+
if { if let true = true && true { true } else { false } } && true {}
3252
external! { if (true) {} }
3353
with_span! {
3454
span

tests/ui/needless_if.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//@run-rustfix
22
//@aux-build:proc_macros.rs
3+
#![feature(let_chains)]
34
#![allow(
45
clippy::blocks_in_if_conditions,
56
clippy::if_same_then_else,
67
clippy::ifs_same_cond,
78
clippy::needless_else,
89
clippy::no_effect,
10+
clippy::nonminimal_bool,
911
unused
1012
)]
1113
#![warn(clippy::needless_if)]
@@ -14,21 +16,42 @@ extern crate proc_macros;
1416
use proc_macros::external;
1517
use proc_macros::with_span;
1618

19+
fn no_side_effects() -> bool {
20+
true
21+
}
22+
23+
fn has_side_effects(a: &mut u32) -> bool {
24+
*a = 1;
25+
true
26+
}
27+
1728
fn main() {
1829
// Lint
1930
if (true) {}
31+
// Do not remove the condition
32+
if no_side_effects() {}
33+
let mut x = 0;
34+
if has_side_effects(&mut x) {}
35+
assert_eq!(x, 1);
2036
// Do not lint
2137
if (true) {
2238
} else {
2339
}
40+
if {
41+
return;
42+
} {}
2443
// Do not lint if `else if` is present
2544
if (true) {
2645
} else if (true) {
2746
}
28-
// Ensure clippy does not bork this up, other cases should be added
47+
// Do not lint if any `let` is present
48+
if let true = true {}
49+
if let true = true && true {}
50+
if true && let true = true {}
2951
if {
30-
return;
31-
} {}
52+
if let true = true && true { true } else { false }
53+
} && true
54+
{}
3255
external! { if (true) {} }
3356
with_span! {
3457
span

tests/ui/needless_if.stderr

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
1-
error: this if branch is empty
2-
--> $DIR/needless_if.rs:19:5
1+
error: this `if` branch is empty
2+
--> $DIR/needless_if.rs:30:5
33
|
44
LL | if (true) {}
5-
| ^^^^^^^^^^^^ help: you can remove it: `(true);`
5+
| ^^^^^^^^^^^^ help: you can remove it
66
|
77
= note: `-D clippy::needless-if` implied by `-D warnings`
88

9-
error: this if branch is empty
10-
--> $DIR/needless_if.rs:29:5
9+
error: this `if` branch is empty
10+
--> $DIR/needless_if.rs:32:5
11+
|
12+
LL | if no_side_effects() {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `no_side_effects();`
14+
15+
error: this `if` branch is empty
16+
--> $DIR/needless_if.rs:34:5
17+
|
18+
LL | if has_side_effects(&mut x) {}
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `has_side_effects(&mut x);`
20+
21+
error: this `if` branch is empty
22+
--> $DIR/needless_if.rs:40:5
1123
|
1224
LL | / if {
1325
LL | | return;
@@ -21,5 +33,5 @@ LL + return;
2133
LL + };
2234
|
2335

24-
error: aborting due to 2 previous errors
36+
error: aborting due to 4 previous errors
2537

0 commit comments

Comments
 (0)