diff options
-rw-r--r-- | crates/ra_assists/src/fill_struct_fields.rs | 151 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 |
2 files changed, 153 insertions, 0 deletions
diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs new file mode 100644 index 000000000..90ce9c577 --- /dev/null +++ b/crates/ra_assists/src/fill_struct_fields.rs | |||
@@ -0,0 +1,151 @@ | |||
1 | use std::fmt::Write; | ||
2 | |||
3 | use hir::{AdtDef, Ty, source_binder}; | ||
4 | use hir::db::HirDatabase; | ||
5 | |||
6 | use ra_syntax::ast::{self, AstNode}; | ||
7 | |||
8 | use crate::{AssistCtx, Assist, AssistId}; | ||
9 | |||
10 | pub(crate) fn fill_struct_fields(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
11 | let struct_lit = ctx.node_at_offset::<ast::StructLit>()?; | ||
12 | let named_field_list = struct_lit.named_field_list()?; | ||
13 | |||
14 | // If we already have existing struct fields, don't provide the assist. | ||
15 | if named_field_list.fields().count() > 0 { | ||
16 | return None; | ||
17 | } | ||
18 | |||
19 | let function = | ||
20 | source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, struct_lit.syntax())?; | ||
21 | |||
22 | let infer_result = function.infer(ctx.db); | ||
23 | let source_map = function.body_source_map(ctx.db); | ||
24 | let node_expr = source_map.node_expr(struct_lit.into())?; | ||
25 | let struct_lit_ty = infer_result[node_expr].clone(); | ||
26 | let struct_def = match struct_lit_ty { | ||
27 | Ty::Adt { def_id: AdtDef::Struct(s), .. } => s, | ||
28 | _ => return None, | ||
29 | }; | ||
30 | |||
31 | let db = ctx.db; | ||
32 | ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| { | ||
33 | let mut buf = String::from("{\n"); | ||
34 | let struct_fields = struct_def.fields(db); | ||
35 | for field in struct_fields { | ||
36 | let field_name = field.name(db).to_string(); | ||
37 | write!(&mut buf, " {}: (),\n", field_name).unwrap(); | ||
38 | } | ||
39 | buf.push_str("}"); | ||
40 | |||
41 | edit.target(struct_lit.syntax().range()); | ||
42 | edit.set_cursor(struct_lit.syntax().range().start()); | ||
43 | edit.replace_node_and_indent(named_field_list.syntax(), buf); | ||
44 | }); | ||
45 | |||
46 | ctx.build() | ||
47 | } | ||
48 | |||
49 | #[cfg(test)] | ||
50 | mod tests { | ||
51 | use crate::helpers::{check_assist, check_assist_target}; | ||
52 | |||
53 | use super::fill_struct_fields; | ||
54 | |||
55 | #[test] | ||
56 | fn fill_struct_fields_empty_body() { | ||
57 | check_assist( | ||
58 | fill_struct_fields, | ||
59 | r#" | ||
60 | struct S<'a, D> { | ||
61 | a: u32, | ||
62 | b: String, | ||
63 | c: (i32, i32), | ||
64 | d: D, | ||
65 | r: &'a str, | ||
66 | } | ||
67 | |||
68 | fn main() { | ||
69 | let s = S<|> {} | ||
70 | } | ||
71 | "#, | ||
72 | r#" | ||
73 | struct S<'a, D> { | ||
74 | a: u32, | ||
75 | b: String, | ||
76 | c: (i32, i32), | ||
77 | d: D, | ||
78 | r: &'a str, | ||
79 | } | ||
80 | |||
81 | fn main() { | ||
82 | let s = <|>S { | ||
83 | a: (), | ||
84 | b: (), | ||
85 | c: (), | ||
86 | d: (), | ||
87 | r: (), | ||
88 | } | ||
89 | } | ||
90 | "#, | ||
91 | ); | ||
92 | } | ||
93 | |||
94 | #[test] | ||
95 | fn fill_struct_fields_target() { | ||
96 | check_assist_target( | ||
97 | fill_struct_fields, | ||
98 | r#" | ||
99 | struct S<'a, D> { | ||
100 | a: u32, | ||
101 | b: String, | ||
102 | c: (i32, i32), | ||
103 | d: D, | ||
104 | r: &'a str, | ||
105 | } | ||
106 | |||
107 | fn main() { | ||
108 | let s = S<|> {} | ||
109 | } | ||
110 | "#, | ||
111 | "S {}", | ||
112 | ); | ||
113 | } | ||
114 | |||
115 | #[test] | ||
116 | fn fill_struct_fields_preserve_self() { | ||
117 | check_assist( | ||
118 | fill_struct_fields, | ||
119 | r#" | ||
120 | struct Foo { | ||
121 | foo: u8, | ||
122 | bar: String, | ||
123 | baz: i128, | ||
124 | } | ||
125 | |||
126 | impl Foo { | ||
127 | pub fn new() -> Self { | ||
128 | Self <|>{} | ||
129 | } | ||
130 | } | ||
131 | "#, | ||
132 | r#" | ||
133 | struct Foo { | ||
134 | foo: u8, | ||
135 | bar: String, | ||
136 | baz: i128, | ||
137 | } | ||
138 | |||
139 | impl Foo { | ||
140 | pub fn new() -> Self { | ||
141 | <|>Self { | ||
142 | foo: (), | ||
143 | bar: (), | ||
144 | baz: (), | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 0c4abb450..871b37f58 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -90,6 +90,7 @@ mod add_impl; | |||
90 | mod flip_comma; | 90 | mod flip_comma; |
91 | mod change_visibility; | 91 | mod change_visibility; |
92 | mod fill_match_arms; | 92 | mod fill_match_arms; |
93 | mod fill_struct_fields; | ||
93 | mod introduce_variable; | 94 | mod introduce_variable; |
94 | mod replace_if_let_with_match; | 95 | mod replace_if_let_with_match; |
95 | mod split_import; | 96 | mod split_import; |
@@ -103,6 +104,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
103 | add_impl::add_impl, | 104 | add_impl::add_impl, |
104 | change_visibility::change_visibility, | 105 | change_visibility::change_visibility, |
105 | fill_match_arms::fill_match_arms, | 106 | fill_match_arms::fill_match_arms, |
107 | fill_struct_fields::fill_struct_fields, | ||
106 | flip_comma::flip_comma, | 108 | flip_comma::flip_comma, |
107 | introduce_variable::introduce_variable, | 109 | introduce_variable::introduce_variable, |
108 | replace_if_let_with_match::replace_if_let_with_match, | 110 | replace_if_let_with_match::replace_if_let_with_match, |