Skip to content

Commit a9dbd49

Browse files
authored
Merge pull request rust-lang#19171 from ShoyuVanilla/migrate-de-morgan-assist
internal: Migrate `apply_demorgan` to `SyntaxEditor`
2 parents 32e4049 + 1c2225b commit a9dbd49

File tree

10 files changed

+351
-75
lines changed

10 files changed

+351
-75
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs

+27-22
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
7676

7777
let cfg = ctx.config.import_path_config();
7878

79+
let make = SyntaxFactory::new();
80+
7981
let module = ctx.sema.scope(expr.syntax())?.module();
8082
let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
8183
Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
@@ -93,7 +95,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
9395
.into_iter()
9496
.filter_map(|variant| {
9597
Some((
96-
build_pat(ctx, module, variant, cfg)?,
98+
build_pat(ctx, &make, module, variant, cfg)?,
9799
variant.should_be_hidden(ctx.db(), module.krate()),
98100
))
99101
})
@@ -144,10 +146,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
144146
let is_hidden = variants
145147
.iter()
146148
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
147-
let patterns =
148-
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
149+
let patterns = variants
150+
.into_iter()
151+
.filter_map(|variant| build_pat(ctx, &make, module, variant, cfg));
149152

150-
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
153+
(ast::Pat::from(make.tuple_pat(patterns)), is_hidden)
151154
})
152155
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
153156
(
@@ -176,9 +179,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
176179
let is_hidden = variants
177180
.iter()
178181
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
179-
let patterns =
180-
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
181-
(ast::Pat::from(make::slice_pat(patterns)), is_hidden)
182+
let patterns = variants
183+
.into_iter()
184+
.filter_map(|variant| build_pat(ctx, &make, module, variant, cfg));
185+
186+
(ast::Pat::from(make.slice_pat(patterns)), is_hidden)
182187
})
183188
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
184189
(
@@ -203,8 +208,6 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
203208
"Fill match arms",
204209
ctx.sema.original_range(match_expr.syntax()).range,
205210
|builder| {
206-
let make = SyntaxFactory::new();
207-
208211
// having any hidden variants means that we need a catch-all arm
209212
needs_catch_all_arm |= has_hidden_variants;
210213

@@ -243,7 +246,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
243246

244247
if needs_catch_all_arm && !has_catch_all_arm {
245248
cov_mark::hit!(added_wildcard_pattern);
246-
let arm = make.match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo());
249+
let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo());
247250
arms.push(arm);
248251
}
249252

@@ -290,7 +293,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
290293
}
291294
}
292295

293-
editor.add_mappings(make.finish_with_mappings());
296+
editor.add_mappings(make.take());
294297
builder.add_file_edits(ctx.file_id(), editor);
295298
},
296299
)
@@ -445,6 +448,7 @@ fn resolve_array_of_enum_def(
445448

446449
fn build_pat(
447450
ctx: &AssistContext<'_>,
451+
make: &SyntaxFactory,
448452
module: hir::Module,
449453
var: ExtendedVariant,
450454
cfg: ImportPathConfig,
@@ -455,31 +459,32 @@ fn build_pat(
455459
let edition = module.krate().edition(db);
456460
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
457461
let fields = var.fields(db);
458-
let pat = match var.kind(db) {
462+
let pat: ast::Pat = match var.kind(db) {
459463
hir::StructKind::Tuple => {
460464
let mut name_generator = suggest_name::NameGenerator::new();
461465
let pats = fields.into_iter().map(|f| {
462466
let name = name_generator.for_type(&f.ty(db), db, edition);
463467
match name {
464-
Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(),
465-
None => make::wildcard_pat().into(),
468+
Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(),
469+
None => make.wildcard_pat().into(),
466470
}
467471
});
468-
make::tuple_struct_pat(path, pats).into()
472+
make.tuple_struct_pat(path, pats).into()
469473
}
470474
hir::StructKind::Record => {
471-
let pats = fields
475+
let fields = fields
472476
.into_iter()
473-
.map(|f| make::name(f.name(db).as_str()))
474-
.map(|name| make::ext::simple_ident_pat(name).into());
475-
make::record_pat(path, pats).into()
477+
.map(|f| make.name_ref(f.name(db).as_str()))
478+
.map(|name_ref| make.record_pat_field_shorthand(name_ref));
479+
let fields = make.record_pat_field_list(fields, None);
480+
make.record_pat_with_fields(path, fields).into()
476481
}
477-
hir::StructKind::Unit => make::path_pat(path),
482+
hir::StructKind::Unit => make.path_pat(path),
478483
};
479484
Some(pat)
480485
}
481-
ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
482-
ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
486+
ExtendedVariant::True => Some(ast::Pat::from(make.literal_pat("true"))),
487+
ExtendedVariant::False => Some(ast::Pat::from(make.literal_pat("false"))),
483488
}
484489
}
485490

src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs

+80-40
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use std::collections::VecDeque;
33
use ide_db::{
44
assists::GroupLabel,
55
famous_defs::FamousDefs,
6-
source_change::SourceChangeBuilder,
76
syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
87
};
98
use syntax::{
10-
ast::{self, make, AstNode, Expr::BinExpr, HasArgList},
11-
ted, SyntaxKind, T,
9+
ast::{self, syntax_factory::SyntaxFactory, AstNode, Expr::BinExpr, HasArgList},
10+
syntax_editor::{Position, SyntaxEditor},
11+
SyntaxKind, SyntaxNode, T,
1212
};
1313

1414
use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
@@ -58,9 +58,12 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
5858
_ => return None,
5959
};
6060

