Skip to content

Commit 1e975d6

Browse files
authored
Merge pull request #18855 from Giga-Bowser/migrate-if-let
internal: Migrate `if let` replacement assists to `SyntaxEditor`
2 parents f2a7136 + 54d9b5a commit 1e975d6

23 files changed

+433
-154
lines changed

crates/ide-assists/src/handlers/add_missing_match_arms.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
212212
!hidden
213213
})
214214
.map(|(pat, _)| {
215-
make::match_arm(iter::once(pat), None, make::ext::expr_todo())
216-
.clone_for_update()
215+
make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update()
217216
});
218217

219218
let catch_all_arm = new_match_arm_list
@@ -243,12 +242,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
243242

244243
if needs_catch_all_arm && !has_catch_all_arm {
245244
cov_mark::hit!(added_wildcard_pattern);
246-
let arm = make::match_arm(
247-
iter::once(make::wildcard_pat().into()),
248-
None,
249-
make::ext::expr_todo(),
250-
)
251-
.clone_for_update();
245+
let arm =
246+
make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo())
247+
.clone_for_update();
252248
todo_placeholders.push(arm.expr().unwrap());
253249
added_arms.push(arm);
254250
}

crates/ide-assists/src/handlers/apply_demorgan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
252252

253253
/// Add bang and parentheses to the expression.
254254
fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
255-
make::expr_prefix(T![!], make::expr_paren(expr))
255+
make::expr_prefix(T![!], make::expr_paren(expr)).into()
256256
}
257257

258258
#[cfg(test)]

crates/ide-assists/src/handlers/bool_to_enum.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr {
195195
make::tail_only_block_expr(true_expr),
196196
Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))),
197197
)
198+
.into()
198199
}
199200
}
200201

crates/ide-assists/src/handlers/convert_closure_to_fn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ fn wrap_capture_in_deref_if_needed(
507507
if does_autoderef {
508508
return capture_name;
509509
}
510-
make::expr_prefix(T![*], capture_name)
510+
make::expr_prefix(T![*], capture_name).into()
511511
}
512512

513513
fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr {

crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
9797
);
9898

9999
for r in return_exprs {
100-
let t = r.expr().unwrap_or_else(make::expr_unit);
100+
let t = r.expr().unwrap_or_else(make::ext::expr_unit);
101101
ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
102102
}
103103

crates/ide-assists/src/handlers/convert_while_to_loop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
6060
.indent(while_indent_level);
6161
let block_expr = if is_pattern_cond(while_cond.clone()) {
6262
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
63-
let stmts = iter::once(make::expr_stmt(if_expr).into());
63+
let stmts = iter::once(make::expr_stmt(if_expr.into()).into());
6464
make::block_expr(stmts, None)
6565
} else {
6666
let if_cond = invert_boolean_expression(while_cond);

crates/ide-assists/src/handlers/extract_function.rs

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ impl FlowHandler {
15331533
.into(),
15341534
call_expr,
15351535
);
1536-
make::expr_if(condition.into(), block, None)
1536+
make::expr_if(condition.into(), block, None).into()
15371537
}
15381538
FlowHandler::IfOption { action } => {
15391539
let path = make::ext::ident_path("Some");
@@ -1544,7 +1544,7 @@ impl FlowHandler {
15441544
let action_expr = action.make_result_handler(Some(value));
15451545
let action_stmt = make::expr_stmt(action_expr);
15461546
let then = make::block_expr(iter::once(action_stmt.into()), None);
1547-
make::expr_if(cond.into(), then, None)
1547+
make::expr_if(cond.into(), then, None).into()
15481548
}
15491549
FlowHandler::MatchOption { none } => {
15501550
let some_name = "value";
@@ -1554,15 +1554,15 @@ impl FlowHandler {
15541554
let value_pat = make::ext::simple_ident_pat(make::name(some_name));
15551555
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
15561556
let value = make::expr_path(make::ext::ident_path(some_name));
1557-
make::match_arm(iter::once(pat.into()), None, value)
1557+
make::match_arm(pat.into(), None, value)
15581558
};
15591559
let none_arm = {
15601560
let path = make::ext::ident_path("None");
15611561
let pat = make::path_pat(path);
1562-
make::match_arm(iter::once(pat), None, none.make_result_handler(None))
1562+
make::match_arm(pat, None, none.make_result_handler(None))
15631563
};
15641564
let arms = make::match_arm_list(vec![some_arm, none_arm]);
1565-
make::expr_match(call_expr, arms)
1565+
make::expr_match(call_expr, arms).into()
15661566
}
15671567
FlowHandler::MatchResult { err } => {
15681568
let ok_name = "value";
@@ -1573,21 +1573,17 @@ impl FlowHandler {
15731573
let value_pat = make::ext::simple_ident_pat(make::name(ok_name));
15741574
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
15751575
let value = make::expr_path(make::ext::ident_path(ok_name));
1576-
make::match_arm(iter::once(pat.into()), None, value)
1576+
make::match_arm(pat.into(), None, value)
15771577
};
15781578
let err_arm = {
15791579
let path = make::ext::ident_path("Err");
15801580
let value_pat = make::ext::simple_ident_pat(make::name(err_name));
15811581
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
15821582
let value = make::expr_path(make::ext::ident_path(err_name));
1583-
make::match_arm(
1584-
iter::once(pat.into()),
1585-
None,
1586-
err.make_result_handler(Some(value)),
1587-
)
1583+
make::match_arm(pat.into(), None, err.make_result_handler(Some(value)))
15881584
};
15891585
let arms = make::match_arm_list(vec![ok_arm, err_arm]);
1590-
make::expr_match(call_expr, arms)
1586+
make::expr_match(call_expr, arms).into()
15911587
}
15921588
}
15931589
}
@@ -1879,7 +1875,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
18791875
.iter()
18801876
.map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
18811877
let expr = make::expr_tuple(exprs);
1882-
tail_expr = Some(expr);
1878+
tail_expr = Some(expr.into());
18831879
}
18841880
},
18851881
};
@@ -1910,7 +1906,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
19101906
match &handler {
19111907
FlowHandler::None => block,
19121908
FlowHandler::Try { kind } => {
1913-
let block = with_default_tail_expr(block, make::expr_unit());
1909+
let block = with_default_tail_expr(block, make::ext::expr_unit());
19141910
map_tail_expr(block, |tail_expr| {
19151911
let constructor = match kind {
19161912
TryKind::Option => "Some",
@@ -1924,7 +1920,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
19241920
FlowHandler::If { .. } => {
19251921
let controlflow_continue = make::expr_call(
19261922
make::expr_path(make::path_from_text("ControlFlow::Continue")),
1927-
make::arg_list(iter::once(make::expr_unit())),
1923+
make::arg_list([make::ext::expr_unit()]),
19281924
);
19291925
with_tail_expr(block, controlflow_continue)
19301926
}
@@ -2127,17 +2123,17 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Op
21272123
FlowHandler::None | FlowHandler::Try { .. } => return None,
21282124
FlowHandler::If { .. } => make::expr_call(
21292125
make::expr_path(make::path_from_text("ControlFlow::Break")),
2130-
make::arg_list(iter::once(make::expr_unit())),
2126+
make::arg_list([make::ext::expr_unit()]),
21312127
),
21322128
FlowHandler::IfOption { .. } => {
2133-
let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
2134-
let args = make::arg_list(iter::once(expr));
2129+
let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
2130+
let args = make::arg_list([expr]);
21352131
make::expr_call(make::expr_path(make::ext::ident_path("Some")), args)
21362132
}
21372133
FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")),
21382134
FlowHandler::MatchResult { .. } => {
2139-
let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
2140-
let args = make::arg_list(iter::once(expr));
2135+
let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
2136+
let args = make::arg_list([expr]);
21412137
make::expr_call(make::expr_path(make::ext::ident_path("Err")), args)
21422138
}
21432139
};

crates/ide-assists/src/handlers/move_guard.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
6161
};
6262

6363
edit.delete(guard.syntax().text_range());
64-
edit.replace_ast(arm_expr, if_expr);
64+
edit.replace_ast(arm_expr, if_expr.into());
6565
},
6666
)
6767
}

crates/ide-assists/src/handlers/remove_dbg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
102102
};
103103
(range, None)
104104
},
105-
_ => (macro_call.syntax().text_range(), Some(make::expr_unit())),
105+
_ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())),
106106
}
107107
}
108108
}
@@ -152,7 +152,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
152152
exprs => {
153153
let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
154154
let expr = make::expr_tuple(exprs);
155-
(macro_call.syntax().text_range(), Some(expr))
155+
(macro_call.syntax().text_range(), Some(expr.into()))
156156
}
157157
})
158158
}

crates/ide-assists/src/handlers/replace_if_let_with_match.rs

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::iter::{self, successors};
1+
use std::iter::successors;
22

33
use either::Either;
44
use ide_db::{
@@ -8,11 +8,7 @@ use ide_db::{
88
RootDatabase,
99
};
1010
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},
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

150150
fn 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

Comments
 (0)