1- use std:: iter:: { self , successors} ;
1+ use std:: iter:: successors;
22
33use either:: Either ;
44use ide_db:: {
@@ -8,11 +8,7 @@ use ide_db::{
88 RootDatabase ,
99} ;
1010use syntax:: {
11- ast:: {
12- self ,
13- edit:: { AstNodeEdit , IndentLevel } ,
14- make, HasName ,
15- } ,
11+ ast:: { self , edit:: IndentLevel , edit_in_place:: Indent , syntax_factory:: SyntaxFactory , HasName } ,
1612 AstNode , TextRange , T ,
1713} ;
1814
@@ -108,51 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
108104 AssistId ( "replace_if_let_with_match" , AssistKind :: RefactorRewrite ) ,
109105 format ! ( "Replace if{let_} with match" ) ,
110106 available_range,
111- move |edit| {
107+ move |builder| {
108+ let make = SyntaxFactory :: new ( ) ;
112109 let match_expr = {
113- let else_arm = make_else_arm ( ctx, else_block, & cond_bodies) ;
110+ let else_arm = make_else_arm ( ctx, & make , else_block, & cond_bodies) ;
114111 let make_match_arm = |( pat, body) : ( _ , ast:: BlockExpr ) | {
115- let body = body. reset_indent ( ) . indent ( IndentLevel ( 1 ) ) ;
112+ let body = make. block_expr ( body. statements ( ) , body. tail_expr ( ) ) ;
113+ body. indent ( IndentLevel :: from ( 1 ) ) ;
114+ let body = unwrap_trivial_block ( body) ;
116115 match pat {
117- Either :: Left ( pat) => make:: match_arm ( pat, None , unwrap_trivial_block ( body) ) ,
118- Either :: Right ( _) if !pat_seen => make:: match_arm (
119- make:: literal_pat ( "true" ) . into ( ) ,
120- None ,
121- unwrap_trivial_block ( body) ,
122- ) ,
123- Either :: Right ( expr) => make:: match_arm (
124- make:: wildcard_pat ( ) . into ( ) ,
125- Some ( make:: match_guard ( expr) ) ,
126- unwrap_trivial_block ( body) ,
116+ Either :: Left ( pat) => make. match_arm ( pat, None , body) ,
117+ Either :: Right ( _) if !pat_seen => {
118+ make. match_arm ( make. literal_pat ( "true" ) . into ( ) , None , body)
119+ }
120+ Either :: Right ( expr) => make. match_arm (
121+ make. wildcard_pat ( ) . into ( ) ,
122+ Some ( make. match_guard ( expr) ) ,
123+ body,
127124 ) ,
128125 }
129126 } ;
130- let arms = cond_bodies. into_iter ( ) . map ( make_match_arm) . chain ( iter:: once ( else_arm) ) ;
131- let match_expr = make:: expr_match ( scrutinee_to_be_expr, make:: match_arm_list ( arms) ) ;
132- match_expr. indent ( IndentLevel :: from_node ( if_expr. syntax ( ) ) ) . into ( )
127+ let arms = cond_bodies. into_iter ( ) . map ( make_match_arm) . chain ( [ else_arm] ) ;
128+ let match_expr = make. expr_match ( scrutinee_to_be_expr, make. match_arm_list ( arms) ) ;
129+ match_expr. indent ( IndentLevel :: from_node ( if_expr. syntax ( ) ) ) ;
130+ match_expr. into ( )
133131 } ;
134132
135133 let has_preceding_if_expr =
136134 if_expr. syntax ( ) . parent ( ) . is_some_and ( |it| ast:: IfExpr :: can_cast ( it. kind ( ) ) ) ;
137135 let expr = if has_preceding_if_expr {
138136 // make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
139- make:: block_expr ( None , Some ( match_expr) ) . into ( )
137+ make. block_expr ( [ ] , Some ( match_expr) ) . into ( )
140138 } else {
141139 match_expr
142140 } ;
143- edit. replace_ast :: < ast:: Expr > ( if_expr. into ( ) , expr) ;
141+
142+ let mut editor = builder. make_editor ( if_expr. syntax ( ) ) ;
143+ editor. replace ( if_expr. syntax ( ) , expr. syntax ( ) ) ;
144+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
145+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
144146 } ,
145147 )
146148}
147149
148150fn make_else_arm (
149151 ctx : & AssistContext < ' _ > ,
152+ make : & SyntaxFactory ,
150153 else_block : Option < ast:: BlockExpr > ,
151154 conditionals : & [ ( Either < ast:: Pat , ast:: Expr > , ast:: BlockExpr ) ] ,
152155) -> ast:: MatchArm {
153156 let ( pattern, expr) = if let Some ( else_block) = else_block {
154157 let pattern = match conditionals {
155- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
158+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
156159 [ ( Either :: Left ( pat) , _) ] => match ctx
157160 . sema
158161 . type_of_pat ( pat)
@@ -162,24 +165,24 @@ fn make_else_arm(
162165 if does_pat_match_variant ( pat, & it. sad_pattern ( ) ) {
163166 it. happy_pattern_wildcard ( )
164167 } else if does_pat_variant_nested_or_literal ( ctx, pat) {
165- make:: wildcard_pat ( ) . into ( )
168+ make. wildcard_pat ( ) . into ( )
166169 } else {
167170 it. sad_pattern ( )
168171 }
169172 }
170- None => make:: wildcard_pat ( ) . into ( ) ,
173+ None => make. wildcard_pat ( ) . into ( ) ,
171174 } ,
172- _ => make:: wildcard_pat ( ) . into ( ) ,
175+ _ => make. wildcard_pat ( ) . into ( ) ,
173176 } ;
174177 ( pattern, unwrap_trivial_block ( else_block) )
175178 } else {
176179 let pattern = match conditionals {
177- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
178- _ => make:: wildcard_pat ( ) . into ( ) ,
180+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
181+ _ => make. wildcard_pat ( ) . into ( ) ,
179182 } ;
180- ( pattern, make:: ext :: expr_unit ( ) )
183+ ( pattern, make. expr_unit ( ) )
181184 } ;
182- make:: match_arm ( pattern, None , expr)
185+ make. match_arm ( pattern, None , expr)
183186}
184187
185188// Assist: replace_match_with_if_let
@@ -245,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
245248 }
246249 _ => " let" ,
247250 } ;
248- let target = match_expr. syntax ( ) . text_range ( ) ;
249251 acc. add (
250252 AssistId ( "replace_match_with_if_let" , AssistKind :: RefactorRewrite ) ,
251253 format ! ( "Replace match with if{let_}" ) ,
252- target,
253- move |edit| {
254- fn make_block_expr ( expr : ast:: Expr ) -> ast:: BlockExpr {
254+ match_expr. syntax ( ) . text_range ( ) ,
255+ move |builder| {
256+ let make = SyntaxFactory :: new ( ) ;
257+ let make_block_expr = |expr : ast:: Expr | {
255258 // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
256259 // formatted without enclosing braces. If we encounter such block exprs,
257260 // wrap them in another BlockExpr.
258261 match expr {
259262 ast:: Expr :: BlockExpr ( block) if block. modifier ( ) . is_none ( ) => block,
260- expr => make:: block_expr ( iter :: empty ( ) , Some ( expr) ) ,
263+ expr => make. block_expr ( [ ] , Some ( expr) ) ,
261264 }
262- }
265+ } ;
263266
264267 let condition = match if_let_pat {
265268 ast:: Pat :: LiteralPat ( p)
@@ -270,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
270273 ast:: Pat :: LiteralPat ( p)
271274 if p. literal ( ) . is_some_and ( |it| it. token ( ) . kind ( ) == T ! [ false ] ) =>
272275 {
273- make:: expr_prefix ( T ! [ !] , scrutinee) . into ( )
276+ make. expr_prefix ( T ! [ !] , scrutinee) . into ( )
274277 }
275- _ => make:: expr_let ( if_let_pat, scrutinee) . into ( ) ,
278+ _ => make. expr_let ( if_let_pat, scrutinee) . into ( ) ,
276279 } ;
277- let then_block = make_block_expr ( then_expr. reset_indent ( ) ) ;
280+ let then_expr = then_expr. clone_for_update ( ) ;
281+ then_expr. reindent_to ( IndentLevel :: single ( ) ) ;
282+ let then_block = make_block_expr ( then_expr) ;
278283 let else_expr = if is_empty_expr ( & else_expr) { None } else { Some ( else_expr) } ;
279- let if_let_expr = make:: expr_if (
284+ let if_let_expr = make. expr_if (
280285 condition,
281286 then_block,
282287 else_expr. map ( make_block_expr) . map ( ast:: ElseBranch :: Block ) ,
283- )
284- . indent ( IndentLevel :: from_node ( match_expr. syntax ( ) ) ) ;
288+ ) ;
289+ if_let_expr . indent ( IndentLevel :: from_node ( match_expr. syntax ( ) ) ) ;
285290
286- edit. replace_ast :: < ast:: Expr > ( match_expr. into ( ) , if_let_expr. into ( ) ) ;
291+ let mut editor = builder. make_editor ( match_expr. syntax ( ) ) ;
292+ editor. replace ( match_expr. syntax ( ) , if_let_expr. syntax ( ) ) ;
293+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
294+ builder. add_file_edits ( ctx. file_id ( ) , editor) ;
287295 } ,
288296 )
289297}
0 commit comments