61-
let demorganed = bin_expr.clone_subtree().clone_for_update();
61+
let make = SyntaxFactory::new();
62+
63+
let demorganed = bin_expr.clone_subtree();
64+
let mut editor = SyntaxEditor::new(demorganed.syntax().clone());
65+
editor.replace(demorganed.op_token()?, make.token(inv_token));
6266

63-
ted::replace(demorganed.op_token()?, ast::make::token(inv_token));
6467
let mut exprs = VecDeque::from([
6568
(bin_expr.lhs()?, demorganed.lhs()?),
6669
(bin_expr.rhs()?, demorganed.rhs()?),
@@ -70,35 +73,39 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
7073
if let BinExpr(bin_expr) = &expr {
7174
if let BinExpr(cbin_expr) = &dm {
7275
if op == bin_expr.op_kind()? {
73-
ted::replace(cbin_expr.op_token()?, ast::make::token(inv_token));
76+
editor.replace(cbin_expr.op_token()?, make.token(inv_token));
7477
exprs.push_back((bin_expr.lhs()?, cbin_expr.lhs()?));
7578
exprs.push_back((bin_expr.rhs()?, cbin_expr.rhs()?));
7679
} else {
77-
let mut inv = invert_boolean_expression(expr);
78-
if inv.needs_parens_in(dm.syntax().parent()?) {
79-
inv = ast::make::expr_paren(inv).clone_for_update();
80+
let mut inv = invert_boolean_expression(&make, expr);
81+
if needs_parens_in_place_of(&inv, &dm.syntax().parent()?, &dm) {
82+
inv = make.expr_paren(inv).into();
8083
}
81-
ted::replace(dm.syntax(), inv.syntax());
84+
editor.replace(dm.syntax(), inv.syntax());
8285
}
8386
} else {
8487
return None;
8588
}
8689
} else {
87-
let mut inv = invert_boolean_expression(dm.clone_subtree()).clone_for_update();
88-
if inv.needs_parens_in(dm.syntax().parent()?) {
89-
inv = ast::make::expr_paren(inv).clone_for_update();
90+
let mut inv = invert_boolean_expression(&make, dm.clone());
91+
if needs_parens_in_place_of(&inv, &dm.syntax().parent()?, &dm) {
92+
inv = make.expr_paren(inv).into();
9093
}
91-
ted::replace(dm.syntax(), inv.syntax());
94+
editor.replace(dm.syntax(), inv.syntax());
9295
}
9396
}
9497

98+
editor.add_mappings(make.finish_with_mappings());
99+
let edit = editor.finish();
100+
let demorganed = ast::Expr::cast(edit.new_root().clone())?;
101+
95102
acc.add_group(
96103
&GroupLabel("Apply De Morgan's law".to_owned()),
97104
AssistId("apply_demorgan", AssistKind::RefactorRewrite),
98105
"Apply De Morgan's law",
99106
op_range,
100-
|edit| {
101-
let demorganed = ast::Expr::BinExpr(demorganed);
107+
|builder| {
108+
let make = SyntaxFactory::new();
102109
let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast);
103110
let neg_expr = paren_expr
104111
.clone()
@@ -107,24 +114,32 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
107114
.filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not)))
108115
.map(ast::Expr::PrefixExpr);
109116

117+
let mut editor;
110118
if let Some(paren_expr) = paren_expr {
111119
if let Some(neg_expr) = neg_expr {
112120
cov_mark::hit!(demorgan_double_negation);
113121
let parent = neg_expr.syntax().parent();
122+
editor = builder.make_editor(neg_expr.syntax());
114123

115124
if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)) {
116125
cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
117-
edit.replace_ast(neg_expr, make::expr_paren(demorganed));
126+
editor.replace(neg_expr.syntax(), make.expr_paren(demorganed).syntax());
118127
} else {
119-
edit.replace_ast(neg_expr, demorganed);
128+
editor.replace(neg_expr.syntax(), demorganed.syntax());
120129
};
121130
} else {
122131
cov_mark::hit!(demorgan_double_parens);
123-
edit.replace_ast(paren_expr.into(), add_bang_paren(demorganed));
132+
editor = builder.make_editor(paren_expr.syntax());
133+
134+
editor.replace(paren_expr.syntax(), add_bang_paren(&make, demorganed).syntax());
124135
}
125136
} else {
126-
edit.replace_ast(bin_expr.into(), add_bang_paren(demorganed));
137+
editor = builder.make_editor(bin_expr.syntax());
138+
editor.replace(bin_expr.syntax(), add_bang_paren(&make, demorganed).syntax());
127139
}
140+
141+
editor.add_mappings(make.finish_with_mappings());
142+
builder.add_file_edits(ctx.file_id(), editor);
128143
},
129144
)
130145
}
@@ -161,7 +176,7 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
161176
let (name, arg_expr) = validate_method_call_expr(ctx, &method_call)?;
162177

