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,53 +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) => {
118- make:: match_arm ( iter:: once ( pat) , None , 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)
119119 }
120- Either :: Right ( _) if !pat_seen => make:: match_arm (
121- iter:: once ( make:: literal_pat ( "true" ) . into ( ) ) ,
122- None ,
123- unwrap_trivial_block ( body) ,
124- ) ,
125- Either :: Right ( expr) => make:: match_arm (
126- iter:: once ( make:: wildcard_pat ( ) . into ( ) ) ,
127- Some ( expr) ,
128- unwrap_trivial_block ( body) ,
120+ Either :: Right ( expr) => make. match_arm (
121+ make. wildcard_pat ( ) . into ( ) ,
122+ Some ( make. match_guard ( expr) ) ,
123+ body,
129124 ) ,
130125 }
131126 } ;
132- let arms = cond_bodies. into_iter ( ) . map ( make_match_arm) . chain ( iter:: once ( else_arm) ) ;
133- let match_expr = make:: expr_match ( scrutinee_to_be_expr, make:: match_arm_list ( arms) ) ;
134- match_expr. indent ( IndentLevel :: from_node ( if_expr. syntax ( ) ) )
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 ( )
135131 } ;
136132
137133 let has_preceding_if_expr =
138134 if_expr. syntax ( ) . parent ( ) . is_some_and ( |it| ast:: IfExpr :: can_cast ( it. kind ( ) ) ) ;
139135 let expr = if has_preceding_if_expr {
140136 // make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
141- make:: block_expr ( None , Some ( match_expr) ) . into ( )
137+ make. block_expr ( [ ] , Some ( match_expr) ) . into ( )
142138 } else {
143139 match_expr
144140 } ;
145- 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) ;
146146 } ,
147147 )
148148}
149149
150150fn make_else_arm (
151151 ctx : & AssistContext < ' _ > ,
152+ make : & SyntaxFactory ,
152153 else_block : Option < ast:: BlockExpr > ,
153154 conditionals : & [ ( Either < ast:: Pat , ast:: Expr > , ast:: BlockExpr ) ] ,
154155) -> ast:: MatchArm {
155156 let ( pattern, expr) = if let Some ( else_block) = else_block {
156157 let pattern = match conditionals {
157- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
158+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
158159 [ ( Either :: Left ( pat) , _) ] => match ctx
159160 . sema
160161 . type_of_pat ( pat)
@@ -164,24 +165,24 @@ fn make_else_arm(
164165 if does_pat_match_variant ( pat, & it. sad_pattern ( ) ) {
165166 it. happy_pattern_wildcard ( )
166167 } else if does_pat_variant_nested_or_literal ( ctx, pat) {
167- make:: wildcard_pat ( ) . into ( )
168+ make. wildcard_pat ( ) . into ( )
168169 } else {
169170 it. sad_pattern ( )
170171 }
171172 }
172- None => make:: wildcard_pat ( ) . into ( ) ,
173+ None => make. wildcard_pat ( ) . into ( ) ,
173174 } ,
174- _ => make:: wildcard_pat ( ) . into ( ) ,
175+ _ => make. wildcard_pat ( ) . into ( ) ,
175176 } ;
176177 ( pattern, unwrap_trivial_block ( else_block) )
177178 } else {
178179 let pattern = match conditionals {
179- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
180- _ => make:: wildcard_pat ( ) . into ( ) ,
180+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
181+ _ => make. wildcard_pat ( ) . into ( ) ,
181182 } ;
182- ( pattern, make:: expr_unit ( ) )
183+ ( pattern, make. expr_unit ( ) )
183184 } ;
184- make:: match_arm ( iter :: once ( pattern) , None , expr)
185+ make. match_arm ( pattern, None , expr)
185186}
186187
187188// Assist: replace_match_with_if_let
@@ -247,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
247248 }
248249 _ => " let" ,
249250 } ;
250- let target = match_expr. syntax ( ) . text_range ( ) ;
251251 acc. add (
252252 AssistId ( "replace_match_with_if_let" , AssistKind :: RefactorRewrite ) ,
253253 format ! ( "Replace match with if{let_}" ) ,
254- target,
255- move |edit| {
256- 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 | {
257258 // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
258259 // formatted without enclosing braces. If we encounter such block exprs,
259260 // wrap them in another BlockExpr.
260261 match expr {
261262 ast:: Expr :: BlockExpr ( block) if block. modifier ( ) . is_none ( ) => block,
262- expr => make:: block_expr ( iter :: empty ( ) , Some ( expr) ) ,
263+ expr => make. block_expr ( [ ] , Some ( expr) ) ,
263264 }
264- }
265+ } ;
265266
266267 let condition = match if_let_pat {
267268 ast:: Pat :: LiteralPat ( p)
@@ -272,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
272273 ast:: Pat :: LiteralPat ( p)
273274 if p. literal ( ) . is_some_and ( |it| it. token ( ) . kind ( ) == T ! [ false ] ) =>
274275 {
275- make:: expr_prefix ( T ! [ !] , scrutinee)
276+ make. expr_prefix ( T ! [ !] , scrutinee) . into ( )
276277 }
277- _ => make:: expr_let ( if_let_pat, scrutinee) . into ( ) ,
278+ _ => make. expr_let ( if_let_pat, scrutinee) . into ( ) ,
278279 } ;
279- 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) ;
280283 let else_expr = if is_empty_expr ( & else_expr) { None } else { Some ( else_expr) } ;
281- let if_let_expr = make:: expr_if (
284+ let if_let_expr = make. expr_if (
282285 condition,
283286 then_block,
284287 else_expr. map ( make_block_expr) . map ( ast:: ElseBranch :: Block ) ,
285- )
286- . indent ( IndentLevel :: from_node ( match_expr. syntax ( ) ) ) ;
288+ ) ;
289+ if_let_expr . indent ( IndentLevel :: from_node ( match_expr. syntax ( ) ) ) ;
287290
288- edit. replace_ast :: < ast:: Expr > ( match_expr. into ( ) , if_let_expr) ;
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) ;
289295 } ,
290296 )
291297}
0 commit comments