@@ -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
@@ -187,7 +190,8 @@ impl CollapsibleIf {
187190 . with_leading_whitespace ( cx)
188191 . into_span ( )
189192 } ;
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 ;
191195 let mut sugg = vec ! [
192196 // Remove the outer then block `{`
193197 ( then_open_bracket, String :: new( ) ) ,
@@ -196,6 +200,17 @@ impl CollapsibleIf {
196200 // Replace inner `if` by `&&`
197201 ( inner_if, String :: from( "&&" ) ) ,
198202 ] ;
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+
199214 sugg. extend ( parens_around ( check) ) ;
200215 sugg. extend ( parens_around ( check_inner) ) ;
201216
@@ -285,3 +300,37 @@ fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Spa
285300 } )
286301 . next ( )
287302}
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