aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/assists')
-rw-r--r--crates/ra_ide_api/src/assists/fill_match_arm.rs157
-rw-r--r--crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm1.snap20
-rw-r--r--crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm2.snap20
3 files changed, 197 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/assists/fill_match_arm.rs b/crates/ra_ide_api/src/assists/fill_match_arm.rs
new file mode 100644
index 000000000..6ae829d85
--- /dev/null
+++ b/crates/ra_ide_api/src/assists/fill_match_arm.rs
@@ -0,0 +1,157 @@
1use std::fmt::Write;
2use hir::{
3 AdtDef,
4 source_binder,
5 Ty,
6 FieldSource,
7};
8use ra_ide_api_light::{
9 assists::{
10 Assist,
11 AssistBuilder
12 }
13};
14use ra_syntax::{
15 ast::{
16 self,
17 AstNode,
18 }
19};
20
21use crate::assists::AssistCtx;
22
23pub fn fill_match_arm(ctx: AssistCtx) -> Option<Assist> {
24 let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;
25
26 // We already have some match arms, so we don't provide any assists.
27 match match_expr.match_arm_list() {
28 Some(arm_list) if arm_list.arms().count() > 0 => {
29 return None;
30 }
31 _ => {}
32 }
33
34 let expr = match_expr.expr()?;
35 let function = source_binder::function_from_child_node(ctx.db, ctx.file_id, expr.syntax())?;
36 let infer_result = function.infer(ctx.db);
37 let syntax_mapping = function.body_syntax_mapping(ctx.db);
38 let node_expr = syntax_mapping.node_expr(expr)?;
39 let match_expr_ty = infer_result[node_expr].clone();
40 match match_expr_ty {
41 Ty::Adt { def_id, .. } => match def_id {
42 AdtDef::Enum(e) => {
43 let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
44 let variants = e.variants(ctx.db);
45 for variant in variants {
46 let name = variant.name(ctx.db)?;
47 write!(
48 &mut buf,
49 " {}::{}",
50 e.name(ctx.db)?.to_string(),
51 name.to_string()
52 )
53 .expect("write fmt");
54
55 let pat = variant
56 .fields(ctx.db)
57 .into_iter()
58 .map(|field| {
59 let name = field.name(ctx.db).to_string();
60 let (_, source) = field.source(ctx.db);
61 match source {
62 FieldSource::Named(_) => name,
63 FieldSource::Pos(_) => "_".to_string(),
64 }
65 })
66 .collect::<Vec<_>>();
67
68 match pat.first().map(|s| s.as_str()) {
69 Some("_") => write!(&mut buf, "({})", pat.join(", ")).expect("write fmt"),
70 Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).expect("write fmt"),
71 None => (),
72 };
73
74 buf.push_str(" => (),\n");
75 }
76 buf.push_str("}");
77 ctx.build("fill match arms", |edit: &mut AssistBuilder| {
78 edit.replace_node_and_indent(match_expr.syntax(), buf);
79 })
80 }
81 _ => None,
82 },
83 _ => None,
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use insta::assert_debug_snapshot_matches;
90
91 use ra_syntax::{TextRange, TextUnit};
92
93 use crate::{
94 FileRange,
95 mock_analysis::{analysis_and_position, single_file_with_position}
96};
97 use ra_db::SourceDatabase;
98
99 fn test_assit(name: &str, code: &str) {
100 let (analysis, position) = if code.contains("//-") {
101 analysis_and_position(code)
102 } else {
103 single_file_with_position(code)
104 };
105 let frange = FileRange {
106 file_id: position.file_id,
107 range: TextRange::offset_len(position.offset, TextUnit::from(1)),
108 };
109 let source_file = analysis
110 .with_db(|db| db.parse(frange.file_id))
111 .expect("source file");
112 let ret = analysis
113 .with_db(|db| crate::assists::assists(db, frange.file_id, &source_file, frange.range))
114 .expect("assists");
115
116 assert_debug_snapshot_matches!(name, ret);
117 }
118
119 #[test]
120 fn test_fill_match_arm() {
121 test_assit(
122 "fill_match_arm1",
123 r#"
124 enum A {
125 As,
126 Bs,
127 Cs(String),
128 Ds(String, String),
129 Es{x: usize, y: usize}
130 }
131
132 fn main() {
133 let a = A::As;
134 match a<|>
135 }
136 "#,
137 );
138
139 test_assit(
140 "fill_match_arm2",
141 r#"
142 enum A {
143 As,
144 Bs,
145 Cs(String),
146 Ds(String, String),
147 Es{x: usize, y: usize}
148 }
149
150 fn main() {
151 let a = A::As;
152 match a<|> {}
153 }
154 "#,
155 );
156 }
157}
diff --git a/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm1.snap b/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm1.snap
new file mode 100644
index 000000000..980726d92
--- /dev/null
+++ b/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm1.snap
@@ -0,0 +1,20 @@
1---
2created: "2019-02-03T15:38:46.094184+00:00"
3creator: [email protected]
4expression: ret
5source: crates/ra_ide_api/src/assits/fill_match_arm.rs
6---
7[
8 LocalEdit {
9 label: "fill match arms",
10 edit: TextEdit {
11 atoms: [
12 AtomTextEdit {
13 delete: [211; 218),
14 insert: "match a {\n A::As => (),\n A::Bs => (),\n A::Cs(_) => (),\n A::Ds(_, _) => (),\n A::Es{x, y} => (),\n }"
15 }
16 ]
17 },
18 cursor_position: None
19 }
20]
diff --git a/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm2.snap b/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm2.snap
new file mode 100644
index 000000000..cee0efe74
--- /dev/null
+++ b/crates/ra_ide_api/src/assists/snapshots/tests__fill_match_arm2.snap
@@ -0,0 +1,20 @@
1---
2created: "2019-02-03T15:41:34.640074+00:00"
3creator: [email protected]
4expression: ret
5source: crates/ra_ide_api/src/assits/fill_match_arm.rs
6---
7[
8 LocalEdit {
9 label: "fill match arms",
10 edit: TextEdit {
11 atoms: [
12 AtomTextEdit {
13 delete: [211; 221),
14 insert: "match a {\n A::As => (),\n A::Bs => (),\n A::Cs(_) => (),\n A::Ds(_, _) => (),\n A::Es{x, y} => (),\n }"
15 }
16 ]
17 },
18 cursor_position: None
19 }
20]