Skip to content

Commit f06f1b8

Browse files
committed
Migrate some leftovers in add_missing_match_arms
1 parent e2c281a commit f06f1b8

File tree

3 files changed

+196
-25
lines changed

3 files changed

+196
-25
lines changed

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

+39-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::iter::{self, Peekable};
2+
use std::ops::Deref;
3+
use std::rc::Rc;
24

35
use either::Either;
46
use hir::{sym, Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics};
@@ -76,6 +78,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
7678

7779
let cfg = ctx.config.import_path_config();
7880

81+
// As `make` is borrowed by the closure that builds `missing_pats`, this is needed
82+
// to satisfy the borrow checker.
83+
let make = Rc::new(SyntaxFactory::new());
84+
let make_weak = Rc::downgrade(&make);
85+
7986
let module = ctx.sema.scope(expr.syntax())?.module();
8087
let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
8188
Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
@@ -92,8 +99,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
9299
let missing_pats = variants
93100
.into_iter()
94101
.filter_map(|variant| {
102+
let make = make_weak.upgrade()?;
95103
Some((
96-
build_pat(ctx, module, variant, cfg)?,
104+
build_pat(ctx, make, module, variant, cfg)?,
97105
variant.should_be_hidden(ctx.db(), module.krate()),
98106
))
99107
})
@@ -140,14 +148,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
140148
.into_iter()
141149
.multi_cartesian_product()
142150
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
143-
.map(|variants| {
151+
.filter_map(|variants| {
144152
let is_hidden = variants
145153
.iter()
146154
.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));
155+
let patterns = variants.into_iter().filter_map(|variant| {
156+
make_weak.upgrade().and_then(|make| build_pat(ctx, make, module, variant, cfg))
157+
});
149158

150-
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
159+
make_weak
160+
.upgrade()
161+
.map(|make| (ast::Pat::from(make.tuple_pat(patterns)), is_hidden))
151162
})
152163
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
153164
(
@@ -172,13 +183,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
172183
.into_iter()
173184
.multi_cartesian_product()
174185
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
175-
.map(|variants| {
186+
.filter_map(|variants| {
176187
let is_hidden = variants
177188
.iter()
178189
.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)
190+
let patterns = variants.into_iter().filter_map(|variant| {
191+
make_weak.upgrade().and_then(|make| build_pat(ctx, make, module, variant, cfg))
192+
});
193+
194+
make_weak
195+
.upgrade()
196+
.map(|make| (ast::Pat::from(make.slice_pat(patterns)), is_hidden))
182197
})
183198
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
184199
(
@@ -203,8 +218,6 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
203218
"Fill match arms",
204219
ctx.sema.original_range(match_expr.syntax()).range,
205220
|builder| {
206-
let make = SyntaxFactory::new();
207-
208221
// having any hidden variants means that we need a catch-all arm
209222
needs_catch_all_arm |= has_hidden_variants;
210223

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

244257
if needs_catch_all_arm && !has_catch_all_arm {
245258
cov_mark::hit!(added_wildcard_pattern);
246-
let arm = make.match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo());
259+
let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo());
247260
arms.push(arm);
248261
}
249262

@@ -290,7 +303,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
290303
}
291304
}
292305

