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,53 +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) => {
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)
119
119
}
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,
129
124
) ,
130
125
}
131
126
} ;
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 ( )
135
131
} ;
136
132
137
133
let has_preceding_if_expr =
138
134
if_expr. syntax ( ) . parent ( ) . is_some_and ( |it| ast:: IfExpr :: can_cast ( it. kind ( ) ) ) ;
139
135
let expr = if has_preceding_if_expr {
140
136
// 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 ( )
142
138
} else {
143
139
match_expr
144
140
} ;
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) ;
146
146
} ,
147
147
)
148
148
}
149
149
150
150
fn make_else_arm (
151
151
ctx : & AssistContext < ' _ > ,
152
+ make : & SyntaxFactory ,
152
153
else_block : Option < ast:: BlockExpr > ,
153
154
conditionals : & [ ( Either < ast:: Pat , ast:: Expr > , ast:: BlockExpr ) ] ,
154
155
) -> ast:: MatchArm {
155
156
let ( pattern, expr) = if let Some ( else_block) = else_block {
156
157
let pattern = match conditionals {
157
- [ ( Either :: Right ( _) , _) ] => make:: literal_pat ( "false" ) . into ( ) ,
158
+ [ ( Either :: Right ( _) , _) ] => make. literal_pat ( "false" ) . into ( ) ,
158
159
[ ( Either :: Left ( pat) , _) ] => match ctx
159
160
. sema
160
161
. type_of_pat ( pat)
@@ -164,24 +165,24 @@ fn make_else_arm(
164
165
if does_pat_match_variant ( pat, & it. sad_pattern ( ) ) {
165
166
it. happy_pattern_wildcard ( )
166
167
} else if does_pat_variant_nested_or_literal ( ctx, pat) {
167
- make:: wildcard_pat ( ) . into ( )
168
+ make. wildcard_pat ( ) . into ( )
168
169
} else {
169
170
it. sad_pattern ( )
170
171
}
171
172
}
172
- None => make:: wildcard_pat ( ) . into ( ) ,
173
+ None => make. wildcard_pat ( ) . into ( ) ,
173
174
} ,
174
- _ => make:: wildcard_pat ( ) . into ( ) ,
175
+ _ => make. wildcard_pat ( ) . into ( ) ,
175
176
} ;
176
177
( pattern, unwrap_trivial_block ( else_block) )
177
178
} else {
178
179
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 ( ) ,
181
182
} ;
182
- ( pattern, make:: expr_unit ( ) )
183
+ ( pattern, make. expr_unit ( ) )
183
184
} ;
184
- make:: match_arm ( iter :: once ( pattern) , None , expr)
185
+ make. match_arm ( pattern, None , expr)
185
186
}
186
187
187
188
// Assist: replace_match_with_if_let
@@ -247,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
247
248
}
248
249
_ => " let" ,
249
250
} ;
250
- let target = match_expr. syntax ( ) . text_range ( ) ;
251
251
acc. add (
252
252
AssistId ( "replace_match_with_if_let" , AssistKind :: RefactorRewrite ) ,
253
253
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 | {
257
258
// Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
258
259
// formatted without enclosing braces. If we encounter such block exprs,
259
260
// wrap them in another BlockExpr.
260
261
match expr {
261
262
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) ) ,
263
264
}
264
- }
265
+ } ;
265
266
266
267
let condition = match if_let_pat {
267
268
ast:: Pat :: LiteralPat ( p)
@@ -272,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
272
273
ast:: Pat :: LiteralPat ( p)
273
274
if p. literal ( ) . is_some_and ( |it| it. token ( ) . kind ( ) == T ! [ false ] ) =>
274
275
{
275
- make:: expr_prefix ( T ! [ !] , scrutinee)
276
+ make. expr_prefix ( T ! [ !] , scrutinee) . into ( )
276
277
}
277
- _ => make:: expr_let ( if_let_pat, scrutinee) . into ( ) ,
278
+ _ => make. expr_let ( if_let_pat, scrutinee) . into ( ) ,
278
279
} ;
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) ;
280
283
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 (
282
285
condition,
283
286
then_block,
284
287
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 ( ) ) ) ;
287
290
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) ;
289
295
} ,
290
296
)
291
297
}
0 commit comments