Skip to content

Commit 646f583

Browse files
committed
fix: remove else-if collapse suggestion when all branches contain only an if {..} else {..} expression
If two `if` arms contain only a single `if {..} else {..}` statement, don't suggest a collapse as this can lead to less readable code.
1 parent 26a5677 commit 646f583

File tree

4 files changed

+91
-3
lines changed

4 files changed

+91
-3
lines changed

clippy_lints/src/collapsible_if.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ impl LateLintPass<'_> for CollapsibleIf {
267267
&& !expr.span.from_expansion()
268268
{
269269
if let Some(else_) = else_
270+
// Short circuit if both `if` branches contain only a single `if {..} else {}`, as
271+
// collapsing such blocks can lead to less readable code (#4971)
272+
&& !(single_inner_if_else(then) && single_inner_if_else(else_))
270273
&& let ExprKind::Block(else_, None) = else_.kind
271274
{
272275
self.check_collapsible_else_if(cx, then.span, else_);
@@ -280,6 +283,19 @@ impl LateLintPass<'_> for CollapsibleIf {
280283
}
281284
}
282285

286+
/// Returns true if `expr` is a block that contains only one `if {..} else {}` statement
287+
fn single_inner_if_else(expr: &Expr<'_>) -> bool {
288+
if let ExprKind::Block(block, None) = expr.kind
289+
&& let Some(inner_expr) = expr_block(block)
290+
&& let ExprKind::If(_, _, else_) = inner_expr.kind
291+
&& else_.is_some()
292+
{
293+
true
294+
} else {
295+
false
296+
}
297+
}
298+
283299
/// If `block` is a block with either one expression or a statement containing an expression,
284300
/// return the expression. We don't peel blocks recursively, as extra blocks might be intentional.
285301
fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {

tests/ui/collapsible_else_if.fixed

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ fn main() {
7070
}
7171
//~^^^^^^^^ collapsible_else_if
7272

73+
if x == "hello" {
74+
if y == "world" {
75+
print!("Hello ");
76+
} else {
77+
println!("world");
78+
}
79+
} else if let Some(42) = Some(42) {
80+
println!("42");
81+
}
82+
//~^^^^^ collapsible_else_if
83+
7384
if x == "hello" {
7485
print!("Hello ");
7586
} else {
@@ -78,6 +89,21 @@ fn main() {
7889
println!("world!")
7990
}
8091
}
92+
93+
if x == "hello" {
94+
if y == "world" {
95+
print!("Hello ");
96+
} else {
97+
println!("world");
98+
}
99+
} else {
100+
if let Some(42) = Some(42) {
101+
println!("42");
102+
} else {
103+
println!("!");
104+
}
105+
}
106+
81107
}
82108

83109
#[rustfmt::skip]

tests/ui/collapsible_else_if.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ fn main() {
8484
}
8585
//~^^^^^^^^ collapsible_else_if
8686

87+
if x == "hello" {
88+
if y == "world" {
89+
print!("Hello ");
90+
} else {
91+
println!("world");
92+
}
93+
} else {
94+
if let Some(42) = Some(42) {
95+
println!("42");
96+
}
97+
}
98+
//~^^^^^ collapsible_else_if
99+
87100
if x == "hello" {
88101
print!("Hello ");
89102
} else {
@@ -92,6 +105,21 @@ fn main() {
92105
println!("world!")
93106
}
94107
}
108+
109+
if x == "hello" {
110+
if y == "world" {
111+
print!("Hello ");
112+
} else {
113+
println!("world");
114+
}
115+
} else {
116+
if let Some(42) = Some(42) {
117+
println!("42");
118+
} else {
119+
println!("!");
120+
}
121+
}
122+
95123
}
96124

97125
#[rustfmt::skip]

tests/ui/collapsible_else_if.stderr

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,25 @@ LL + }
142142
|
143143

144144
error: this `else { if .. }` block can be collapsed
145-
--> tests/ui/collapsible_else_if.rs:100:10
145+
--> tests/ui/collapsible_else_if.rs:93:12
146+
|
147+
LL | } else {
148+
| ____________^
149+
LL | | if let Some(42) = Some(42) {
150+
LL | | println!("42");
151+
LL | | }
152+
LL | | }
153+
| |_____^
154+
|
155+
help: collapse nested if block
156+
|
157+
LL ~ } else if let Some(42) = Some(42) {
158+
LL + println!("42");
159+
LL + }
160+
|
161+
162+
error: this `else { if .. }` block can be collapsed
163+
--> tests/ui/collapsible_else_if.rs:128:10
146164
|
147165
LL | }else{
148166
| __________^
@@ -151,13 +169,13 @@ LL | | }
151169
| |_____^ help: collapse nested if block: `if false {}`
152170

153171
error: this `else { if .. }` block can be collapsed
154-
--> tests/ui/collapsible_else_if.rs:139:12
172+
--> tests/ui/collapsible_else_if.rs:167:12
155173
|
156174
LL | } else {
157175
| ____________^
158176
LL | | (if y == "world" { println!("world") } else { println!("!") })
159177
LL | | }
160178
| |_____^ help: collapse nested if block: `if y == "world" { println!("world") } else { println!("!") }`
161179

162-
error: aborting due to 9 previous errors
180+
error: aborting due to 10 previous errors
163181

0 commit comments

Comments
 (0)