163178
let ast::Expr::ClosureExpr(closure_expr) = arg_expr else { return None };
164-
let closure_body = closure_expr.body()?;
179+
let closure_body = closure_expr.body()?.clone_for_update();
165180

166181
let op_range = method_call.syntax().text_range();
167182
let label = format!("Apply De Morgan's law to `Iterator::{}`", name.text().as_str());
@@ -170,18 +185,19 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
170185
AssistId("apply_demorgan_iterator", AssistKind::RefactorRewrite),
171186
label,
172187
op_range,
173-
|edit| {
188+
|builder| {
189+
let make = SyntaxFactory::new();
190+
let mut editor = builder.make_editor(method_call.syntax());
174191
// replace the method name
175192
let new_name = match name.text().as_str() {
176-
"all" => make::name_ref("any"),
177-
"any" => make::name_ref("all"),
193+
"all" => make.name_ref("any"),
194+
"any" => make.name_ref("all"),
178195
_ => unreachable!(),
179-
}
180-
.clone_for_update();
181-
edit.replace_ast(name, new_name);
196+
};
197+
editor.replace(name.syntax(), new_name.syntax());
182198

183199
// negate all tail expressions in the closure body
184-
let tail_cb = &mut |e: &_| tail_cb_impl(edit, e);
200+
let tail_cb = &mut |e: &_| tail_cb_impl(&mut editor, &make, e);
185201
walk_expr(&closure_body, &mut |expr| {
186202
if let ast::Expr::ReturnExpr(ret_expr) = expr {
187203
if let Some(ret_expr_arg) = &ret_expr.expr() {
@@ -198,15 +214,15 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
198214
.and_then(ast::PrefixExpr::cast)
199215
.filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not)))
200216
{
201-
edit.delete(
202-
prefix_expr
203-
.op_token()
204-
.expect("prefix expression always has an operator")
205-
.text_range(),
217+
editor.delete(
218+
prefix_expr.op_token().expect("prefix expression always has an operator"),
206219
);
207220
} else {
208-
edit.insert(method_call.syntax().text_range().start(), "!");
221+
editor.insert(Position::before(method_call.syntax()), make.token(SyntaxKind::BANG));
209222
}
223+
224+
editor.add_mappings(make.finish_with_mappings());
225+
builder.add_file_edits(ctx.file_id(), editor);
210226
},
211227
)
212228
}
@@ -233,26 +249,50 @@ fn validate_method_call_expr(
233249
it_type.impls_trait(sema.db, iter_trait, &[]).then_some((name_ref, arg_expr))
234250
}
235251