293-
editor.add_mappings(make.finish_with_mappings());
306+
editor.add_mappings(Rc::into_inner(make).unwrap().finish_with_mappings());
294307
builder.add_file_edits(ctx.file_id(), editor);
295308
},
296309
)
@@ -445,6 +458,7 @@ fn resolve_array_of_enum_def(
445458

446459
fn build_pat(
447460
ctx: &AssistContext<'_>,
461+
make: impl Deref<Target = SyntaxFactory>,
448462
module: hir::Module,
449463
var: ExtendedVariant,
450464
cfg: ImportPathConfig,
@@ -455,31 +469,32 @@ fn build_pat(
455469
let edition = module.krate().edition(db);
456470
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
457471
let fields = var.fields(db);
458-
let pat = match var.kind(db) {
472+
let pat: ast::Pat = match var.kind(db) {
459473
hir::StructKind::Tuple => {
460474
let mut name_generator = suggest_name::NameGenerator::new();
461475
let pats = fields.into_iter().map(|f| {
462476
let name = name_generator.for_type(&f.ty(db), db, edition);
463477
match name {
464-
Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(),
465-
None => make::wildcard_pat().into(),
478+
Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(),
479+
None => make.wildcard_pat().into(),
466480
}
467481
});
468-
make::tuple_struct_pat(path, pats).into()
482+
make.tuple_struct_pat(path, pats).into()
469483
}
470484
hir::StructKind::Record => {
471-
let pats = fields
485+
let fields = fields
472486
.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()
487+
.map(|f| make.name_ref(f.name(db).as_str()))
488+
.map(|name_ref| make.record_pat_field_shorthand(name_ref));
489+
let fields = make.record_pat_field_list(fields, None);
490+
make.record_pat_with_fields(path, fields).into()
476491
}
477-
hir::StructKind::Unit => make::path_pat(path),
492+
hir::StructKind::Unit => make.path_pat(path),
478493
};
479494
Some(pat)
480495
}
481-
ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
482-
ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
496+
ExtendedVariant::True => Some(ast::Pat::from(make.literal_pat("true"))),
497+
ExtendedVariant::False => Some(ast::Pat::from(make.literal_pat("false"))),
483498
}
484499
}
485500

crates/syntax/src/ast/make.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField
784784
ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
785785
}
786786

