diff options
Diffstat (limited to 'crates/ra_assists/src/fill_match_arms.rs')
-rw-r--r-- | crates/ra_assists/src/fill_match_arms.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/crates/ra_assists/src/fill_match_arms.rs b/crates/ra_assists/src/fill_match_arms.rs new file mode 100644 index 000000000..9aa37d94c --- /dev/null +++ b/crates/ra_assists/src/fill_match_arms.rs | |||
@@ -0,0 +1,145 @@ | |||
1 | use std::fmt::Write; | ||
2 | |||
3 | use hir::{ | ||
4 | AdtDef, Ty, FieldSource, source_binder, | ||
5 | db::HirDatabase, | ||
6 | }; | ||
7 | use ra_syntax::ast::{self, AstNode}; | ||
8 | |||
9 | use crate::{AssistCtx, Assist}; | ||
10 | |||
11 | pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
12 | let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?; | ||
13 | |||
14 | // We already have some match arms, so we don't provide any assists. | ||
15 | match match_expr.match_arm_list() { | ||
16 | Some(arm_list) if arm_list.arms().count() > 0 => { | ||
17 | return None; | ||
18 | } | ||
19 | _ => {} | ||
20 | } | ||
21 | |||
22 | let expr = match_expr.expr()?; | ||
23 | let function = | ||
24 | source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, expr.syntax())?; | ||
25 | let infer_result = function.infer(ctx.db); | ||
26 | let syntax_mapping = function.body_syntax_mapping(ctx.db); | ||
27 | let node_expr = syntax_mapping.node_expr(expr)?; | ||
28 | let match_expr_ty = infer_result[node_expr].clone(); | ||
29 | let enum_def = match match_expr_ty { | ||
30 | Ty::Adt { | ||
31 | def_id: AdtDef::Enum(e), | ||
32 | .. | ||
33 | } => e, | ||
34 | _ => return None, | ||
35 | }; | ||
36 | let enum_name = enum_def.name(ctx.db)?; | ||
37 | let db = ctx.db; | ||
38 | |||
39 | ctx.build("fill match arms", |edit| { | ||
40 | let mut buf = format!("match {} {{\n", expr.syntax().text().to_string()); | ||
41 | let variants = enum_def.variants(db); | ||
42 | for variant in variants { | ||
43 | let name = match variant.name(db) { | ||
44 | Some(it) => it, | ||
45 | None => continue, | ||
46 | }; | ||
47 | write!(&mut buf, " {}::{}", enum_name, name.to_string()).unwrap(); | ||
48 | |||
49 | let pat = variant | ||
50 | .fields(db) | ||
51 | .into_iter() | ||
52 | .map(|field| { | ||
53 | let name = field.name(db).to_string(); | ||
54 | let (_, source) = field.source(db); | ||
55 | match source { | ||
56 | FieldSource::Named(_) => name, | ||
57 | FieldSource::Pos(_) => "_".to_string(), | ||
58 | } | ||
59 | }) | ||
60 | .collect::<Vec<_>>(); | ||
61 | |||
62 | match pat.first().map(|s| s.as_str()) { | ||
63 | Some("_") => write!(&mut buf, "({})", pat.join(", ")).unwrap(), | ||
64 | Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).unwrap(), | ||
65 | None => (), | ||
66 | }; | ||
67 | |||
68 | buf.push_str(" => (),\n"); | ||
69 | } | ||
70 | buf.push_str("}"); | ||
71 | edit.set_cursor(expr.syntax().range().start()); | ||
72 | edit.replace_node_and_indent(match_expr.syntax(), buf); | ||
73 | }) | ||
74 | } | ||
75 | |||
76 | #[cfg(test)] | ||
77 | mod tests { | ||
78 | use crate::helpers::check_assist; | ||
79 | |||
80 | use super::fill_match_arms; | ||
81 | |||
82 | #[test] | ||
83 | fn fill_match_arms_empty_body() { | ||
84 | check_assist( | ||
85 | fill_match_arms, | ||
86 | r#" | ||
87 | enum A { | ||
88 | As, | ||
89 | Bs, | ||
90 | Cs(String), | ||
91 | Ds(String, String), | ||
92 | Es{x: usize, y: usize} | ||
93 | } | ||
94 | |||
95 | fn main() { | ||
96 | let a = A::As; | ||
97 | match a<|> {} | ||
98 | } | ||
99 | "#, | ||
100 | r#" | ||
101 | enum A { | ||
102 | As, | ||
103 | Bs, | ||
104 | Cs(String), | ||
105 | Ds(String, String), | ||
106 | Es{x: usize, y: usize} | ||
107 | } | ||
108 | |||
109 | fn main() { | ||
110 | let a = A::As; | ||
111 | match <|>a { | ||
112 | A::As => (), | ||
113 | A::Bs => (), | ||
114 | A::Cs(_) => (), | ||
115 | A::Ds(_, _) => (), | ||
116 | A::Es{x, y} => (), | ||
117 | } | ||
118 | } | ||
119 | "#, | ||
120 | ); | ||
121 | } | ||
122 | #[test] | ||
123 | fn fill_match_arms_no_body() { | ||
124 | check_assist( | ||
125 | fill_match_arms, | ||
126 | r#" | ||
127 | enum E { X, Y} | ||
128 | |||
129 | fn main() { | ||
130 | match E::X<|> | ||
131 | } | ||
132 | "#, | ||
133 | r#" | ||
134 | enum E { X, Y} | ||
135 | |||
136 | fn main() { | ||
137 | match <|>E::X { | ||
138 | E::X => (), | ||
139 | E::Y => (), | ||
140 | } | ||
141 | } | ||
142 | "#, | ||
143 | ); | ||
144 | } | ||
145 | } | ||