@@ -136,6 +136,9 @@ impl CollapsibleIf {
136
136
return ;
137
137
}
138
138
139
+ // Peel off any parentheses.
140
+ let ( _, else_block_span, _) = peel_parens ( cx. tcx . sess . source_map ( ) , else_. span ) ;
141
+
139
142
// Prevent "elseif"
140
143
// Check that the "else" is followed by whitespace
141
144
let requires_space = if let Some ( c) = snippet ( cx, up_to_else, ".." ) . chars ( ) . last ( ) {
@@ -152,7 +155,7 @@ impl CollapsibleIf {
152
155
if requires_space { " " } else { "" } ,
153
156
snippet_block_with_applicability(
154
157
cx,
155
- else_ . span ,
158
+ else_block_span ,
156
159
".." ,
157
160
Some ( else_block. span) ,
158
161
& mut applicability
@@ -187,7 +190,8 @@ impl CollapsibleIf {
187
190
. with_leading_whitespace ( cx)
188
191
. into_span ( )
189
192
} ;
190
- let inner_if = inner. span . split_at ( 2 ) . 0 ;
193
+ let ( paren_start, inner_if_span, paren_end) = peel_parens ( cx. tcx . sess . source_map ( ) , inner. span ) ;
194
+ let inner_if = inner_if_span. split_at ( 2 ) . 0 ;
191
195
let mut sugg = vec ! [
192
196
// Remove the outer then block `{`
193
197
( then_open_bracket, String :: new( ) ) ,
@@ -196,6 +200,17 @@ impl CollapsibleIf {
196
200
// Replace inner `if` by `&&`
197
201
( inner_if, String :: from( "&&" ) ) ,
198
202
] ;
203
+
204
+ if !paren_start. is_empty ( ) {
205
+ // Remove any leading parentheses '('
206
+ sugg. push ( ( paren_start, String :: new ( ) ) ) ;
207
+ }
208
+
209
+ if !paren_end. is_empty ( ) {
210
+ // Remove any trailing parentheses ')'
211
+ sugg. push ( ( paren_end, String :: new ( ) ) ) ;
212
+ }
213
+
199
214
sugg. extend ( parens_around ( check) ) ;
200
215
sugg. extend ( parens_around ( check_inner) ) ;
201
216
@@ -285,3 +300,37 @@ fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Spa
285
300
} )
286
301
. next ( )
287
302
}
303
+
304
+ /// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`.
305
+ fn peel_parens ( sm : & SourceMap , mut span : Span ) -> ( Span , Span , Span ) {
306
+ use crate :: rustc_span:: Pos ;
307
+
308
+ let start = span. shrink_to_lo ( ) ;
309
+ let end = span. shrink_to_hi ( ) ;
310
+
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
+ }
318
+
319
+ ( start. with_hi ( span. lo ( ) ) , span, end. with_lo ( span. hi ( ) ) )
320
+ }
321
+
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 ;
326
+ }
327
+
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
+ } )
336
+ }
0 commit comments