1
1
use std:: fmt:: Write ;
2
2
3
- use hir:: { AdtDef , Ty , source_binder} ;
4
- use hir:: db:: HirDatabase ;
3
+ use hir:: { AdtDef , Ty , db:: HirDatabase , source_binder:: function_from_child_node} ;
5
4
6
5
use ra_syntax:: ast:: { self , AstNode } ;
7
6
8
7
use crate :: { AssistCtx , Assist , AssistId } ;
9
8
10
9
pub ( crate ) fn fill_struct_fields ( mut ctx : AssistCtx < impl HirDatabase > ) -> Option < Assist > {
11
10
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 {
11
+ let mut fsf = FillStructFields {
12
+ ctx : & mut ctx,
13
+ named_field_list : struct_lit. named_field_list ( ) ?,
14
+ struct_fields : vec ! [ ] ,
15
+ struct_lit,
16
+ } ;
17
+ fsf. evaluate_struct_def_fields ( ) ?;
18
+ if fsf. struct_lit_and_def_have_the_same_number_of_fields ( ) {
16
19
return None ;
17
20
}
21
+ fsf. remove_already_included_fields ( ) ?;
22
+ fsf. add_action ( ) ?;
23
+ ctx. build ( )
24
+ }
18
25
19
- let function =
20
- source_binder:: function_from_child_node ( ctx. db , ctx. frange . file_id , struct_lit. syntax ( ) ) ?;
26
+ struct FillStructFields < ' a , ' b : ' a , DB > {
27
+ ctx : & ' a mut AssistCtx < ' b , DB > ,
28
+ named_field_list : & ' a ast:: NamedFieldList ,
29
+ struct_fields : Vec < ( String , String ) > ,
30
+ struct_lit : & ' a ast:: StructLit ,
31
+ }
21
32
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
- } ;
33
+ impl < DB > FillStructFields < ' _ , ' _ , DB >
34
+ where
35
+ DB : HirDatabase ,
36
+ {
37
+ fn add_action ( & mut self ) -> Option < ( ) > {
38
+ let named_field_list = self . named_field_list ;
39
+ let struct_fields_string = self . struct_fields_string ( ) ?;
40
+ let struct_lit = self . struct_lit ;
41
+ self . ctx . add_action ( AssistId ( "fill_struct_fields" ) , "fill struct fields" , |edit| {
42
+ edit. target ( struct_lit. syntax ( ) . range ( ) ) ;
43
+ edit. set_cursor ( struct_lit. syntax ( ) . range ( ) . start ( ) ) ;
44
+ edit. replace_node_and_indent ( named_field_list. syntax ( ) , struct_fields_string) ;
45
+ } ) ;
46
+ Some ( ( ) )
47
+ }
30
48
31
- let db = ctx. db ;
32
- ctx. add_action ( AssistId ( "fill_struct_fields" ) , "fill struct fields" , |edit| {
49
+ fn struct_lit_and_def_have_the_same_number_of_fields ( & self ) -> bool {
50
+ self . named_field_list . fields ( ) . count ( ) == self . struct_fields . len ( )
51
+ }
52
+
53
+ fn evaluate_struct_def_fields ( & mut self ) -> Option < ( ) > {
54
+ let function = function_from_child_node (
55
+ self . ctx . db ,
56
+ self . ctx . frange . file_id ,
57
+ self . struct_lit . syntax ( ) ,
58
+ ) ?;
59
+ let infer_result = function. infer ( self . ctx . db ) ;
60
+ let source_map = function. body_source_map ( self . ctx . db ) ;
61
+ let node_expr = source_map. node_expr ( self . struct_lit . into ( ) ) ?;
62
+ let struct_lit_ty = infer_result[ node_expr] . clone ( ) ;
63
+ let struct_def = match struct_lit_ty {
64
+ Ty :: Adt { def_id : AdtDef :: Struct ( s) , .. } => s,
65
+ _ => return None ,
66
+ } ;
67
+ self . struct_fields = struct_def
68
+ . fields ( self . ctx . db )
69
+ . into_iter ( )
70
+ . map ( |f| ( f. name ( self . ctx . db ) . to_string ( ) , "()" . into ( ) ) )
71
+ . collect ( ) ;
72
+ Some ( ( ) )
73
+ }
74
+
75
+ fn remove_already_included_fields ( & mut self ) -> Option < ( ) > {
76
+ for ast_field in self . named_field_list . fields ( ) {
77
+ let expr = ast_field. expr ( ) ?. syntax ( ) . text ( ) . to_string ( ) ;
78
+ let name_from_ast = ast_field. name_ref ( ) ?. text ( ) . to_string ( ) ;
79
+ if let Some ( idx) = self . struct_fields . iter ( ) . position ( |( n, _) | n == & name_from_ast) {
80
+ self . struct_fields [ idx] = ( name_from_ast, expr) ;
81
+ }
82
+ }
83
+ Some ( ( ) )
84
+ }
85
+
86
+ fn struct_fields_string ( & mut self ) -> Option < String > {
33
87
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 ( ) ;
88
+ for ( name, expr) in & self . struct_fields {
89
+ write ! ( & mut buf, " {}: {},\n " , name, expr) . unwrap ( ) ;
38
90
}
39
91
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 ( )
92
+ Some ( buf)
93
+ }
47
94
}
48
95
49
96
#[ cfg( test) ]
@@ -62,7 +109,7 @@ mod tests {
62
109
b: String,
63
110
c: (i32, i32),
64
111
d: D,
65
- r : &'a str,
112
+ e : &'a str,
66
113
}
67
114
68
115
fn main() {
@@ -75,7 +122,7 @@ mod tests {
75
122
b: String,
76
123
c: (i32, i32),
77
124
d: D,
78
- r : &'a str,
125
+ e : &'a str,
79
126
}
80
127
81
128
fn main() {
@@ -84,7 +131,7 @@ mod tests {
84
131
b: (),
85
132
c: (),
86
133
d: (),
87
- r : (),
134
+ e : (),
88
135
}
89
136
}
90
137
"# ,
@@ -101,7 +148,7 @@ mod tests {
101
148
b: String,
102
149
c: (i32, i32),
103
150
d: D,
104
- r : &'a str,
151
+ e : &'a str,
105
152
}
106
153
107
154
fn main() {
@@ -148,4 +195,46 @@ mod tests {
148
195
"# ,
149
196
) ;
150
197
}
198
+
199
+ #[ test]
200
+ fn fill_struct_fields_partial ( ) {
201
+ check_assist (
202
+ fill_struct_fields,
203
+ r#"
204
+ struct S<'a, D> {
205
+ a: u32,
206
+ b: String,
207
+ c: (i32, i32),
208
+ d: D,
209
+ e: &'a str,
210
+ }
211
+
212
+ fn main() {
213
+ let s = S {
214
+ c: (1, 2),
215
+ e: "foo",<|>
216
+ }
217
+ }
218
+ "# ,
219
+ r#"
220
+ struct S<'a, D> {
221
+ a: u32,
222
+ b: String,
223
+ c: (i32, i32),
224
+ d: D,
225
+ e: &'a str,
226
+ }
227
+
228
+ fn main() {
229
+ let s = <|>S {
230
+ a: (),
231
+ b: (),
232
+ c: (1, 2),
233
+ d: (),
234
+ e: "foo",
235
+ }
236
+ }
237
+ "# ,
238
+ ) ;
239
+ }
151
240
}
0 commit comments