|
1 | 1 | use std::iter::{self, Peekable};
|
2 | 2 |
|
3 | 3 | 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; |
5 | 6 | use ide_db::RootDatabase;
|
6 | 7 | use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
|
7 | 8 | use itertools::Itertools;
|
8 | 9 | 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}; |
10 | 11 |
|
11 | 12 | use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
|
12 | 13 |
|
@@ -90,7 +91,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
90 | 91 | .into_iter()
|
91 | 92 | .filter_map(|variant| {
|
92 | 93 | Some((
|
93 |
| - build_pat(ctx.db(), module, variant, cfg)?, |
| 94 | + build_pat(ctx, module, variant, cfg)?, |
94 | 95 | variant.should_be_hidden(ctx.db(), module.krate()),
|
95 | 96 | ))
|
96 | 97 | })
|
@@ -141,9 +142,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
141 | 142 | let is_hidden = variants
|
142 | 143 | .iter()
|
143 | 144 | .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)); |
147 | 147 |
|
148 | 148 | (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
|
149 | 149 | })
|
@@ -174,9 +174,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
174 | 174 | let is_hidden = variants
|
175 | 175 | .iter()
|
176 | 176 | .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)); |
180 | 179 | (ast::Pat::from(make::slice_pat(patterns)), is_hidden)
|
181 | 180 | })
|
182 | 181 | .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
|
@@ -438,33 +437,39 @@ fn resolve_array_of_enum_def(
|
438 | 437 | }
|
439 | 438 |
|
440 | 439 | fn build_pat(
|
441 |
| - db: &RootDatabase, |
| 440 | + ctx: &AssistContext<'_>, |
442 | 441 | module: hir::Module,
|
443 | 442 | var: ExtendedVariant,
|
444 | 443 | cfg: ImportPathConfig,
|
445 | 444 | ) -> Option<ast::Pat> {
|
| 445 | + let db = ctx.db(); |
446 | 446 | match var {
|
447 | 447 | ExtendedVariant::Variant(var) => {
|
448 | 448 | let edition = module.krate().edition(db);
|
449 | 449 | 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 | + }); |
455 | 461 | make::tuple_struct_pat(path, pats).into()
|
456 | 462 | }
|
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()); |
464 | 468 | make::record_pat(path, pats).into()
|
465 | 469 | }
|
466 |
| - ast::StructKind::Unit => make::path_pat(path), |
467 |
| - }) |
| 470 | + hir::StructKind::Unit => make::path_pat(path), |
| 471 | + }; |
| 472 | + Some(pat) |
468 | 473 | }
|
469 | 474 | ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
|
470 | 475 | ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
|
@@ -1976,4 +1981,81 @@ fn a() {
|
1976 | 1981 | }"#,
|
1977 | 1982 | )
|
1978 | 1983 | }
|
| 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 | + } |
1979 | 2061 | }
|
0 commit comments