feat: generate names for tuple-struct in add-missing-match-arms

This commit is contained in:
roife 2024-09-04 01:38:34 +08:00
parent 32d9597200
commit b304701b67

View File

@ -1,12 +1,13 @@
use std::iter::{self, Peekable}; use std::iter::{self, Peekable};
use either::Either; use either::Either;
use hir::{sym, Adt, Crate, HasAttrs, HasSource, ImportPathConfig, ModuleDef, Semantics}; use hir::{sym, Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics};
use ide_db::syntax_helpers::suggest_name;
use ide_db::RootDatabase; use ide_db::RootDatabase;
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
use itertools::Itertools; use itertools::Itertools;
use syntax::ast::edit_in_place::Removable; use syntax::ast::edit_in_place::Removable;
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; use syntax::ast::{self, make, AstNode, MatchArmList, MatchExpr, Pat};
use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
@ -90,7 +91,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
.into_iter() .into_iter()
.filter_map(|variant| { .filter_map(|variant| {
Some(( Some((
build_pat(ctx.db(), module, variant, cfg)?, build_pat(ctx, module, variant, cfg)?,
variant.should_be_hidden(ctx.db(), module.krate()), variant.should_be_hidden(ctx.db(), module.krate()),
)) ))
}) })
@ -141,9 +142,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
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 = variants let patterns =
.into_iter() variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
.filter_map(|variant| build_pat(ctx.db(), module, variant, cfg));
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden) (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
}) })
@ -174,9 +174,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
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 = variants let patterns =
.into_iter() variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
.filter_map(|variant| build_pat(ctx.db(), module, variant, cfg));
(ast::Pat::from(make::slice_pat(patterns)), is_hidden) (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));
@ -438,33 +437,39 @@ fn resolve_array_of_enum_def(
} }
fn build_pat( fn build_pat(
db: &RootDatabase, ctx: &AssistContext<'_>,
module: hir::Module, module: hir::Module,
var: ExtendedVariant, var: ExtendedVariant,
cfg: ImportPathConfig, cfg: ImportPathConfig,
) -> Option<ast::Pat> { ) -> Option<ast::Pat> {
let db = ctx.db();
match var { match var {
ExtendedVariant::Variant(var) => { ExtendedVariant::Variant(var) => {
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);
// FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though let fields = var.fields(db);
Some(match var.source(db)?.value.kind() { let pat = match var.kind(db) {
ast::StructKind::Tuple(field_list) => { hir::StructKind::Tuple => {
let pats = let mut name_generator = suggest_name::NameGenerator::new();
iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); let pats = fields.into_iter().map(|f| {
let name = name_generator.for_type(&f.ty(db), db, edition);
match name {
Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(),
None => make::wildcard_pat().into(),
}
});
make::tuple_struct_pat(path, pats).into() make::tuple_struct_pat(path, pats).into()
} }
ast::StructKind::Record(field_list) => { hir::StructKind::Record => {
let pats = field_list.fields().map(|f| { let pats = fields
make::ext::simple_ident_pat( .into_iter()
f.name().expect("Record field must have a name"), .map(|f| make::name(f.name(db).as_str()))
) .map(|name| make::ext::simple_ident_pat(name).into());
.into()
});
make::record_pat(path, pats).into() make::record_pat(path, pats).into()
} }
ast::StructKind::Unit => make::path_pat(path), hir::StructKind::Unit => make::path_pat(path),
}) };
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"))),
@ -1976,4 +1981,81 @@ fn a() {
}"#, }"#,
) )
} }
#[test]
fn suggest_name_for_tuple_struct_patterns() {
// single tuple struct
check_assist(
add_missing_match_arms,
r#"
struct S;
pub enum E {
A
B(S),
}
fn f() {
let value = E::A;
match value {
$0
}
}
"#,
r#"
struct S;
pub enum E {
A
B(S),
}
fn f() {
let value = E::A;
match value {
$0E::A => todo!(),
E::B(s) => todo!(),
}
}
"#,
);
// multiple tuple struct patterns
check_assist(
add_missing_match_arms,
r#"
struct S1;
struct S2;
pub enum E {
A
B(S1, S2),
}
fn f() {
let value = E::A;
match value {
$0
}
}
"#,
r#"
struct S1;
struct S2;
pub enum E {
A
B(S1, S2),
}
fn f() {
let value = E::A;
match value {
$0E::A => todo!(),
E::B(s1, s2) => todo!(),
}
}
"#,
);
}
} }