Skip to content

Commit 54d9b5a

Browse files
committed
internal: Migrate if let <=> match assists to SyntaxEditor
1 parent eb2ce57 commit 54d9b5a

File tree

1 file changed

+53
-45
lines changed

1 file changed

+53
-45
lines changed

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

Lines changed: 53 additions & 45 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,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

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

Comments
 (0)