787-
/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
787+
/// Returns a `IdentPat` if the path has just one segment, a `PathPat` otherwise.
788788
pub fn path_pat(path: ast::Path) -> ast::Pat {
789789
return from_text(&path.to_string());
790790
fn from_text(text: &str) -> ast::Pat {

crates/syntax/src/ast/syntax_factory/constructors.rs

+156
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,32 @@ impl SyntaxFactory {
156156
make::literal_pat(text).clone_for_update()
157157
}
158158

159+
pub fn slice_pat(&self, pats: impl IntoIterator<Item = ast::Pat>) -> ast::SlicePat {
160+
let (pats, input) = iterator_input(pats);
161+
let ast = make::slice_pat(pats).clone_for_update();
162+
163+
if let Some(mut mapping) = self.mappings() {
164+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
165+
builder.map_children(input.into_iter(), ast.pats().map(|it| it.syntax().clone()));
166+
builder.finish(&mut mapping);
167+
}
168+
169+
ast
170+
}
171+
172+
pub fn tuple_pat(&self, pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
173+
let (pats, input) = iterator_input(pats);
174+
let ast = make::tuple_pat(pats).clone_for_update();
175+
176+
if let Some(mut mapping) = self.mappings() {
177+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
178+
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
179+
builder.finish(&mut mapping);
180+
}
181+
182+
ast
183+
}
184+
159185
pub fn tuple_struct_pat(
160186
&self,
161187
path: ast::Path,
@@ -174,6 +200,96 @@ impl SyntaxFactory {
174200
ast
175201
}
176202

203+
pub fn record_pat_with_fields(
204+
&self,
205+
path: ast::Path,
206+
fields: ast::RecordPatFieldList,
207+
) -> ast::RecordPat {
208+
let ast = make::record_pat_with_fields(path.clone(), fields.clone()).clone_for_update();
209+
210+
if let Some(mut mapping) = self.mappings() {
211+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
212+
builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
213+
builder.map_node(
214+
fields.syntax().clone(),
215+
ast.record_pat_field_list().unwrap().syntax().clone(),
216+
);
217+
builder.finish(&mut mapping);
218+
}
219+
220+
ast
221+
}
222+
223+
pub fn record_pat_field_list(
224+
&self,
225+
fields: impl IntoIterator<Item = ast::RecordPatField>,
226+
rest_pat: Option<ast::RestPat>,
227+
) -> ast::RecordPatFieldList {
228+
let (fields, input) = iterator_input(fields);
229+
let ast = make::record_pat_field_list(fields, rest_pat.clone()).clone_for_update();
230+
231+
if let Some(mut mapping) = self.mappings() {
232+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
233+
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
234+
if let Some(rest_pat) = rest_pat {
235+
builder
236+
.map_node(rest_pat.syntax().clone(), ast.rest_pat().unwrap().syntax().clone());
237+
}
238+
builder.finish(&mut mapping);
239+
}
240+
241+
ast
242+
}
243+
244+
pub fn record_pat_field(self, name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
245+
let ast = make::record_pat_field(name_ref.clone(), pat.clone()).clone_for_update();
246+
247+
if let Some(mut mapping) = self.mappings() {
248+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
249+
builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
250+
builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
251+
builder.finish(&mut mapping);
252+
}
253+
254+
ast
255+
}
256+
257+
pub fn record_pat_field_shorthand(&self, name_ref: ast::NameRef) -> ast::RecordPatField {
258+
let ast = make::record_pat_field_shorthand(name_ref.clone()).clone_for_update();
259+
260+
if let Some(mut mapping) = self.mappings() {
261+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
262+
builder.map_node(name_ref.syntax().clone(), ast.pat().unwrap().syntax().clone());
263+
builder.finish(&mut mapping);
264+
}
265+
266+
ast
267+
}
268+
269+
pub fn path_pat(&self, path: ast::Path) -> ast::Pat {
270+
let ast = make::path_pat(path.clone()).clone_for_update();
271+
272+
match &ast {
273+
ast::Pat::PathPat(ast) => {
274+
if let Some(mut mapping) = self.mappings() {
275+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
276+
builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
277+
builder.finish(&mut mapping)
278+
}
279+
}
280+
ast::Pat::IdentPat(ast) => {
281+
if let Some(mut mapping) = self.mappings() {
282+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
283+
builder.map_node(path.syntax().clone(), ast.name().unwrap().syntax().clone());
284+
builder.finish(&mut mapping)
285+
}
286+
}
287+
_ => unreachable!(),
288+
}
289+
290+
ast
291+
}
292+
177293
pub fn block_expr(
178294
&self,
179295
statements: impl IntoIterator<Item = ast::Stmt>,
@@ -214,6 +330,21 @@ impl SyntaxFactory {
214330
make::expr_empty_block().clone_for_update()
215331
}
216332

333+
pub fn expr_paren(&self, expr: ast::Expr) -> ast::ParenExpr {
334+
// FIXME: `make::expr_paren` should return a `MethodCallExpr`, not just an `Expr`
335+
let ast::Expr::ParenExpr(ast) = make::expr_paren(expr.clone()).clone_for_update() else {
336+
unreachable!()
337+
};
338+
339+
if let Some(mut mapping) = self.mappings() {
340+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
341+
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
342+
builder.finish(&mut mapping);
343+
}
344+
345+
ast
346+
}
347+
217348
pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
218349
let (fields, input) = iterator_input(fields);
219350
let ast = make::expr_tuple(fields).clone_for_update();
@@ -292,6 +423,31 @@ impl SyntaxFactory {
292423
ast
293424
}
294425

426+
pub fn expr_method_call(
427+
&self,
428+
receiver: ast::Expr,
429+
method: ast::NameRef,
430+
arg_list: ast::ArgList,
431+
) -> ast::MethodCallExpr {
432+
// FIXME: `make::expr_method_call` should return a `MethodCallExpr`, not just an `Expr`
433+
let ast::Expr::MethodCallExpr(ast) =
434+
make::expr_method_call(receiver.clone(), method.clone(), arg_list.clone())
435+
.clone_for_update()
436+
else {
437+
unreachable!()
438+
};
439+
440+
if let Some(mut mapping) = self.mappings() {
441+
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
442+
builder.map_node(receiver.syntax().clone(), ast.receiver().unwrap().syntax().clone());
443+
builder.map_node(method.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
444+
builder.map_node(arg_list.syntax().clone(), ast.arg_list().unwrap().syntax().clone());
445+
builder.finish(&mut mapping);
446+
}
447+
448+
ast
449+
}
450+
295451
pub fn arg_list(&self, args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
296452
let (args, input) = iterator_input(args);
297453
let ast = make::arg_list(args).clone_for_update();

0 commit comments

Comments
 (0)