aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-05-06 15:27:34 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-05-06 15:27:34 +0100
commitef782adc293deb287128f005dbab2038ba3ccdc1 (patch)
tree6e451b71b482e75a5a30548ab8f769c5ec17864c /crates/ra_assists/src
parent32db5884ada59c72aa7ab9f88910ef7c8f882e7d (diff)
parent12f8472d2800b2d7c05cb1fc466c80072ed8e283 (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.rs5
-rw-r--r--crates/ra_assists/src/fill_struct_fields.rs226
-rw-r--r--crates/ra_assists/src/lib.rs2
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;
4use ra_text_edit::TextEditBuilder; 4use ra_text_edit::TextEditBuilder;
5use ra_syntax::{AstNode, TreeArc, ast, SyntaxKind::*, SyntaxElement, SourceFile, InsertPosition, Direction}; 5use ra_syntax::{AstNode, TreeArc, ast, SyntaxKind::*, SyntaxElement, SourceFile, InsertPosition, Direction};
6use ra_fmt::leading_indent; 6use ra_fmt::leading_indent;
7use hir::Name;
7 8
8pub struct AstEditor<N: AstNode> { 9pub 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
237impl AstBuilder<ast::NamedField> { 238impl 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 @@
1use hir::{AdtDef, db::HirDatabase};
2
3use ra_syntax::ast::{self, AstNode};
4
5use crate::{AssistCtx, Assist, AssistId, ast_editor::{AstEditor, AstBuilder}};
6
7pub(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)]
56mod 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;
93mod flip_binexpr; 93mod flip_binexpr;
94mod change_visibility; 94mod change_visibility;
95mod fill_match_arms; 95mod fill_match_arms;
96mod fill_struct_fields;
97mod introduce_variable; 96mod introduce_variable;
98mod inline_local_variable; 97mod inline_local_variable;
99mod replace_if_let_with_match; 98mod 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,