Skip to content

Commit b304701

Browse files
committed
feat: generate names for tuple-struct in add-missing-match-arms
1 parent 32d9597 commit b304701

File tree

1 file changed

+106
-24
lines changed

1 file changed

+106
-24
lines changed

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

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::iter::{self, Peekable};
22

33
use either::Either;
4-
use hir::{sym, Adt, Crate, HasAttrs, HasSource, ImportPathConfig, ModuleDef, Semantics};
4+
use hir::{sym, Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics};
5+
use ide_db::syntax_helpers::suggest_name;
56
use ide_db::RootDatabase;
67
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
78
use itertools::Itertools;
89
use syntax::ast::edit_in_place::Removable;
9-
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
10+
use syntax::ast::{self, make, AstNode, MatchArmList, MatchExpr, Pat};
1011

1112
use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
1213

@@ -90,7 +91,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
9091
.into_iter()
9192
.filter_map(|variant| {
9293
Some((
93-
build_pat(ctx.db(), module, variant, cfg)?,
94+
build_pat(ctx, module, variant, cfg)?,
9495
variant.should_be_hidden(ctx.db(), module.krate()),
9596
))
9697
})
@@ -141,9 +142,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
141142
let is_hidden = variants
142143
.iter()
143144
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
144-
let patterns = variants
145-
.into_iter()
146-
.filter_map(|variant| build_pat(ctx.db(), module, variant, cfg));
145+
let patterns =
146+
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
147147

148148
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
149149
})
@@ -174,9 +174,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
174174
let is_hidden = variants
175175
.iter()
176176
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
177-
let patterns = variants
178-
.into_iter()
179-
.filter_map(|variant| build_pat(ctx.db(), module, variant, cfg));
177+
let patterns =
178+
variants.into_iter().filter_map(|variant| build_pat(ctx, module, variant, cfg));
180179
(ast::Pat::from(make::slice_pat(patterns)), is_hidden)
181180
})
182181
.filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
@@ -438,33 +437,39 @@ fn resolve_array_of_enum_def(
438437
}
439438

440439
fn build_pat(
441-
db: &RootDatabase,
440+
ctx: &AssistContext<'_>,
442441
module: hir::Module,
443442
var: ExtendedVariant,
444443
cfg: ImportPathConfig,
445444
) -> Option<ast::Pat> {
445+
let db = ctx.db();
446446
match var {
447447
ExtendedVariant::Variant(var) => {
448448
let edition = module.krate().edition(db);
449449
let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition);
450-
// FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
451-
Some(match var.source(db)?.value.kind() {
452-
ast::StructKind::Tuple(field_list) => {
453-
let pats =
454-
iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
450+
let fields = var.fields(db);
451+
let pat = match var.kind(db) {
452+
hir::StructKind::Tuple => {
453+
let mut name_generator = suggest_name::NameGenerator::new();
454+
let pats = fields.into_iter().map(|f| {
455+
let name = name_generator.for_type(&f.ty(db), db, edition);
456+
match name {
457+
Some(name) => make::ext::simple_ident_pat(make::name(&name)).into(),
458+
None => make::wildcard_pat().into(),
459+
}
460+
});
455461
make::tuple_struct_pat(path, pats).into()
456462
}
457-
ast::StructKind::Record(field_list) => {
458-
let pats = field_list.fields().map(|f| {
459-
make::ext::simple_ident_pat(
460-
f.name().expect("Record field must have a name"),
461-
)
462-
.into()
463-
});
463+
hir::StructKind::Record => {
464+
let pats = fields
465+
.into_iter()
466+
.map(|f| make::name(f.name(db).as_str()))
467+
.map(|name| make::ext::simple_ident_pat(name).into());
464468
make::record_pat(path, pats).into()
465469
}
466-
ast::StructKind::Unit => make::path_pat(path),
467-
})
470+
hir::StructKind::Unit => make::path_pat(path),
471+
};
472+
Some(pat)
468473
}
469474
ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
470475
ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
@@ -1976,4 +1981,81 @@ fn a() {
19761981
}"#,
19771982
)
19781983
}
1984+
1985+
#[test]
1986+
fn suggest_name_for_tuple_struct_patterns() {
1987+
// single tuple struct
1988+
check_assist(
1989+
add_missing_match_arms,
1990+
r#"
1991+
struct S;
1992+
1993+
pub enum E {
1994+
A
1995+
B(S),
1996+
}
1997+
1998+
fn f() {
1999+
let value = E::A;
2000+
match value {
2001+
$0
2002+
}
2003+
}
2004+
"#,
2005+
r#"
2006+
struct S;
2007+
2008+
pub enum E {
2009+
A
2010+
B(S),
2011+
}
2012+
2013+
fn f() {
2014+
let value = E::A;
2015+
match value {
2016+
$0E::A => todo!(),
2017+
E::B(s) => todo!(),
2018+
}
2019+
}
2020+
"#,
2021+
);
2022+
2023+
// multiple tuple struct patterns
2024+
check_assist(
2025+
add_missing_match_arms,
2026+
r#"
2027+
struct S1;
2028+
struct S2;
2029+
2030+
pub enum E {
2031+
A
2032+
B(S1, S2),
2033+
}
2034+
2035+
fn f() {
2036+
let value = E::A;
2037+
match value {
2038+
$0
2039+
}
2040+
}
2041+
"#,
2042+
r#"
2043+
struct S1;
2044+
struct S2;
2045+
2046+
pub enum E {
2047+
A
2048+
B(S1, S2),
2049+
}
2050+
2051+
fn f() {
2052+
let value = E::A;
2053+
match value {
2054+
$0E::A => todo!(),
2055+
E::B(s1, s2) => todo!(),
2056+
}
2057+
}
2058+
"#,
2059+
);
2060+
}
19792061
}

0 commit comments

Comments
 (0)