@@ -2,8 +2,6 @@ use hir::ModuleDef;
22use ide_db:: helpers:: { import_assets:: NameToImport , mod_path_to_ast} ;
33use ide_db:: items_locator;
44use itertools:: Itertools ;
5- use syntax:: ast:: edit:: AstNodeEdit ;
6- use syntax:: ted;
75use syntax:: {
86 ast:: { self , make, AstNode , NameOwner } ,
97 SyntaxKind :: { IDENT , WHITESPACE } ,
@@ -12,8 +10,8 @@ use syntax::{
1210use crate :: {
1311 assist_context:: { AssistBuilder , AssistContext , Assists } ,
1412 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 ,
1715 } ,
1816 AssistId , AssistKind ,
1917} ;
@@ -169,158 +167,12 @@ fn impl_def_from_trait(
169167
170168 // Generate a default `impl` function body for the derived trait.
171169 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) ;
173171 } ;
174172
175173 Some ( ( impl_def, first_assoc_item) )
176174}
177175
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- }
324176fn update_attribute (
325177 builder : & mut AssistBuilder ,
326178 input : & ast:: TokenTree ,
0 commit comments