1
- use hir:: { self , HasCrate , HirDisplay } ;
1
+ use hir:: { self , HasCrate , HasSource , HirDisplay } ;
2
2
use syntax:: ast:: { self , make, AstNode , HasName , HasVisibility } ;
3
3
4
4
use crate :: {
5
5
utils:: { find_struct_impl, render_snippet, Cursor } ,
6
6
AssistContext , AssistId , AssistKind , Assists , GroupLabel ,
7
7
} ;
8
+ use syntax:: ast:: edit:: AstNodeEdit ;
8
9
9
10
// Assist: generate_setter
10
11
//
@@ -33,6 +34,7 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
33
34
let strukt_name = strukt. name ( ) ?;
34
35
35
36
let field = ctx. find_node_at_offset :: < ast:: RecordField > ( ) ?;
37
+ let field_name = field. name ( ) ?;
36
38
let field_ty = field. ty ( ) ?;
37
39
38
40
let sema_field_ty = ctx. sema . resolve_type ( & field_ty) ?;
@@ -61,36 +63,62 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
61
63
target,
62
64
|builder| {
63
65
// make function
64
- let vis = strukt. visibility ( ) ;
66
+ let method_source = match method. source ( ctx. db ( ) ) {
67
+ Some ( source) => source. value ,
68
+ None => return ,
69
+ } ;
70
+ let method_name = method. name ( ctx. db ( ) ) ;
71
+ let vis = method_source. visibility ( ) ;
65
72
let name = make:: name ( & method. name ( ctx. db ( ) ) . to_string ( ) ) ;
66
73
let type_params = None ;
67
- let params = make:: param_list ( None , [ ] ) ;
68
- let body = make:: block_expr ( [ ] , None ) ;
74
+ let self_ty = method
75
+ . self_param ( ctx. db ( ) )
76
+ . map ( |s| s. source ( ctx. db ( ) ) . map ( |s| s. value ) )
77
+ . flatten ( ) ;
78
+ let params = make:: param_list ( self_ty, [ ] ) ;
79
+ let tail_expr = make:: expr_method_call (
80
+ field_from_idents ( [ "self" , & field_name. to_string ( ) ] ) . unwrap ( ) ,
81
+ make:: name_ref ( & method_name. to_string ( ) ) ,
82
+ make:: arg_list ( [ ] ) ,
83
+ ) ;
84
+ let body = make:: block_expr ( [ ] , Some ( tail_expr) ) ;
69
85
let ret_type = & method. ret_type ( ctx. db ( ) ) . display ( ctx. db ( ) ) . to_string ( ) ;
70
86
let ret_type = Some ( make:: ret_type ( make:: ty ( ret_type) ) ) ;
71
87
let is_async = false ;
72
- let f = make:: fn_ ( vis, name, type_params, params, body, ret_type, is_async) ;
88
+ let f = make:: fn_ ( vis, name, type_params, params, body, ret_type, is_async)
89
+ . indent ( ast:: edit:: IndentLevel ( 1 ) )
90
+ . clone_for_update ( ) ;
73
91
74
92
let cursor = Cursor :: Before ( f. syntax ( ) ) ;
75
93
let cap = ctx. config . snippet_cap . unwrap ( ) ; // FIXME.
76
94
95
+ // Create or update an impl block, and attach the function to it.
77
96
match impl_def {
78
97
Some ( impl_def) => {
98
+ // Remember where in our source our `impl` block lives.
79
99
let impl_def = impl_def. clone_for_update ( ) ;
80
100
let old_range = impl_def. syntax ( ) . text_range ( ) ;
101
+
102
+ // Attach the function to the impl block
81
103
let assoc_items = impl_def. get_or_create_assoc_item_list ( ) ;
82
104
assoc_items. add_item ( f. clone ( ) . into ( ) ) ;
105
+
106
+ // Update the impl block.
83
107
let snippet = render_snippet ( cap, impl_def. syntax ( ) , cursor) ;
84
108
builder. replace_snippet ( cap, old_range, snippet) ;
85
109
}
86
110
None => {
111
+ // Attach the function to the impl block
87
112
let name = & strukt_name. to_string ( ) ;
88
- let impl_def = make:: impl_ ( make:: ext:: ident_path ( name) ) ;
113
+ let impl_def = make:: impl_ ( make:: ext:: ident_path ( name) ) . clone_for_update ( ) ;
89
114
let assoc_items = impl_def. get_or_create_assoc_item_list ( ) ;
90
115
assoc_items. add_item ( f. clone ( ) . into ( ) ) ;
91
- let start_offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
116
+
117
+ // Insert the impl block.
118
+ let offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
92
119
let snippet = render_snippet ( cap, impl_def. syntax ( ) , cursor) ;
93
- builder. insert_snippet ( cap, start_offset, snippet) ;
120
+ let snippet = format ! ( "\n \n {}" , snippet) ;
121
+ builder. insert_snippet ( cap, offset, snippet) ;
94
122
}
95
123
}
96
124
} ,
@@ -99,35 +127,77 @@ pub(crate) fn generate_delegate(acc: &mut Assists, ctx: &AssistContext) -> Optio
99
127
Some ( ( ) )
100
128
}
101
129
130
+ pub fn field_from_idents < ' a > (
131
+ parts : impl std:: iter:: IntoIterator < Item = & ' a str > ,
132
+ ) -> Option < ast:: Expr > {
133
+ let mut iter = parts. into_iter ( ) ;
134
+ let base = make:: expr_path ( make:: ext:: ident_path ( iter. next ( ) ?) ) ;
135
+ let expr = iter. fold ( base, |base, s| make:: expr_field ( base, s) ) ;
136
+ Some ( expr)
137
+ }
138
+
102
139
#[ cfg( test) ]
103
140
mod tests {
104
141
use crate :: tests:: check_assist;
105
142
106
143
use super :: * ;
107
144
108
145
#[ test]
109
- fn test_generate_setter_from_field ( ) {
146
+ fn test_generate_delegate_create_impl_block ( ) {
147
+ check_assist (
148
+ generate_delegate,
149
+ r#"
150
+ struct Age(u8);
151
+ impl Age {
152
+ fn age(&self) -> u8 {
153
+ self.0
154
+ }
155
+ }
156
+
157
+ struct Person {
158
+ ag$0e: Age,
159
+ }"# ,
160
+ r#"
161
+ struct Age(u8);
162
+ impl Age {
163
+ fn age(&self) -> u8 {
164
+ self.0
165
+ }
166
+ }
167
+
168
+ struct Person {
169
+ age: Age,
170
+ }
171
+
172
+ impl Person {
173
+ $0fn age(&self) -> u8 {
174
+ self.age.age()
175
+ }
176
+ }"# ,
177
+ ) ;
178
+ }
179
+
180
+ #[ test]
181
+ fn test_generate_delegate_update_impl_block ( ) {
110
182
check_assist (
111
183
generate_delegate,
112
184
r#"
113
185
struct Age(u8);
114
186
impl Age {
115
187
fn age(&self) -> u8 {
116
188
self.0
117
-
118
189
}
119
190
}
120
191
121
192
struct Person {
122
193
ag$0e: Age,
123
194
}
124
195
125
- impl Person {}
126
- "# ,
196
+ impl Person {}"# ,
127
197
r#"
128
198
struct Age(u8);
129
199
impl Age {
130
- $0fn age(&self) -> u8 {
200
+ fn age(&self) -> u8 {
131
201
self.0
132
202
}
133
203
}
@@ -137,7 +207,12 @@ struct Person {
137
207
}
138
208
139
209
impl Person {
140
- fn age(&self) -> u8 {
210
+ $0fn age(&self) -> u8 {
211
+ self.age.age()
212
+ }
213
+ }"# ,
214
+ ) ;
215
+ }
141
216
self . age. age( )
142
217
}
143
218
} "#,
0 commit comments