Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/replace_if_let_with_match.rs')
-rw-r--r--crates/ide-assists/src/handlers/replace_if_let_with_match.rs62
1 files changed, 47 insertions, 15 deletions
diff --git a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index ada2fd9b21..0badad7d0c 100644
--- a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -111,9 +111,10 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
format!("Replace if{let_} with match"),
available_range,
move |builder| {
- let make = SyntaxFactory::with_mappings();
+ let editor = builder.make_editor(if_expr.syntax());
+ let make = editor.make();
let match_expr: ast::Expr = {
- let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies);
+ let else_arm = make_else_arm(ctx, make, else_block, &cond_bodies);
let make_match_arm =
|(pat, guard, body): (_, Option<ast::Expr>, ast::BlockExpr)| {
// Dedent from original position, then indent for match arm
@@ -131,6 +132,11 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
};
let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
let expr = scrutinee_to_be_expr.reset_indent();
+ let expr = if match_scrutinee_needs_paren(&expr) {
+ make.expr_paren(expr).into()
+ } else {
+ expr
+ };
let match_expr = make.expr_match(expr, make.match_arm_list(arms)).indent(indent);
match_expr.into()
};
@@ -146,10 +152,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
} else {
match_expr
};
-
- let mut editor = builder.make_editor(if_expr.syntax());
editor.replace(if_expr.syntax(), expr.syntax());
- editor.add_mappings(make.finish_with_mappings());
builder.add_file_edits(ctx.vfs_file_id(), editor);
},
)
@@ -267,7 +270,8 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
format!("Replace match with if{let_}"),
match_expr.syntax().text_range(),
move |builder| {
- let make = SyntaxFactory::with_mappings();
+ let editor = builder.make_editor(match_expr.syntax());
+ let make = editor.make();
let make_block_expr = |expr: ast::Expr| {
// Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
// formatted without enclosing braces. If we encounter such block exprs,
@@ -292,7 +296,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
_ => make.expr_let(if_let_pat, scrutinee).into(),
};
let condition = if let Some(guard) = guard {
- let guard = wrap_paren(guard, &make, ast::prec::ExprPrecedence::LAnd);
+ let guard = wrap_paren(guard, make, ast::prec::ExprPrecedence::LAnd);
make.expr_bin(condition, ast::BinaryOp::LogicOp(ast::LogicOp::And), guard).into()
} else {
condition
@@ -309,9 +313,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
)
.indent(IndentLevel::from_node(match_expr.syntax()));
- let mut editor = builder.make_editor(match_expr.syntax());
editor.replace(match_expr.syntax(), if_let_expr.syntax());
- editor.add_mappings(make.finish_with_mappings());
builder.add_file_edits(ctx.vfs_file_id(), editor);
},
)
@@ -402,27 +404,37 @@ fn let_and_guard(cond: &ast::Expr) -> (Option<ast::LetExpr>, Option<ast::Expr>)
} else if let ast::Expr::BinExpr(bin_expr) = cond
&& let Some(ast::Expr::LetExpr(let_expr)) = and_bin_expr_left(bin_expr).lhs()
{
- let (mut edit, new_expr) = SyntaxEditor::with_ast_node(bin_expr);
-
+ let (editor, new_expr) = SyntaxEditor::with_ast_node(bin_expr);
let left_bin = and_bin_expr_left(&new_expr);
if let Some(rhs) = left_bin.rhs() {
- edit.replace(left_bin.syntax(), rhs.syntax());
+ editor.replace(left_bin.syntax(), rhs.syntax());
} else {
if let Some(next) = left_bin.syntax().next_sibling_or_token()
&& next.kind() == SyntaxKind::WHITESPACE
{
- edit.delete(next);
+ editor.delete(next);
}
- edit.delete(left_bin.syntax());
+ editor.delete(left_bin.syntax());
}
- let new_expr = edit.finish().new_root().clone();
+ let new_expr = editor.finish().new_root().clone();
(Some(let_expr), ast::Expr::cast(new_expr))
} else {
(None, Some(cond.clone()))
}
}
+fn match_scrutinee_needs_paren(expr: &ast::Expr) -> bool {
+ let make = SyntaxFactory::without_mappings();
+ let fake_scrutinee = make.expr_unit();
+ let fake_match = make.expr_match(fake_scrutinee, make.match_arm_list(std::iter::empty()));
+ let Some(fake_expr) = fake_match.expr() else {
+ stdx::never!();
+ return false;
+ };
+ expr.needs_parens_in_place_of(fake_match.syntax(), fake_expr.syntax())
+}
+
fn and_bin_expr_left(expr: &ast::BinExpr) -> ast::BinExpr {
if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
&& let Some(ast::Expr::BinExpr(left)) = expr.lhs()
@@ -452,6 +464,26 @@ fn main() {
}
#[test]
+ fn test_if_with_match_paren_jump_scrutinee() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+fn f() {
+ if $0(return) {}
+}
+"#,
+ r#"
+fn f() {
+ match (return) {
+ true => {}
+ false => (),
+ }
+}
+"#,
+ )
+ }
+
+ #[test]
fn test_if_with_match_no_else() {
check_assist(
replace_if_let_with_match,