1
- use std:: iter:: { self , successors} ;
1
+ use std:: iter:: successors;
2
2
3
3
use either:: Either ;
4
4
use ide_db:: {
@@ -8,11 +8,7 @@ use ide_db::{
8
8
RootDatabase ,
9
9
} ;
10
10
use 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 } ,
16
12
AstNode , TextRange , T ,
17
13
} ;
18
14
@@ -108,51 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
108
104
AssistId ( "replace_if_let_with_match" , AssistKind :: RefactorRewrite ) ,
109
105
format ! ( "Replace if{let_} with match" ) ,
110
106
available_range,
111
- move |edit| {
107
+ move |builder| {
108
+ let make = SyntaxFactory :: new ( ) ;
112
109
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) ;
114
111
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) ;
116
115
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,
127
124
) ,
128
125
}
129
126
} ;
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 ( )
133
131
} ;
134
132
135
133
let has_preceding_if_expr =
136
134
if_expr. syntax ( ) . parent ( ) . is_some_and ( |it| ast:: IfExpr :: can_cast ( it. kind ( ) ) ) ;
137
135
let expr = if has_preceding_if_expr {
138
136
// 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 ( )
140
138
} else {
141
139
match_expr
142
140
} ;
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) ;
144
146
} ,
145
147
)
146
148
}
147
149
148
150
fn make_else_arm (
149
151
ctx : & AssistContext < ' _ > ,
152
+ make : & SyntaxFactory ,
150
153
else_block : Option < ast:: BlockExpr > ,
151
154
conditionals : & [ ( Either < ast:: Pat , ast:: Expr > , ast:: BlockExpr ) ] ,
152
155
) -> ast:: MatchArm {
153
156
let ( pattern, expr) = if let Some ( else_block) = else_block {
154
157
let pattern = match conditionals {
155
- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
158
+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
156
159
[ ( Either :: Left ( pat) , _) ] => match ctx
157
160
. sema
158
161
. type_of_pat ( pat)
@@ -162,24 +165,24 @@ fn make_else_arm(
162
165
if does_pat_match_variant ( pat, & it. sad_pattern ( ) ) {
163
166
it. happy_pattern_wildcard ( )
164
167
} else if does_pat_variant_nested_or_literal ( ctx, pat) {
165
- make:: wildcard_pat ( ) . into ( )
168
+ make. wildcard_pat ( ) . into ( )
166
169
} else {
167
170
it. sad_pattern ( )
168
171
}
169
172
}
170
- None => make:: wildcard_pat ( ) . into ( ) ,
173
+ None => make. wildcard_pat ( ) . into ( ) ,
171
174
} ,
172
- _ => make:: wildcard_pat ( ) . into ( ) ,
175
+ _ => make. wildcard_pat ( ) . into ( ) ,
173
176
} ;
174
177
( pattern, unwrap_trivial_block ( else_block) )
175
178
} else {
176
179
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 ( ) ,
179
182
} ;
180
- ( pattern, make:: ext :: expr_unit ( ) )
183
+ ( pattern, make. expr_unit ( ) )
181
184
} ;
182
- make:: match_arm ( pattern, None , expr)
185
+ make. match_arm ( pattern, None , expr)
183
186
}
184
187
185
188
// Assist: replace_match_with_if_let
@@ -245,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
245
248
}
246
249
_ => " let" ,
247
250
} ;
248
- let target = match_expr. syntax ( ) . text_range ( ) ;
249
251
acc. add (
250
252
AssistId ( "replace_match_with_if_let" , AssistKind :: RefactorRewrite ) ,
251
253
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 | {
255
258
// Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
256
259
// formatted without enclosing braces. If we encounter such block exprs,
257
260
// wrap them in another BlockExpr.
258
261
match expr {
259
262
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) ) ,
261
264
}
262
- }
265
+ } ;
263
266
264
267
let condition = match if_let_pat {
265
268
ast:: Pat :: LiteralPat ( p)
@@ -270,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
270
273
ast:: Pat :: LiteralPat ( p)
271
274
if p. literal ( ) . is_some_and ( |it| it. token ( ) . kind ( ) == T ! [ false ] ) =>
272
275
{
273
- make:: expr_prefix ( T ! [ !] , scrutinee) . into ( )
276
+ make. expr_prefix ( T ! [ !] , scrutinee) . into ( )
274
277
}
275
- _ => make:: expr_let ( if_let_pat, scrutinee) . into ( ) ,
278
+ _ => make. expr_let ( if_let_pat, scrutinee) . into ( ) ,
276
279
} ;
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) ;
278
283
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 (
280
285
condition,
281
286
then_block,
282
287
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 ( ) ) ) ;
285
290
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) ;
287
295
} ,
288
296
)
289
297
}
0 commit comments