aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/fill_match_arms.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-02-03 18:26:35 +0000
committerAleksey Kladov <[email protected]>2019-02-06 14:00:00 +0000
commit0c5fd8f7cbf04eda763e55bc9a38dad5f7ec917d (patch)
tree4af15c8906b85de01a15c717bc1fac388952cd3d /crates/ra_assists/src/fill_match_arms.rs
parent736a55c97e69f95e6ff4a0c3dafb2018e8ea05f9 (diff)
move assists to a separate crate
Diffstat (limited to 'crates/ra_assists/src/fill_match_arms.rs')
-rw-r--r--crates/ra_assists/src/fill_match_arms.rs145
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 @@
1use std::fmt::Write;
2
3use hir::{
4 AdtDef, Ty, FieldSource, source_binder,
5 db::HirDatabase,
6};
7use ra_syntax::ast::{self, AstNode};
8
9use crate::{AssistCtx, Assist};
10
11pub(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)]
77mod 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}