diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-06 15:27:34 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-06 15:27:34 +0100 |
commit | ef782adc293deb287128f005dbab2038ba3ccdc1 (patch) | |
tree | 6e451b71b482e75a5a30548ab8f769c5ec17864c /crates/ra_assists/src | |
parent | 32db5884ada59c72aa7ab9f88910ef7c8f882e7d (diff) | |
parent | 12f8472d2800b2d7c05cb1fc466c80072ed8e283 (diff) |
Merge #1163
1163: fill struct fields diagnostic r=matklad a=pasa
implementation of #1095
Co-authored-by: Sergey Parilin <[email protected]>
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/ast_editor.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/fill_struct_fields.rs | 226 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 |
3 files changed, 5 insertions, 228 deletions
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs index 6854294ae..726e5c0a3 100644 --- a/crates/ra_assists/src/ast_editor.rs +++ b/crates/ra_assists/src/ast_editor.rs | |||
@@ -4,6 +4,7 @@ use arrayvec::ArrayVec; | |||
4 | use ra_text_edit::TextEditBuilder; | 4 | use ra_text_edit::TextEditBuilder; |
5 | use ra_syntax::{AstNode, TreeArc, ast, SyntaxKind::*, SyntaxElement, SourceFile, InsertPosition, Direction}; | 5 | use ra_syntax::{AstNode, TreeArc, ast, SyntaxKind::*, SyntaxElement, SourceFile, InsertPosition, Direction}; |
6 | use ra_fmt::leading_indent; | 6 | use ra_fmt::leading_indent; |
7 | use hir::Name; | ||
7 | 8 | ||
8 | pub struct AstEditor<N: AstNode> { | 9 | pub struct AstEditor<N: AstNode> { |
9 | original_ast: TreeArc<N>, | 10 | original_ast: TreeArc<N>, |
@@ -235,6 +236,10 @@ pub struct AstBuilder<N: AstNode> { | |||
235 | } | 236 | } |
236 | 237 | ||
237 | impl AstBuilder<ast::NamedField> { | 238 | impl AstBuilder<ast::NamedField> { |
239 | pub fn from_name(name: &Name) -> TreeArc<ast::NamedField> { | ||
240 | ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name)) | ||
241 | } | ||
242 | |||
238 | fn from_text(text: &str) -> TreeArc<ast::NamedField> { | 243 | fn from_text(text: &str) -> TreeArc<ast::NamedField> { |
239 | ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text)) | 244 | ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text)) |
240 | } | 245 | } |
diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs deleted file mode 100644 index 54b70e17d..000000000 --- a/crates/ra_assists/src/fill_struct_fields.rs +++ /dev/null | |||
@@ -1,226 +0,0 @@ | |||
1 | use hir::{AdtDef, db::HirDatabase}; | ||
2 | |||
3 | use ra_syntax::ast::{self, AstNode}; | ||
4 | |||
5 | use crate::{AssistCtx, Assist, AssistId, ast_editor::{AstEditor, AstBuilder}}; | ||
6 | |||
7 | pub(crate) fn fill_struct_fields(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
8 | let struct_lit = ctx.node_at_offset::<ast::StructLit>()?; | ||
9 | let named_field_list = struct_lit.named_field_list()?; | ||
10 | |||
11 | // Collect all fields from struct definition | ||
12 | let mut fields = { | ||
13 | let analyzer = | ||
14 | hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, struct_lit.syntax(), None); | ||
15 | let struct_lit_ty = analyzer.type_of(ctx.db, struct_lit.into())?; | ||
16 | let struct_def = match struct_lit_ty.as_adt() { | ||
17 | Some((AdtDef::Struct(s), _)) => s, | ||
18 | _ => return None, | ||
19 | }; | ||
20 | struct_def.fields(ctx.db) | ||
21 | }; | ||
22 | |||
23 | // Filter out existing fields | ||
24 | for ast_field in named_field_list.fields() { | ||
25 | let name_from_ast = ast_field.name_ref()?.text().to_string(); | ||
26 | fields.retain(|field| field.name(ctx.db).to_string() != name_from_ast); | ||
27 | } | ||
28 | if fields.is_empty() { | ||
29 | return None; | ||
30 | } | ||
31 | |||
32 | let db = ctx.db; | ||
33 | ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| { | ||
34 | let mut ast_editor = AstEditor::new(named_field_list); | ||
35 | if named_field_list.fields().count() == 0 && fields.len() > 2 { | ||
36 | ast_editor.make_multiline(); | ||
37 | }; | ||
38 | |||
39 | for field in fields { | ||
40 | let field = AstBuilder::<ast::NamedField>::from_pieces( | ||
41 | &AstBuilder::<ast::NameRef>::new(&field.name(db).to_string()), | ||
42 | Some(&AstBuilder::<ast::Expr>::unit()), | ||
43 | ); | ||
44 | ast_editor.append_field(&field); | ||
45 | } | ||
46 | |||
47 | edit.target(struct_lit.syntax().range()); | ||
48 | edit.set_cursor(struct_lit.syntax().range().start()); | ||
49 | |||
50 | ast_editor.into_text_edit(edit.text_edit_builder()); | ||
51 | }); | ||
52 | ctx.build() | ||
53 | } | ||
54 | |||
55 | #[cfg(test)] | ||
56 | mod tests { | ||
57 | use crate::helpers::{check_assist, check_assist_target}; | ||
58 | |||
59 | use super::fill_struct_fields; | ||
60 | |||
61 | #[test] | ||
62 | fn fill_struct_fields_empty_body() { | ||
63 | check_assist( | ||
64 | fill_struct_fields, | ||
65 | r#" | ||
66 | struct S<'a, D> { | ||
67 | a: u32, | ||
68 | b: String, | ||
69 | c: (i32, i32), | ||
70 | d: D, | ||
71 | e: &'a str, | ||
72 | } | ||
73 | |||
74 | fn main() { | ||
75 | let s = S<|> {} | ||
76 | } | ||
77 | "#, | ||
78 | r#" | ||
79 | struct S<'a, D> { | ||
80 | a: u32, | ||
81 | b: String, | ||
82 | c: (i32, i32), | ||
83 | d: D, | ||
84 | e: &'a str, | ||
85 | } | ||
86 | |||
87 | fn main() { | ||
88 | let s = <|>S { | ||
89 | a: (), | ||
90 | b: (), | ||
91 | c: (), | ||
92 | d: (), | ||
93 | e: (), | ||
94 | } | ||
95 | } | ||
96 | "#, | ||
97 | ); | ||
98 | } | ||
99 | |||
100 | #[test] | ||
101 | fn fill_struct_fields_target() { | ||
102 | check_assist_target( | ||
103 | fill_struct_fields, | ||
104 | r#" | ||
105 | struct S<'a, D> { | ||
106 | a: u32, | ||
107 | b: String, | ||
108 | c: (i32, i32), | ||
109 | d: D, | ||
110 | e: &'a str, | ||
111 | } | ||
112 | |||
113 | fn main() { | ||
114 | let s = S<|> {} | ||
115 | } | ||
116 | "#, | ||
117 | "S {}", | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn fill_struct_fields_preserve_self() { | ||
123 | check_assist( | ||
124 | fill_struct_fields, | ||
125 | r#" | ||
126 | struct Foo { | ||
127 | foo: u8, | ||
128 | bar: String, | ||
129 | baz: i128, | ||
130 | } | ||
131 | |||
132 | impl Foo { | ||
133 | pub fn new() -> Self { | ||
134 | Self <|>{} | ||
135 | } | ||
136 | } | ||
137 | "#, | ||
138 | r#" | ||
139 | struct Foo { | ||
140 | foo: u8, | ||
141 | bar: String, | ||
142 | baz: i128, | ||
143 | } | ||
144 | |||
145 | impl Foo { | ||
146 | pub fn new() -> Self { | ||
147 | <|>Self { | ||
148 | foo: (), | ||
149 | bar: (), | ||
150 | baz: (), | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | "#, | ||
155 | ); | ||
156 | } | ||
157 | |||
158 | #[test] | ||
159 | fn fill_struct_fields_partial() { | ||
160 | check_assist( | ||
161 | fill_struct_fields, | ||
162 | r#" | ||
163 | struct S<'a, D> { | ||
164 | a: u32, | ||
165 | b: String, | ||
166 | c: (i32, i32), | ||
167 | d: D, | ||
168 | e: &'a str, | ||
169 | } | ||
170 | |||
171 | fn main() { | ||
172 | let s = S { | ||
173 | c: (1, 2), | ||
174 | e: "foo",<|> | ||
175 | } | ||
176 | } | ||
177 | "#, | ||
178 | r#" | ||
179 | struct S<'a, D> { | ||
180 | a: u32, | ||
181 | b: String, | ||
182 | c: (i32, i32), | ||
183 | d: D, | ||
184 | e: &'a str, | ||
185 | } | ||
186 | |||
187 | fn main() { | ||
188 | let s = <|>S { | ||
189 | c: (1, 2), | ||
190 | e: "foo", | ||
191 | a: (), | ||
192 | b: (), | ||
193 | d: (), | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn fill_struct_short() { | ||
202 | check_assist( | ||
203 | fill_struct_fields, | ||
204 | r#" | ||
205 | struct S { | ||
206 | foo: u32, | ||
207 | bar: String, | ||
208 | } | ||
209 | |||
210 | fn main() { | ||
211 | let s = S {<|> }; | ||
212 | } | ||
213 | "#, | ||
214 | r#" | ||
215 | struct S { | ||
216 | foo: u32, | ||
217 | bar: String, | ||
218 | } | ||
219 | |||
220 | fn main() { | ||
221 | let s = <|>S { foo: (), bar: () }; | ||
222 | } | ||
223 | "#, | ||
224 | ); | ||
225 | } | ||
226 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index a2998ae59..ae97a1ab5 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -93,7 +93,6 @@ mod flip_comma; | |||
93 | mod flip_binexpr; | 93 | mod flip_binexpr; |
94 | mod change_visibility; | 94 | mod change_visibility; |
95 | mod fill_match_arms; | 95 | mod fill_match_arms; |
96 | mod fill_struct_fields; | ||
97 | mod introduce_variable; | 96 | mod introduce_variable; |
98 | mod inline_local_variable; | 97 | mod inline_local_variable; |
99 | mod replace_if_let_with_match; | 98 | mod replace_if_let_with_match; |
@@ -110,7 +109,6 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
110 | add_impl::add_impl, | 109 | add_impl::add_impl, |
111 | change_visibility::change_visibility, | 110 | change_visibility::change_visibility, |
112 | fill_match_arms::fill_match_arms, | 111 | fill_match_arms::fill_match_arms, |
113 | fill_struct_fields::fill_struct_fields, | ||
114 | flip_comma::flip_comma, | 112 | flip_comma::flip_comma, |
115 | flip_binexpr::flip_binexpr, | 113 | flip_binexpr::flip_binexpr, |
116 | introduce_variable::introduce_variable, | 114 | introduce_variable::introduce_variable, |