mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-25 09:27:43 +00:00
Migrate some leftovers in add_missing_match_arms
This commit is contained in:
parent
e2c281aaae
commit
f06f1b81bb
3 changed files with 196 additions and 25 deletions
|
|
@ -1,4 +1,6 @@
|
||||||
use std::iter::{self, Peekable};
|
use std::iter::{self, Peekable};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{sym, Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics};
|
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<'_>)
|
||||||
|
|
||||||
let cfg = ctx.config.import_path_config();
|
let cfg = ctx.config.import_path_config();
|
||||||
|
|
||||||
|
// As `make` is borrowed by the closure that builds `missing_pats`, this is needed
|
||||||
|
// to satisfy the borrow checker.
|
||||||
|
let make = Rc::new(SyntaxFactory::new());
|
||||||
|
let make_weak = Rc::downgrade(&make);
|
||||||
|
|
||||||
let module = ctx.sema.scope(expr.syntax())?.module();
|
let module = ctx.sema.scope(expr.syntax())?.module();
|
||||||
let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
|
let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
|
||||||
Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
|
Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
|
||||||
|
|
@ -92,8 +99,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
let missing_pats = variants
|
let missing_pats = variants
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|variant| {
|
||||||
|
let make = make_weak.upgrade()?;
|
||||||
Some((
|
Some((
|
||||||
build_pat(ctx, module, variant, cfg)?,
|
build_pat(ctx, make, module, variant, cfg)?,
|
||||||
variant.should_be_hidden(ctx.db(), module.krate()),
|
variant.should_be_hidden(ctx.db(), module.krate()),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
@ -140,14 +148,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.multi_cartesian_product()
|
.multi_cartesian_product()
|
||||||
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
|
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
|
||||||
.map(|variants| {
|
.filter_map(|variants| {
|
||||||
let is_hidden = variants
|
let is_hidden = variants
|
||||||
.iter()
|
.iter()
|
||||||
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
|
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
|
||||||
let patterns =
|
let patterns = variants.into_iter().filter_map(|variant| {
|
||||||
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
|
make_weak.upgrade().and_then(|make| build_pat(ctx, make, module, variant, cfg))
|
||||||
|
});
|
||||||
|
|
||||||
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
|
make_weak
|
||||||
|
.upgrade()
|
||||||
|
.map(|make| (ast::Pat::from(make.tuple_pat(patterns)), is_hidden))
|
||||||
})
|
})
|
||||||
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
|
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
|
||||||
(
|
(
|
||||||
|
|
@ -172,13 +183,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.multi_cartesian_product()
|
.multi_cartesian_product()
|
||||||
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
|
.inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
|
||||||
.map(|variants| {
|
.filter_map(|variants| {
|
||||||
let is_hidden = variants
|
let is_hidden = variants
|
||||||
.iter()
|
.iter()
|
||||||
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
|
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
|
||||||
let patterns =
|
let patterns = variants.into_iter().filter_map(|variant| {
|
||||||
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
|
make_weak.upgrade().and_then(|make| build_pat(ctx, make, module, variant, cfg))
|
||||||
(ast::Pat::from(make::slice_pat(patterns)), is_hidden)
|
});
|
||||||
|
|
||||||
|
make_weak
|
||||||
|
.upgrade()
|
||||||
|
.map(|make| (ast::Pat::from(make.slice_pat(patterns)), is_hidden))
|
||||||
})
|
})
|
||||||
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
|
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
|
||||||
(
|
(
|
||||||
|
|
@ -203,8 +218,6 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
"Fill match arms",
|
"Fill match arms",
|
||||||
ctx.sema.original_range(match_expr.syntax()).range,
|
ctx.sema.original_range(match_expr.syntax()).range,
|
||||||
|builder| {
|
|builder| {
|
||||||
let make = SyntaxFactory::new();
|
|
||||||
|
|
||||||
// having any hidden variants means that we need a catch-all arm
|
// having any hidden variants means that we need a catch-all arm
|
||||||
needs_catch_all_arm |= has_hidden_variants;
|
needs_catch_all_arm |= has_hidden_variants;
|
||||||
|
|
||||||
|
|
@ -243,7 +256,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
|
|
||||||
if needs_catch_all_arm && !has_catch_all_arm {
|
if needs_catch_all_arm && !has_catch_all_arm {
|
||||||
cov_mark::hit!(added_wildcard_pattern);
|
cov_mark::hit!(added_wildcard_pattern);
|
||||||
let arm = make.match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo());
|
let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo());
|
||||||
arms.push(arm);
|
arms.push(arm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,7 +303,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.add_mappings(make.finish_with_mappings());
|
editor.add_mappings(Rc::into_inner(make).unwrap().finish_with_mappings());
|
||||||
builder.add_file_edits(ctx.file_id(), editor);
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -445,6 +458,7 @@ fn resolve_array_of_enum_def(
|
||||||
|
|
||||||
fn build_pat(
|
fn build_pat(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
|
make: impl Deref<Target = SyntaxFactory>,
|
||||||
module: hir::Module,
|
module: hir::Module,
|
||||||
var: ExtendedVariant,
|
var: ExtendedVariant,
|
||||||
cfg: ImportPathConfig,
|
cfg: ImportPathConfig,
|
||||||
|
|
@ -455,31 +469,32 @@ fn build_pat(
|
||||||
let edition = module.krate().edition(db);
|
let edition = module.krate().edition(db);
|
||||||
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
|
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
|
||||||
let fields = var.fields(db);
|
let fields = var.fields(db);
|
||||||
let pat = match var.kind(db) {
|
let pat: ast::Pat = match var.kind(db) {
|
||||||
hir::StructKind::Tuple => {
|
hir::StructKind::Tuple => {
|
||||||
let mut name_generator = suggest_name::NameGenerator::new();
|
let mut name_generator = suggest_name::NameGenerator::new();
|
||||||
let pats = fields.into_iter().map(|f| {
|
let pats = fields.into_iter().map(|f| {
|
||||||
let name = name_generator.for_type(&f.ty(db), db, edition);
|
let name = name_generator.for_type(&f.ty(db), db, edition);
|
||||||
match name {
|
match name {
|
||||||
Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(),
|
Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(),
|
||||||
None => make::wildcard_pat().into(),
|
None => make.wildcard_pat().into(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
make::tuple_struct_pat(path, pats).into()
|
make.tuple_struct_pat(path, pats).into()
|
||||||
}
|
}
|
||||||
hir::StructKind::Record => {
|
hir::StructKind::Record => {
|
||||||
let pats = fields
|
let fields = fields
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| make::name(f.name(db).as_str()))
|
.map(|f| make.name_ref(f.name(db).as_str()))
|
||||||
.map(|name| make::ext::simple_ident_pat(name).into());
|
.map(|name_ref| make.record_pat_field_shorthand(name_ref));
|
||||||
make::record_pat(path, pats).into()
|
let fields = make.record_pat_field_list(fields, None);
|
||||||
|
make.record_pat_with_fields(path, fields).into()
|
||||||
}
|
}
|
||||||
hir::StructKind::Unit => make::path_pat(path),
|
hir::StructKind::Unit => make.path_pat(path),
|
||||||
};
|
};
|
||||||
Some(pat)
|
Some(pat)
|
||||||
}
|
}
|
||||||
ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
|
ExtendedVariant::True => Some(ast::Pat::from(make.literal_pat("true"))),
|
||||||
ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
|
ExtendedVariant::False => Some(ast::Pat::from(make.literal_pat("false"))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -784,7 +784,7 @@ pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField
|
||||||
ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
|
ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
|
/// Returns a `IdentPat` if the path has just one segment, a `PathPat` otherwise.
|
||||||
pub fn path_pat(path: ast::Path) -> ast::Pat {
|
pub fn path_pat(path: ast::Path) -> ast::Pat {
|
||||||
return from_text(&path.to_string());
|
return from_text(&path.to_string());
|
||||||
fn from_text(text: &str) -> ast::Pat {
|
fn from_text(text: &str) -> ast::Pat {
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,32 @@ impl SyntaxFactory {
|
||||||
make::literal_pat(text).clone_for_update()
|
make::literal_pat(text).clone_for_update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn slice_pat(&self, pats: impl IntoIterator<Item = ast::Pat>) -> ast::SlicePat {
|
||||||
|
let (pats, input) = iterator_input(pats);
|
||||||
|
let ast = make::slice_pat(pats).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.pats().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tuple_pat(&self, pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
|
||||||
|
let (pats, input) = iterator_input(pats);
|
||||||
|
let ast = make::tuple_pat(pats).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tuple_struct_pat(
|
pub fn tuple_struct_pat(
|
||||||
&self,
|
&self,
|
||||||
path: ast::Path,
|
path: ast::Path,
|
||||||
|
|
@ -174,6 +200,96 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn record_pat_with_fields(
|
||||||
|
&self,
|
||||||
|
path: ast::Path,
|
||||||
|
fields: ast::RecordPatFieldList,
|
||||||
|
) -> ast::RecordPat {
|
||||||
|
let ast = make::record_pat_with_fields(path.clone(), fields.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
|
||||||
|
builder.map_node(
|
||||||
|
fields.syntax().clone(),
|
||||||
|
ast.record_pat_field_list().unwrap().syntax().clone(),
|
||||||
|
);
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record_pat_field_list(
|
||||||
|
&self,
|
||||||
|
fields: impl IntoIterator<Item = ast::RecordPatField>,
|
||||||
|
rest_pat: Option<ast::RestPat>,
|
||||||
|
) -> ast::RecordPatFieldList {
|
||||||
|
let (fields, input) = iterator_input(fields);
|
||||||
|
let ast = make::record_pat_field_list(fields, rest_pat.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
|
||||||
|
if let Some(rest_pat) = rest_pat {
|
||||||
|
builder
|
||||||
|
.map_node(rest_pat.syntax().clone(), ast.rest_pat().unwrap().syntax().clone());
|
||||||
|
}
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record_pat_field(self, name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
|
||||||
|
let ast = make::record_pat_field(name_ref.clone(), pat.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
|
||||||
|
builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record_pat_field_shorthand(&self, name_ref: ast::NameRef) -> ast::RecordPatField {
|
||||||
|
let ast = make::record_pat_field_shorthand(name_ref.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(name_ref.syntax().clone(), ast.pat().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_pat(&self, path: ast::Path) -> ast::Pat {
|
||||||
|
let ast = make::path_pat(path.clone()).clone_for_update();
|
||||||
|
|
||||||
|
match &ast {
|
||||||
|
ast::Pat::PathPat(ast) => {
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Pat::IdentPat(ast) => {
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(path.syntax().clone(), ast.name().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn block_expr(
|
pub fn block_expr(
|
||||||
&self,
|
&self,
|
||||||
statements: impl IntoIterator<Item = ast::Stmt>,
|
statements: impl IntoIterator<Item = ast::Stmt>,
|
||||||
|
|
@ -214,6 +330,21 @@ impl SyntaxFactory {
|
||||||
make::expr_empty_block().clone_for_update()
|
make::expr_empty_block().clone_for_update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_paren(&self, expr: ast::Expr) -> ast::ParenExpr {
|
||||||
|
// FIXME: `make::expr_paren` should return a `MethodCallExpr`, not just an `Expr`
|
||||||
|
let ast::Expr::ParenExpr(ast) = make::expr_paren(expr.clone()).clone_for_update() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
|
pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
|
||||||
let (fields, input) = iterator_input(fields);
|
let (fields, input) = iterator_input(fields);
|
||||||
let ast = make::expr_tuple(fields).clone_for_update();
|
let ast = make::expr_tuple(fields).clone_for_update();
|
||||||
|
|
@ -292,6 +423,31 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_method_call(
|
||||||
|
&self,
|
||||||
|
receiver: ast::Expr,
|
||||||
|
method: ast::NameRef,
|
||||||
|
arg_list: ast::ArgList,
|
||||||
|
) -> ast::MethodCallExpr {
|
||||||
|
// FIXME: `make::expr_method_call` should return a `MethodCallExpr`, not just an `Expr`
|
||||||
|
let ast::Expr::MethodCallExpr(ast) =
|
||||||
|
make::expr_method_call(receiver.clone(), method.clone(), arg_list.clone())
|
||||||
|
.clone_for_update()
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(receiver.syntax().clone(), ast.receiver().unwrap().syntax().clone());
|
||||||
|
builder.map_node(method.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
|
||||||
|
builder.map_node(arg_list.syntax().clone(), ast.arg_list().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn arg_list(&self, args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
pub fn arg_list(&self, args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
||||||
let (args, input) = iterator_input(args);
|
let (args, input) = iterator_input(args);
|
||||||
let ast = make::arg_list(args).clone_for_update();
|
let ast = make::arg_list(args).clone_for_update();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue