aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-18 08:24:18 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-18 08:24:18 +0000
commit7c117567ab55046a9303fc7a6676a50008ad4f33 (patch)
tree5f00d197d1dc9f8ab108afb394cedf227d892288 /crates/ra_assists
parent4c1ea0b628f949612b48dd3b65c7d8bb2255f572 (diff)
parentca262fbab80dd74fd585544b9e6ce99e394dc573 (diff)
Merge #989
989: Implement naive version of fill_struct_fields assist r=matklad a=yanchith Fixes #964 This implements the `fill_struct_fields` assist. Currently only works for named struct fields, but not for tuple structs, because we seem to be missing a `TupleStructLit` (akin to `StructLit`, but for tuple structs). I am happy to implement `TupleStructLit` parsing given some guidance (provided it's really missing) and make the assist work for tuple structs as well. Could do so either in this PR, or another one 🙂 Sorry if I missed something important, this is my first PR for Rust Analyzer. Btw is there any way to run the assists in emacs? UPDATE: I just realized that parsing `TupleStructLit` would be quite difficult as it it really similar, if not identical to a function call... Co-authored-by: yanchith <[email protected]>
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/fill_struct_fields.rs151
-rw-r--r--crates/ra_assists/src/lib.rs2
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 @@
1use std::fmt::Write;
2
3use hir::{AdtDef, Ty, source_binder};
4use hir::db::HirDatabase;
5
6use ra_syntax::ast::{self, AstNode};
7
8use crate::{AssistCtx, Assist, AssistId};
9
10pub(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)]
50mod 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;
90mod flip_comma; 90mod flip_comma;
91mod change_visibility; 91mod change_visibility;
92mod fill_match_arms; 92mod fill_match_arms;
93mod fill_struct_fields;
93mod introduce_variable; 94mod introduce_variable;
94mod replace_if_let_with_match; 95mod replace_if_let_with_match;
95mod split_import; 96mod 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,