11use crate :: { AssistContext , Assists } ;
22use hir:: { HasAttrs as _, HasCrate , HirFileId , ItemInNs } ;
33use ide_db:: {
4- assists:: { AssistId , AssistKind } ,
5- helpers:: mod_path_to_ast,
6- imports:: import_assets:: NameToImport ,
7- items_locator, FxHashMap ,
4+ FxHashMap , assists:: AssistId , helpers:: mod_path_to_ast, imports:: import_assets:: NameToImport ,
5+ items_locator,
86} ;
97use itertools:: Itertools ;
108use smallvec:: SmallVec ;
119use syntax:: {
12- ast:: { self , edit_in_place:: AttrsOwnerEdit , make, HasAttrs } ,
13- syntax_editor:: Position ,
14- AstNode , T ,
10+ AstNode ,
11+ SyntaxKind :: { ATTR , COMMENT , WHITESPACE } ,
12+ T ,
13+ ast:: { self , HasAttrs , edit:: IndentLevel , make} ,
14+ syntax_editor:: { Element , Position } ,
1515} ;
1616
1717// Assist: recursively_add_derive
@@ -64,7 +64,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
6464 // The cursor is on the derive keyword, use all derive items the ADT has.
6565 let items: SmallVec < _ > = adt
6666 . attrs ( ctx. db ( ) )
67- . by_key ( & hir:: sym:: derive)
67+ . by_key ( hir:: sym:: derive)
6868 . attrs ( )
6969 . filter_map ( |attr| attr. parse_path_comma_token_tree ( ctx. db ( ) ) )
7070 . flatten ( )
@@ -104,7 +104,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
104104 } )
105105 . to_string ( ) ;
106106 acc. add (
107- AssistId ( "recursively_add_derive" , AssistKind :: Generate ) ,
107+ AssistId :: generate ( "recursively_add_derive" ) ,
108108 format ! ( "Recursively add `#[derive({formatted_items})]` to each field type" ) ,
109109 adt_src. syntax ( ) . text_range ( ) ,
110110 |edit| {
@@ -138,11 +138,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
138138 } ) ;
139139
140140 let maybe_derive_attr = adt_src. attrs ( ) . find_map ( |attr| {
141- if attr. path ( ) ?. syntax ( ) . text ( ) == "derive" {
142- attr. token_tree ( )
143- } else {
144- None
145- }
141+ if attr. path ( ) ?. syntax ( ) . text ( ) == "derive" { attr. token_tree ( ) } else { None }
146142 } ) ;
147143
148144 if let Some ( derive_attr) = maybe_derive_attr {
@@ -171,19 +167,29 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
171167 let tt = derive_paths
172168 . filter_map ( |item| item. into_token ( ) )
173169 . map ( syntax:: NodeOrToken :: Token )
174- . collect ( ) ;
170+ . collect :: < Vec < _ > > ( ) ;
175171 let derive = make:: attr_outer ( make:: meta_token_tree (
176172 make:: ext:: ident_path ( "derive" ) ,
177173 make:: token_tree ( T ! [ '(' ] , tt) . clone_for_update ( ) ,
178174 ) )
179175 . clone_for_update ( ) ;
180176
181- // TODO: Switch to the `SyntaxEditor` equivalent of `add_attr()` once that's available.
182- let new_adt = adt_src. clone_for_update ( ) ;
183- new_adt. add_attr ( derive) ;
184- editor. replace ( adt_src. syntax ( ) , new_adt. syntax ( ) ) ;
177+ let indent = IndentLevel :: from_node ( adt_src. syntax ( ) ) ;
178+ let after_attrs_and_comments = adt_src
179+ . syntax ( )
180+ . children_with_tokens ( )
181+ . find ( |it| !matches ! ( it. kind( ) , WHITESPACE | COMMENT | ATTR ) )
182+ . map_or ( Position :: first_child_of ( adt_src. syntax ( ) ) , Position :: before) ;
183+
184+ editor. insert_all (
185+ after_attrs_and_comments,
186+ vec ! [
187+ derive. syntax( ) . syntax_element( ) ,
188+ make:: tokens:: whitespace( & format!( "\n {indent}" ) ) . syntax_element( ) ,
189+ ] ,
190+ ) ;
185191 }
186- edit. add_file_edits ( file_id, editor) ;
192+ edit. add_file_edits ( file_id. file_id ( ctx . db ( ) ) , editor) ;
187193 }
188194 } ,
189195 )
@@ -200,31 +206,32 @@ struct DeriveItem {
200206impl DeriveItem {
201207 fn from_path (
202208 ctx : & AssistContext < ' _ > ,
203- ty : & hir:: Type ,
209+ ty : & hir:: Type < ' _ > ,
204210 current_crate : hir:: Crate ,
205211 derive_macro : hir:: Macro ,
206212 name : String ,
207213 ) -> Option < Self > {
208- if derive_macro. kind ( ctx. db ( ) ) != hir:: MacroKind :: Derive {
209- return None ;
214+ match derive_macro. kind ( ctx. db ( ) ) {
215+ hir:: MacroKind :: Derive | hir:: MacroKind :: DeriveBuiltIn => { }
216+ _ => return None ,
210217 }
211218
212219 // Try to find a trait with the same name as the derive macro, which the type implements.
213220 let maybe_trait = items_locator:: items_with_name (
214- & ctx. sema ,
221+ ctx. db ( ) ,
215222 current_crate,
216223 NameToImport :: exact_case_sensitive ( name) ,
217224 items_locator:: AssocSearchMode :: Exclude ,
218225 )
219- . find_map ( |item| item. as_module_def ( ) ? . as_trait ( ) )
226+ . find_map ( |( item, _ ) | item. into_module_def ( ) . as_trait ( ) )
220227 . filter ( |trait_| ty. impls_trait ( ctx. db ( ) , * trait_, & [ ] ) ) ;
221228 Some ( DeriveItem { derive_macro, maybe_trait } )
222229 }
223230
224231 fn implemented_by ( & self , ctx : & AssistContext < ' _ > , adt : & hir:: Adt , src : & ast:: Adt ) -> bool {
225232 // Check if the type already has the derive attribute.
226233 adt. attrs ( ctx. db ( ) )
227- . by_key ( & hir:: sym:: derive)
234+ . by_key ( hir:: sym:: derive)
228235 . attrs ( )
229236 . filter_map ( |attr| attr. parse_path_comma_token_tree ( ctx. db ( ) ) )
230237 . flatten ( )
@@ -280,11 +287,7 @@ fn derive_targets(
280287 . cloned ( )
281288 . collect ( ) ;
282289
283- if derives. is_empty ( ) {
284- None
285- } else {
286- Some ( ( src, derives) )
287- }
290+ if derives. is_empty ( ) { None } else { Some ( ( src, derives) ) }
288291}
289292
290293fn field_types_to_derive (
0 commit comments