236-
fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
252+
fn tail_cb_impl(editor: &mut SyntaxEditor, make: &SyntaxFactory, e: &ast::Expr) {
237253
match e {
238254
ast::Expr::BreakExpr(break_expr) => {
239255
if let Some(break_expr_arg) = break_expr.expr() {
240-
for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(edit, e))
256+
for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(editor, make, e))
241257
}
242258
}
243259
ast::Expr::ReturnExpr(_) => {
244260
// all return expressions have already been handled by the walk loop
245261
}
246262
e => {
247-
let inverted_body = invert_boolean_expression(e.clone());
248-
edit.replace(e.syntax().text_range(), inverted_body.syntax().text());
263+
let inverted_body = invert_boolean_expression(make, e.clone());
264+
editor.replace(e.syntax(), inverted_body.syntax());
249265
}
250266
}
251267
}
252268

253269
/// Add bang and parentheses to the expression.
254-
fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
255-
make::expr_prefix(T![!], make::expr_paren(expr)).into()
270+
fn add_bang_paren(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr {
271+
make.expr_prefix(T![!], make.expr_paren(expr).into()).into()
272+
}
273+
274+
fn needs_parens_in_place_of(
275+
this: &ast::Expr,
276+
parent: &SyntaxNode,
277+
in_place_of: &ast::Expr,
278+
) -> bool {
279+
assert_eq!(Some(parent), in_place_of.syntax().parent().as_ref());
280+
281+
let child_idx = parent
282+
.children()
283+
.enumerate()
284+
.find_map(|(i, it)| if &it == in_place_of.syntax() { Some(i) } else { None })
285+
.unwrap();
286+
let parent = parent.clone_subtree();
287+
let subtree_place = parent.children().nth(child_idx).unwrap();
288+
289+
let mut editor = SyntaxEditor::new(parent);
290+
editor.replace(subtree_place, this.syntax());
291+
let edit = editor.finish();
292+
293+
let replaced = edit.new_root().children().nth(child_idx).unwrap();
294+
let replaced = ast::Expr::cast(replaced).unwrap();
295+
replaced.needs_parens_in(edit.new_root().clone())
256296
}
257297

258298
#[cfg(test)]

src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use syntax::{
1313
};
1414

1515
use crate::{
16-
utils::{invert_boolean_expression, unwrap_trivial_block},
16+
utils::{invert_boolean_expression_legacy, unwrap_trivial_block},
1717
AssistContext, AssistId, AssistKind, Assists,
1818
};
1919

@@ -119,7 +119,7 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_>
119119
| ast::Expr::WhileExpr(_)
120120
| ast::Expr::YieldExpr(_)
121121
);
122-
let cond = if invert_cond { invert_boolean_expression(cond) } else { cond };
122+
let cond = if invert_cond { invert_boolean_expression_legacy(cond) } else { cond };
123123
let cond = if parenthesize { make::expr_paren(cond) } else { cond };
124124
let arg_list = make::arg_list(Some(make::expr_closure(None, closure_body)));
125125
let mcall = make::expr_method_call(cond, make::name_ref("then"), arg_list);

src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use syntax::{
1717

1818
use crate::{
1919
assist_context::{AssistContext, Assists},
20-
utils::invert_boolean_expression,
20+
utils::invert_boolean_expression_legacy,
2121
AssistId, AssistKind,
2222
};
2323

@@ -139,7 +139,7 @@ fn if_expr_to_guarded_return(
139139
let new_expr = {
140140
let then_branch =
141141
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
142-
let cond = invert_boolean_expression(cond_expr);
142+
let cond = invert_boolean_expression_legacy(cond_expr);
143143
make::expr_if(cond, then_branch, None).indent(if_indent_level)
144144
};
145145
new_expr.syntax().clone_for_update()

0 commit comments

Comments
 (0)