diff options
Diffstat (limited to 'crates/ra_assists/src/assists')
-rw-r--r-- | crates/ra_assists/src/assists/fill_match_arms.rs | 67 |
1 files changed, 51 insertions, 16 deletions
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index b75bd44eb..99d80998c 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -46,19 +46,24 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | let expr = match_expr.expr()?; | 48 | let expr = match_expr.expr()?; |
49 | let enum_def = { | 49 | let (enum_def, module) = { |
50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); | 50 | let analyzer = ctx.source_analyzer(expr.syntax(), None); |
51 | resolve_enum_def(ctx.db, &analyzer, &expr)? | 51 | (resolve_enum_def(ctx.db, &analyzer, &expr)?, analyzer.module()?) |
52 | }; | 52 | }; |
53 | let variant_list = enum_def.variant_list()?; | 53 | let variants = enum_def.variants(ctx.db); |
54 | if variants.is_empty() { | ||
55 | return None; | ||
56 | } | ||
57 | |||
58 | let db = ctx.db; | ||
54 | 59 | ||
55 | ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { | 60 | ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| { |
56 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); | 61 | let indent_level = IndentLevel::from_node(match_arm_list.syntax()); |
57 | 62 | ||
58 | let new_arm_list = { | 63 | let new_arm_list = { |
59 | let variants = variant_list.variants(); | ||
60 | let arms = variants | 64 | let arms = variants |
61 | .filter_map(build_pat) | 65 | .into_iter() |
66 | .filter_map(|variant| build_pat(db, module, variant)) | ||
62 | .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())); | 67 | .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())); |
63 | indent_level.increase_indent(make::match_arm_list(arms)) | 68 | indent_level.increase_indent(make::match_arm_list(arms)) |
64 | }; | 69 | }; |
@@ -80,23 +85,25 @@ fn resolve_enum_def( | |||
80 | db: &impl HirDatabase, | 85 | db: &impl HirDatabase, |
81 | analyzer: &hir::SourceAnalyzer, | 86 | analyzer: &hir::SourceAnalyzer, |
82 | expr: &ast::Expr, | 87 | expr: &ast::Expr, |
83 | ) -> Option<ast::EnumDef> { | 88 | ) -> Option<hir::Enum> { |
84 | let expr_ty = analyzer.type_of(db, &expr)?; | 89 | let expr_ty = analyzer.type_of(db, &expr)?; |
85 | 90 | ||
86 | let res = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { | 91 | let result = expr_ty.autoderef(db).find_map(|ty| match ty.as_adt() { |
87 | Some(Adt::Enum(e)) => Some(e.source(db).value), | 92 | Some(Adt::Enum(e)) => Some(e), |
88 | _ => None, | 93 | _ => None, |
89 | }); | 94 | }); |
90 | res | 95 | result |
91 | } | 96 | } |
92 | 97 | ||
93 | fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { | 98 | fn build_pat( |
94 | let path = make::path_qualified( | 99 | db: &impl HirDatabase, |
95 | make::path_from_name_ref(make::name_ref(&var.parent_enum().name()?.syntax().to_string())), | 100 | module: hir::Module, |
96 | make::name_ref(&var.name()?.syntax().to_string()), | 101 | var: hir::EnumVariant, |
97 | ); | 102 | ) -> Option<ast::Pat> { |
103 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | ||
98 | 104 | ||
99 | let pat: ast::Pat = match var.kind() { | 105 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
106 | let pat: ast::Pat = match var.source(db).value.kind() { | ||
100 | ast::StructKind::Tuple(field_list) => { | 107 | ast::StructKind::Tuple(field_list) => { |
101 | let pats = | 108 | let pats = |
102 | iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); | 109 | iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); |
@@ -106,7 +113,7 @@ fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> { | |||
106 | let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); | 113 | let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); |
107 | make::record_pat(path, pats).into() | 114 | make::record_pat(path, pats).into() |
108 | } | 115 | } |
109 | ast::StructKind::Unit => make::path_pat(path).into(), | 116 | ast::StructKind::Unit => make::path_pat(path), |
110 | }; | 117 | }; |
111 | 118 | ||
112 | Some(pat) | 119 | Some(pat) |
@@ -252,4 +259,32 @@ mod tests { | |||
252 | "#, | 259 | "#, |
253 | ); | 260 | ); |
254 | } | 261 | } |
262 | |||
263 | #[test] | ||
264 | fn fill_match_arms_qualifies_path() { | ||
265 | check_assist( | ||
266 | fill_match_arms, | ||
267 | r#" | ||
268 | mod foo { pub enum E { X, Y } } | ||
269 | use foo::E::X; | ||
270 | |||
271 | fn main() { | ||
272 | match X { | ||
273 | <|> | ||
274 | } | ||
275 | } | ||
276 | "#, | ||
277 | r#" | ||
278 | mod foo { pub enum E { X, Y } } | ||
279 | use foo::E::X; | ||
280 | |||
281 | fn main() { | ||
282 | match <|>X { | ||
283 | X => (), | ||
284 | foo::E::Y => (), | ||
285 | } | ||
286 | } | ||
287 | "#, | ||
288 | ); | ||
289 | } | ||
255 | } | 290 | } |