Skip to content

Commit ab543db

Browse files
committed
fix collapsable_else_if when the inner if is in parens
1 parent af19ff8 commit ab543db

File tree

6 files changed

+98
-27
lines changed

6 files changed

+98
-27
lines changed

clippy_lints/src/collapsible_if.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ impl CollapsibleIf {
136136
return;
137137
}
138138

139+
// Peel off any parentheses.
140+
let (_, else_block_span, _) = peel_parens(cx.tcx.sess.source_map(), else_.span);
141+
139142
// Prevent "elseif"
140143
// Check that the "else" is followed by whitespace
141144
let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
@@ -152,7 +155,7 @@ impl CollapsibleIf {
152155
if requires_space { " " } else { "" },
153156
snippet_block_with_applicability(
154157
cx,
155-
else_.span,
158+
else_block_span,
156159
"..",
157160
Some(else_block.span),
158161
&mut applicability
@@ -298,39 +301,36 @@ fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Spa
298301
.next()
299302
}
300303

304+
/// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`.
301305
fn peel_parens(sm: &SourceMap, mut span: Span) -> (Span, Span, Span) {
302306
use crate::rustc_span::Pos;
303-
use rustc_span::SpanData;
304307

305308
let start = span.shrink_to_lo();
306309
let end = span.shrink_to_hi();
307310

308-
loop {
309-
let data = span.data();
310-
let snippet = sm.span_to_snippet(span).unwrap();
311-
312-
let trim_start = snippet.len() - snippet.trim_start().len();
313-
let trim_end = snippet.len() - snippet.trim_end().len();
314-
315-
let trimmed = snippet.trim();
316-
317-
if trimmed.starts_with('(') && trimmed.ends_with(')') {
318-
// Try to remove one layer of parens by adjusting the span
319-
span = SpanData {
320-
lo: data.lo + BytePos::from_usize(trim_start + 1),
321-
hi: data.hi - BytePos::from_usize(trim_end + 1),
322-
ctxt: data.ctxt,
323-
parent: data.parent,
324-
}
325-
.span();
311+
let snippet = sm.span_to_snippet(span).unwrap();
312+
if let Some((trim_start, _, trim_end)) = peel_parens_str(&snippet) {
313+
let mut data = span.data();
314+
data.lo = data.lo + BytePos::from_usize(trim_start);
315+
data.hi = data.hi - BytePos::from_usize(trim_end);
316+
span = data.span();
317+
}
326318

327-
continue;
328-
}
319+
(start.with_hi(span.lo()), span, end.with_lo(span.hi()))
320+
}
329321

330-
break;
322+
fn peel_parens_str(snippet: &str) -> Option<(usize, &str, usize)> {
323+
let trimmed = snippet.trim();
324+
if !(trimmed.starts_with('(') && trimmed.ends_with(')')) {
325+
return None;
331326
}
332327

333-
(start.with_hi(span.lo()),
334-
span,
335-
end.with_lo(span.hi()))
328+
let trim_start = (snippet.len() - snippet.trim_start().len()) + 1;
329+
let trim_end = (snippet.len() - snippet.trim_end().len()) + 1;
330+
331+
let inner = snippet.get(trim_start..snippet.len() - trim_end)?;
332+
Some(match peel_parens_str(inner) {
333+
None => (trim_start, inner, trim_end),
334+
Some((start, inner, end)) => (trim_start + start, inner, trim_end + end),
335+
})
336336
}

tests/ui/collapsible_else_if.fixed

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,25 @@ fn issue14799() {
104104
}
105105
}
106106
}
107+
108+
fn in_parens() {
109+
let x = "hello";
110+
let y = "world";
111+
112+
if x == "hello" {
113+
print!("Hello ");
114+
} else if y == "world" { println!("world") } else { println!("!") }
115+
//~^^^ collapsible_else_if
116+
}
117+
118+
fn in_brackets() {
119+
let x = "hello";
120+
let y = "world";
121+
122+
// There is no lint when the inner `if` is in a block.
123+
if x == "hello" {
124+
print!("Hello ");
125+
} else {
126+
{if y == "world" { println!("world") } else { println!("!") }}
127+
}
128+
}

tests/ui/collapsible_else_if.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,27 @@ fn issue14799() {
120120
}
121121
}
122122
}
123+
124+
fn in_parens() {
125+
let x = "hello";
126+
let y = "world";
127+
128+
if x == "hello" {
129+
print!("Hello ");
130+
} else {
131+
(if y == "world" { println!("world") } else { println!("!") })
132+
}
133+
//~^^^ collapsible_else_if
134+
}
135+
136+
fn in_brackets() {
137+
let x = "hello";
138+
let y = "world";
139+
140+
// There is no lint when the inner `if` is in a block.
141+
if x == "hello" {
142+
print!("Hello ");
143+
} else {
144+
{if y == "world" { println!("world") } else { println!("!") }}
145+
}
146+
}

tests/ui/collapsible_else_if.stderr

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,14 @@ LL | | if false {}
150150
LL | | }
151151
| |_____^ help: collapse nested if block: `if false {}`
152152

153-
error: aborting due to 8 previous errors
153+
error: this `else { if .. }` block can be collapsed
154+
--> tests/ui/collapsible_else_if.rs:130:12
155+
|
156+
LL | } else {
157+
| ____________^
158+
LL | | (if y == "world" { println!("world") } else { println!("!") })
159+
LL | | }
160+
| |_____^ help: collapse nested if block: `if y == "world" { println!("world") } else { println!("!") }`
161+
162+
error: aborting due to 9 previous errors
154163

tests/ui/collapsible_if.fixed

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,11 @@ fn in_parens() {
171171
}
172172
//~^^^^^ collapsible_if
173173
}
174+
175+
fn in_brackets() {
176+
if true {
177+
{if true {
178+
println!("In brackets, not linted");
179+
}}
180+
}
181+
}

tests/ui/collapsible_if.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,11 @@ fn in_parens() {
182182
}
183183
//~^^^^^ collapsible_if
184184
}
185+
186+
fn in_brackets() {
187+
if true {
188+
{if true {
189+
println!("In brackets, not linted");
190+
}}
191+
}
192+
}

0 commit comments

Comments
 (0)