diff options
Diffstat (limited to 'crates/ra_ide_api/src/assists')
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 @@ | |||
1 | use std::fmt::Write; | ||
2 | use hir::{ | ||
3 | AdtDef, | ||
4 | source_binder, | ||
5 | Ty, | ||
6 | FieldSource, | ||
7 | }; | ||
8 | use ra_ide_api_light::{ | ||
9 | assists::{ | ||
10 | Assist, | ||
11 | AssistBuilder | ||
12 | } | ||
13 | }; | ||
14 | use ra_syntax::{ | ||
15 | ast::{ | ||
16 | self, | ||
17 | AstNode, | ||
18 | } | ||
19 | }; | ||
20 | |||
21 | use crate::assists::AssistCtx; | ||
22 | |||
23 | pub 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)] | ||
88 | mod 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 | --- | ||
2 | created: "2019-02-03T15:38:46.094184+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: ret | ||
5 | source: 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 | --- | ||
2 | created: "2019-02-03T15:41:34.640074+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: ret | ||
5 | source: 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 | ] | ||