Skip to content

Commit f6ea1c4

Browse files
committed
Migrate convert_bool_then to SyntaxEditor
Update assist docs
1 parent fe84446 commit f6ea1c4

File tree

5 files changed

+222
-98
lines changed

5 files changed

+222
-98
lines changed

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

+52-30
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use ide_db::{
88
};
99
use itertools::Itertools;
1010
use syntax::{
11-
ast::{self, edit::AstNodeEdit, make, HasArgList},
12-
ted, AstNode, SyntaxNode,
11+
ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory, HasArgList},
12+
syntax_editor::SyntaxEditor,
13+
AstNode, SyntaxNode,
1314
};
1415

1516
use crate::{
16-
utils::{invert_boolean_expression_legacy, unwrap_trivial_block},
17+
utils::{invert_boolean_expression, unwrap_trivial_block},
1718
AssistContext, AssistId, AssistKind, Assists,
1819
};
1920

@@ -76,9 +77,9 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
7677
"Convert `if` expression to `bool::then` call",
7778
target,
7879
|builder| {
79-
let closure_body = closure_body.clone_for_update();
80+
let closure_body = closure_body.clone_subtree();
81+
let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
8082
// Rewrite all `Some(e)` in tail position to `e`
81-
let mut replacements = Vec::new();
8283
for_each_tail_expr(&closure_body, &mut |e| {
8384
let e = match e {
8485
ast::Expr::BreakExpr(e) => e.expr(),
@@ -88,12 +89,16 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
8889
if let Some(ast::Expr::CallExpr(call)) = e {
8990
if let Some(arg_list) = call.arg_list() {
9091
if let Some(arg) = arg_list.args().next() {
91-
replacements.push((call.syntax().clone(), arg.syntax().clone()));
92+
editor.replace(call.syntax(), arg.syntax());
9293
}
9394
}
9495
}
9596
});
96-
replacements.into_iter().for_each(|(old, new)| ted::replace(old, new));
97+
let edit = editor.finish();
98+
let closure_body = ast::Expr::cast(edit.new_root().clone()).unwrap();
99+
100+
let mut editor = builder.make_editor(expr.syntax());
101+
let make = SyntaxFactory::new();
97102
let closure_body = match closure_body {
98103
ast::Expr::BlockExpr(block) => unwrap_trivial_block(block),
99104
e => e,
@@ -119,11 +124,18 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
119124
| ast::Expr::WhileExpr(_)
120125
| ast::Expr::YieldExpr(_)
121126
);
122-
let cond = if invert_cond { invert_boolean_expression_legacy(cond) } else { cond };
123-
let cond = if parenthesize { make::expr_paren(cond) } else { cond };
124-
let arg_list = make::arg_list(Some(make::expr_closure(None, closure_body)));
125-
let mcall = make::expr_method_call(cond, make::name_ref("then"), arg_list);
126-
builder.replace(target, mcall.to_string());
127+
let cond = if invert_cond {
128+
invert_boolean_expression(&make, cond)
129+
} else {
130+
cond.clone_for_update()
131+
};
132+
let cond = if parenthesize { make.expr_paren(cond).into() } else { cond };
133+
let arg_list = make.arg_list(Some(make.expr_closure(None, closure_body).into()));
134+
let mcall = make.expr_method_call(cond, make.name_ref("then"), arg_list);
135+
editor.replace(expr.syntax(), mcall.syntax());
136+
137+
editor.add_mappings(make.finish_with_mappings());
138+
builder.add_file_edits(ctx.file_id(), editor);
127139
},
128140
)
129141
}
@@ -173,45 +185,55 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
173185
"Convert `bool::then` call to `if`",
174186
target,
175187
|builder| {
176-
let closure_body = match closure_body {
188+
let mapless_make = SyntaxFactory::without_mappings();
189+
let closure_body = match closure_body.reset_indent() {
177190
ast::Expr::BlockExpr(block) => block,
178-
e => make::block_expr(None, Some(e)),
191+
e => mapless_make.block_expr(None, Some(e)),
179192
};
180193

181-
let closure_body = closure_body.clone_for_update();
194+
let closure_body = closure_body.clone_subtree();
195+
let mut editor = SyntaxEditor::new(closure_body.syntax().clone());
182196
// Wrap all tails in `Some(...)`
183-
let none_path = make::expr_path(make::ext::ident_path("None"));
184-
let some_path = make::expr_path(make::ext::ident_path("Some"));
185-
let mut replacements = Vec::new();
197+
let none_path = mapless_make.expr_path(mapless_make.ident_path("None"));
198+
let some_path = mapless_make.expr_path(mapless_make.ident_path("Some"));
186199
for_each_tail_expr(&ast::Expr::BlockExpr(closure_body.clone()), &mut |e| {
187200
let e = match e {
188201
ast::Expr::BreakExpr(e) => e.expr(),
189202
ast::Expr::ReturnExpr(e) => e.expr(),
190203
_ => Some(e.clone()),
191204
};
192205
if let Some(expr) = e {
193-
replacements.push((
206+
editor.replace(
194207
expr.syntax().clone(),
195-
make::expr_call(some_path.clone(), make::arg_list(Some(expr)))
208+
mapless_make
209+
.expr_call(some_path.clone(), mapless_make.arg_list(Some(expr)))
196210
.syntax()
197-
.clone_for_update(),
198-
));
211+
.clone(),
212+
);
199213
}
200214
});
201-
replacements.into_iter().for_each(|(old, new)| ted::replace(old, new));
215+
let edit = editor.finish();
216+
let closure_body = ast::BlockExpr::cast(edit.new_root().clone()).unwrap();
217+
218+
let mut editor = builder.make_editor(mcall.syntax());
219+
let make = SyntaxFactory::new();
202220

203221
let cond = match &receiver {
204222
ast::Expr::ParenExpr(expr) => expr.expr().unwrap_or(receiver),
205223
_ => receiver,
206224
};
207-
let if_expr = make::expr_if(
208-
cond,
209-
closure_body.reset_indent(),
210-
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
211-
)
212-
.indent(mcall.indent_level());
225+
let if_expr = make
226+
.expr_if(
227+
cond,
228+
closure_body,
229+
Some(ast::ElseBranch::Block(make.block_expr(None, Some(none_path)))),
230+
)
231+
.indent(mcall.indent_level())
232+
.clone_for_update();
233+
editor.replace(mcall.syntax().clone(), if_expr.syntax().clone());
213234

214-
builder.replace(target, if_expr.to_string());
235+
editor.add_mappings(make.finish_with_mappings());
236+
builder.add_file_edits(ctx.file_id(), editor);
215237
},
216238
)
217239
}

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

+48-38
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use syntax::{
1414
ast::{
1515
self,
1616
edit::{AstNodeEdit, IndentLevel},
17-
make, HasArgList, HasGenericParams, HasName,
17+
make,
18+
syntax_factory::SyntaxFactory,
19+
HasArgList, HasGenericParams, HasName,
1820
},
1921
hacks::parse_expr_from_str,
2022
ted, AstNode, Direction, SyntaxKind, SyntaxNode, TextSize, ToSmolStr, T,
@@ -75,32 +77,32 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
7577
let mut ret_ty = callable.return_type();
7678
let mut closure_mentioned_generic_params = ret_ty.generic_params(ctx.db());
7779

78-
let mut params = callable
79-
.params()
80-
.into_iter()
81-
.map(|param| {
82-
let node = ctx.sema.source(param.clone())?.value.right()?;
83-
let param_ty = param.ty();
84-
closure_mentioned_generic_params.extend(param_ty.generic_params(ctx.db()));
85-
match node.ty() {
86-
Some(_) => Some(node),
87-
None => {
88-
let ty = param_ty
89-
.display_source_code(ctx.db(), module.into(), true)
90-
.unwrap_or_else(|_| "_".to_owned());
91-
Some(make::param(node.pat()?, make::ty(&ty)))
92-
}
80+
let make = SyntaxFactory::new();
81+
82+
let mut params = Vec::new();
83+
for param in callable.params().into_iter() {
84+
let node = ctx.sema.source(param.clone())?.value.right()?;
85+
let param_ty = param.ty();
86+
closure_mentioned_generic_params.extend(param_ty.generic_params(ctx.db()));
87+
let param = match node.ty() {
88+
Some(_) => node.clone_subtree().clone_for_update(),
89+
None => {
90+
let ty = param_ty
91+
.display_source_code(ctx.db(), module.into(), true)
92+
.unwrap_or_else(|_| "_".to_owned());
93+
make.param(node.pat()?, make.ty(&ty))
9394
}
94-
})
95-
.collect::<Option<Vec<_>>>()?;
95+
};
96+
params.push(param);
97+
}
9698

9799
let mut body = closure.body()?.clone_for_update();
98100
let mut is_gen = false;
99101
let mut is_async = closure.async_token().is_some();
100102
if is_async {
101103
ret_ty = ret_ty.future_output(ctx.db())?;
102104
}
103-
// We defer the wrapping of the body in the block, because `make::block()` will generate a new node,
105+
// We defer the wrapping of the body in the block, because `make.block()` will generate a new node,
104106
// but we need to locate `AstPtr`s inside the body.
105107
let mut wrap_body_in_block = true;
106108
if let ast::Expr::BlockExpr(block) = &body {
@@ -150,10 +152,12 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
150152
"Convert closure to fn",
151153
closure.param_list()?.syntax().text_range(),
152154
|builder| {
153-
let closure_name_or_default = closure_name
154-
.as_ref()
155-
.map(|(_, _, it)| it.clone())
156-
.unwrap_or_else(|| make::name("fun_name"));
155+
let closure_name_or_default =
156+
if let Some(name) = closure_name.as_ref().map(|(_, _, it)| it.clone()) {
157+
name.clone_subtree().clone_for_update()
158+
} else {
159+
make.name("fun_name")
160+
};
157161
let captures = closure_ty.captured_items(ctx.db());
158162
let capture_tys = closure_ty.capture_types(ctx.db());
159163

@@ -168,19 +172,19 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
168172
// FIXME: Allow configuring the replacement of `self`.
169173
let capture_name =
170174
if capture.local().is_self(ctx.db()) && !capture.has_field_projections() {
171-
make::name("this")
175+
make.name("this")
172176
} else {
173-
make::name(&capture.place_to_name(ctx.db()))
177+
make.name(&capture.place_to_name(ctx.db()))
174178
};
175179

176180
closure_mentioned_generic_params.extend(capture_ty.generic_params(ctx.db()));
177181

178182
let capture_ty = capture_ty
179183
.display_source_code(ctx.db(), module.into(), true)
180184
.unwrap_or_else(|_| "_".to_owned());
181-
params.push(make::param(
182-
ast::Pat::IdentPat(make::ident_pat(false, false, capture_name.clone_subtree())),
183-
make::ty(&capture_ty),
185+
params.push(make.param(
186+
ast::Pat::IdentPat(make.ident_pat(false, false, capture_name.clone_subtree())),
187+
make.ty(&capture_ty),
184188
));
185189

186190
for capture_usage in capture.usages().sources(ctx.db()) {
@@ -199,16 +203,16 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
199203
}
200204
};
201205
let replacement = wrap_capture_in_deref_if_needed(
206+
&make,
202207
&expr,
203208
&capture_name,
204209
capture.kind(),
205210
capture_usage.is_ref(),
206-
)
207-
.clone_for_update();
211+
);
208212
capture_usages_replacement_map.push((expr, replacement));
209213
}
210214

211-
captures_as_args.push(capture_as_arg(ctx, capture));
215+
captures_as_args.push(capture_as_arg(ctx, &make, capture));
212216
}
213217

214218
let (closure_type_params, closure_where_clause) =
@@ -223,7 +227,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
223227
}
224228

225229
let body = if wrap_body_in_block {
226-
make::block_expr([], Some(body))
230+
make.block_expr([], Some(body))
227231
} else {
228232
ast::BlockExpr::cast(body.syntax().clone()).unwrap()
229233
};
@@ -237,7 +241,7 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>)
237241
.unwrap_or_else(|_| "_".to_owned());
238242
Some(make::ret_type(make::ty(&ret_ty)))
239243
};
240-
let mut fn_ = make::fn_(
244+
let mut fn_ = make.fn_(
241245
None,
242246
closure_name_or_default.clone(),
243247
closure_type_params,
@@ -466,6 +470,7 @@ fn compute_closure_type_params(
466470
}
467471

468472
fn wrap_capture_in_deref_if_needed(
473+
make: &SyntaxFactory,
469474
expr: &ast::Expr,
470475
capture_name: &ast::Name,
471476
capture_kind: CaptureKind,
@@ -483,7 +488,7 @@ fn wrap_capture_in_deref_if_needed(
483488
expr
484489
}
485490

486-
let capture_name = make::expr_path(make::path_from_text(&capture_name.text()));
491+
let capture_name = make.expr_path(make::path_from_text(&capture_name.text()));
487492
if capture_kind == CaptureKind::Move || is_ref {
488493
return capture_name;
489494
}
@@ -505,13 +510,18 @@ fn wrap_capture_in_deref_if_needed(
505510
if does_autoderef {
506511
return capture_name;
507512
}
508-
make::expr_prefix(T![*], capture_name).into()
513+
make.expr_prefix(T![*], capture_name).into()
509514
}
510515

511-
fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr {
516+
fn capture_as_arg(
517+
ctx: &AssistContext<'_>,
518+
make: &SyntaxFactory,
519+
capture: &ClosureCapture,
520+
) -> ast::Expr {
512521
let place =
513522
parse_expr_from_str(&capture.display_place_source_code(ctx.db()), ctx.file_id().edition())
514-
.expect("`display_place_source_code()` produced an invalid expr");
523+
.expect("`display_place_source_code()` produced an invalid expr")
524+
.clone_subtree();
515525
let needs_mut = match capture.kind() {
516526
CaptureKind::SharedRef => false,
517527
CaptureKind::MutableRef | CaptureKind::UniqueSharedRef => true,
@@ -522,7 +532,7 @@ fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Exp
522532
return expr.expr().expect("`display_place_source_code()` produced an invalid expr");
523533
}
524534
}
525-
make::expr_ref(place, needs_mut)
535+
make.expr_ref(place, needs_mut)
526536
}
527537

528538
fn handle_calls(

0 commit comments

Comments
 (0)