@@ -2,8 +2,6 @@ use hir::ModuleDef;
2
2
use ide_db:: helpers:: { import_assets:: NameToImport , mod_path_to_ast} ;
3
3
use ide_db:: items_locator;
4
4
use itertools:: Itertools ;
5
- use syntax:: ast:: edit:: AstNodeEdit ;
6
- use syntax:: ted;
7
5
use syntax:: {
8
6
ast:: { self , make, AstNode , NameOwner } ,
9
7
SyntaxKind :: { IDENT , WHITESPACE } ,
@@ -12,8 +10,8 @@ use syntax::{
12
10
use crate :: {
13
11
assist_context:: { AssistBuilder , AssistContext , Assists } ,
14
12
utils:: {
15
- add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text ,
16
- render_snippet, Cursor , DefaultMethods ,
13
+ add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body ,
14
+ generate_trait_impl_text , render_snippet, Cursor , DefaultMethods ,
17
15
} ,
18
16
AssistId , AssistKind ,
19
17
} ;
@@ -169,158 +167,12 @@ fn impl_def_from_trait(
169
167
170
168
// Generate a default `impl` function body for the derived trait.
171
169
if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item {
172
- let _ = gen_trait_body_impl ( func, trait_path, adt, annotated_name ) ;
170
+ let _ = gen_trait_fn_body ( func, trait_path, adt) ;
173
171
} ;
174
172
175
173
Some ( ( impl_def, first_assoc_item) )
176
174
}
177
175
178
- /// Generate custom trait bodies where possible.
179
- ///
180
- /// Returns `Option` so that we can use `?` rather than `if let Some`. Returning
181
- /// `None` means that generating a custom trait body failed, and the body will remain
182
- /// as `todo!` instead.
183
- fn gen_trait_body_impl (
184
- func : & ast:: Fn ,
185
- trait_path : & ast:: Path ,
186
- adt : & ast:: Adt ,
187
- annotated_name : & ast:: Name ,
188
- ) -> Option < ( ) > {
189
- match trait_path. segment ( ) ?. name_ref ( ) ?. text ( ) . as_str ( ) {
190
- "Debug" => gen_debug_impl ( adt, func, annotated_name) ,
191
- "Default" => gen_default_impl ( adt, func) ,
192
- _ => None ,
193
- }
194
- }
195
-
196
- /// Generate a `Debug` impl based on the fields and members of the target type.
197
- fn gen_debug_impl ( adt : & ast:: Adt , func : & ast:: Fn , annotated_name : & ast:: Name ) -> Option < ( ) > {
198
- match adt {
199
- // `Debug` cannot be derived for unions, so no default impl can be provided.
200
- ast:: Adt :: Union ( _) => None ,
201
-
202
- // => match self { Self::Variant => write!(f, "Variant") }
203
- ast:: Adt :: Enum ( enum_) => {
204
- let list = enum_. variant_list ( ) ?;
205
- let mut arms = vec ! [ ] ;
206
- for variant in list. variants ( ) {
207
- let name = variant. name ( ) ?;
208
- let left = make:: ext:: ident_path ( "Self" ) ;
209
- let right = make:: ext:: ident_path ( & format ! ( "{}" , name) ) ;
210
- let variant_name = make:: path_pat ( make:: path_concat ( left, right) ) ;
211
-
212
- let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) . into ( ) ) ;
213
- let fmt_string = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
214
- let args = make:: arg_list ( vec ! [ target, fmt_string] ) ;
215
- let macro_name = make:: expr_path ( make:: ext:: ident_path ( "write" ) ) ;
216
- let macro_call = make:: expr_macro_call ( macro_name, args) ;
217
-
218
- arms. push ( make:: match_arm ( Some ( variant_name. into ( ) ) , None , macro_call. into ( ) ) ) ;
219
- }
220
-
221
- let match_target = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
222
- let list = make:: match_arm_list ( arms) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
223
- let match_expr = make:: expr_match ( match_target, list) ;
224
-
225
- let body = make:: block_expr ( None , Some ( match_expr) ) ;
226
- let body = body. indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
227
- ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
228
- Some ( ( ) )
229
- }
230
-
231
- ast:: Adt :: Struct ( strukt) => {
232
- let name = format ! ( "\" {}\" " , annotated_name) ;
233
- let args = make:: arg_list ( Some ( make:: expr_literal ( & name) . into ( ) ) ) ;
234
- let target = make:: expr_path ( make:: ext:: ident_path ( "f" ) ) ;
235
-
236
- let expr = match strukt. field_list ( ) {
237
- // => f.debug_struct("Name").finish()
238
- None => make:: expr_method_call ( target, make:: name_ref ( "debug_struct" ) , args) ,
239
-
240
- // => f.debug_struct("Name").field("foo", &self.foo).finish()
241
- Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
242
- let method = make:: name_ref ( "debug_struct" ) ;
243
- let mut expr = make:: expr_method_call ( target, method, args) ;
244
- for field in field_list. fields ( ) {
245
- let name = field. name ( ) ?;
246
- let f_name = make:: expr_literal ( & ( format ! ( "\" {}\" " , name) ) ) . into ( ) ;
247
- let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
248
- let f_path = make:: expr_ref ( f_path, false ) ;
249
- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , name) ) . into ( ) ;
250
- let args = make:: arg_list ( vec ! [ f_name, f_path] ) ;
251
- expr = make:: expr_method_call ( expr, make:: name_ref ( "field" ) , args) ;
252
- }
253
- expr
254
- }
255
-
256
- // => f.debug_tuple("Name").field(self.0).finish()
257
- Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
258
- let method = make:: name_ref ( "debug_tuple" ) ;
259
- let mut expr = make:: expr_method_call ( target, method, args) ;
260
- for ( idx, _) in field_list. fields ( ) . enumerate ( ) {
261
- let f_path = make:: expr_path ( make:: ext:: ident_path ( "self" ) ) ;
262
- let f_path = make:: expr_ref ( f_path, false ) ;
263
- let f_path = make:: expr_field ( f_path, & format ! ( "{}" , idx) ) . into ( ) ;
264
- let method = make:: name_ref ( "field" ) ;
265
- expr = make:: expr_method_call ( expr, method, make:: arg_list ( Some ( f_path) ) ) ;
266
- }
267
- expr
268
- }
269
- } ;
270
-
271
- let method = make:: name_ref ( "finish" ) ;
272
- let expr = make:: expr_method_call ( expr, method, make:: arg_list ( None ) ) ;
273
- let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
274
- ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
275
- Some ( ( ) )
276
- }
277
- }
278
- }
279
-
280
- /// Generate a `Debug` impl based on the fields and members of the target type.
281
- fn gen_default_impl ( adt : & ast:: Adt , func : & ast:: Fn ) -> Option < ( ) > {
282
- fn gen_default_call ( ) -> ast:: Expr {
283
- let trait_name = make:: ext:: ident_path ( "Default" ) ;
284
- let method_name = make:: ext:: ident_path ( "default" ) ;
285
- let fn_name = make:: expr_path ( make:: path_concat ( trait_name, method_name) ) ;
286
- make:: expr_call ( fn_name, make:: arg_list ( None ) )
287
- }
288
- match adt {
289
- // `Debug` cannot be derived for unions, so no default impl can be provided.
290
- ast:: Adt :: Union ( _) => None ,
291
- // Deriving `Debug` for enums is not stable yet.
292
- ast:: Adt :: Enum ( _) => None ,
293
- ast:: Adt :: Struct ( strukt) => {
294
- let expr = match strukt. field_list ( ) {
295
- Some ( ast:: FieldList :: RecordFieldList ( field_list) ) => {
296
- let mut fields = vec ! [ ] ;
297
- for field in field_list. fields ( ) {
298
- let method_call = gen_default_call ( ) ;
299
- let name_ref = make:: name_ref ( & field. name ( ) ?. to_string ( ) ) ;
300
- let field = make:: record_expr_field ( name_ref, Some ( method_call) ) ;
301
- fields. push ( field) ;
302
- }
303
- let struct_name = make:: ext:: ident_path ( "Self" ) ;
304
- let fields = make:: record_expr_field_list ( fields) ;
305
- make:: record_expr ( struct_name, fields) . into ( )
306
- }
307
- Some ( ast:: FieldList :: TupleFieldList ( field_list) ) => {
308
- let struct_name = make:: expr_path ( make:: ext:: ident_path ( "Self" ) ) ;
309
- let fields = field_list. fields ( ) . map ( |_| gen_default_call ( ) ) ;
310
- make:: expr_call ( struct_name, make:: arg_list ( fields) )
311
- }
312
- None => {
313
- let struct_name = make:: ext:: ident_path ( "Self" ) ;
314
- let fields = make:: record_expr_field_list ( None ) ;
315
- make:: record_expr ( struct_name, fields) . into ( )
316
- }
317
- } ;
318
- let body = make:: block_expr ( None , Some ( expr) ) . indent ( ast:: edit:: IndentLevel ( 1 ) ) ;
319
- ted:: replace ( func. body ( ) ?. syntax ( ) , body. clone_for_update ( ) . syntax ( ) ) ;
320
- Some ( ( ) )
321
- }
322
- }
323
- }
324
176
fn update_attribute (
325
177
builder : & mut AssistBuilder ,
326
178
input : & ast:: TokenTree ,
0 commit comments