Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/convert_bool_then.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/convert_bool_then.rs | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs index eb784cd122..151c71c0a7 100644 --- a/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -8,8 +8,9 @@ use ide_db::{ }; use itertools::Itertools; use syntax::{ - ast::{self, edit::AstNodeEdit, make, HasArgList}, - ted, AstNode, SyntaxNode, + ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory, HasArgList}, + syntax_editor::SyntaxEditor, + AstNode, SyntaxNode, }; use crate::{ @@ -76,9 +77,9 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> "Convert `if` expression to `bool::then` call", target, |builder| { - let closure_body = closure_body.clone_for_update(); + let closure_body = closure_body.clone_subtree(); + let mut editor = SyntaxEditor::new(closure_body.syntax().clone()); // Rewrite all `Some(e)` in tail position to `e` - let mut replacements = Vec::new(); for_each_tail_expr(&closure_body, &mut |e| { let e = match e { ast::Expr::BreakExpr(e) => e.expr(), @@ -88,12 +89,16 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> if let Some(ast::Expr::CallExpr(call)) = e { if let Some(arg_list) = call.arg_list() { if let Some(arg) = arg_list.args().next() { - replacements.push((call.syntax().clone(), arg.syntax().clone())); + editor.replace(call.syntax(), arg.syntax()); } } } }); - replacements.into_iter().for_each(|(old, new)| ted::replace(old, new)); + let edit = editor.finish(); + let closure_body = ast::Expr::cast(edit.new_root().clone()).unwrap(); + + let mut editor = builder.make_editor(expr.syntax()); + let make = SyntaxFactory::new(); let closure_body = match closure_body { ast::Expr::BlockExpr(block) => unwrap_trivial_block(block), e => e, @@ -119,11 +124,18 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> | ast::Expr::WhileExpr(_) | ast::Expr::YieldExpr(_) ); - let cond = if invert_cond { invert_boolean_expression(cond) } else { cond }; - let cond = if parenthesize { make::expr_paren(cond) } else { cond }; - let arg_list = make::arg_list(Some(make::expr_closure(None, closure_body))); - let mcall = make::expr_method_call(cond, make::name_ref("then"), arg_list); - builder.replace(target, mcall.to_string()); + let cond = if invert_cond { + invert_boolean_expression(&make, cond) + } else { + cond.clone_for_update() + }; + let cond = if parenthesize { make.expr_paren(cond).into() } else { cond }; + let arg_list = make.arg_list(Some(make.expr_closure(None, closure_body).into())); + let mcall = make.expr_method_call(cond, make.name_ref("then"), arg_list); + editor.replace(expr.syntax(), mcall.syntax()); + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } @@ -173,16 +185,17 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> "Convert `bool::then` call to `if`", target, |builder| { - let closure_body = match closure_body { + let mapless_make = SyntaxFactory::without_mappings(); + let closure_body = match closure_body.reset_indent() { ast::Expr::BlockExpr(block) => block, - e => make::block_expr(None, Some(e)), + e => mapless_make.block_expr(None, Some(e)), }; - let closure_body = closure_body.clone_for_update(); + let closure_body = closure_body.clone_subtree(); + let mut editor = SyntaxEditor::new(closure_body.syntax().clone()); // Wrap all tails in `Some(...)` - let none_path = make::expr_path(make::ext::ident_path("None")); - let some_path = make::expr_path(make::ext::ident_path("Some")); - let mut replacements = Vec::new(); + let none_path = mapless_make.expr_path(mapless_make.ident_path("None")); + let some_path = mapless_make.expr_path(mapless_make.ident_path("Some")); for_each_tail_expr(&ast::Expr::BlockExpr(closure_body.clone()), &mut |e| { let e = match e { ast::Expr::BreakExpr(e) => e.expr(), @@ -190,28 +203,37 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> _ => Some(e.clone()), }; if let Some(expr) = e { - replacements.push(( + editor.replace( expr.syntax().clone(), - make::expr_call(some_path.clone(), make::arg_list(Some(expr))) + mapless_make + .expr_call(some_path.clone(), mapless_make.arg_list(Some(expr))) .syntax() - .clone_for_update(), - )); + .clone(), + ); } }); - replacements.into_iter().for_each(|(old, new)| ted::replace(old, new)); + let edit = editor.finish(); + let closure_body = ast::BlockExpr::cast(edit.new_root().clone()).unwrap(); + + let mut editor = builder.make_editor(mcall.syntax()); + let make = SyntaxFactory::new(); let cond = match &receiver { ast::Expr::ParenExpr(expr) => expr.expr().unwrap_or(receiver), _ => receiver, }; - let if_expr = make::expr_if( - cond, - closure_body.reset_indent(), - Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))), - ) - .indent(mcall.indent_level()); + let if_expr = make + .expr_if( + cond, + closure_body, + Some(ast::ElseBranch::Block(make.block_expr(None, Some(none_path)))), + ) + .indent(mcall.indent_level()) + .clone_for_update(); + editor.replace(mcall.syntax().clone(), if_expr.syntax().clone()); - builder.replace(target, if_expr.to_string()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } |