33use std:: ops;
44
55pub ( crate ) use gen_trait_fn_body:: gen_trait_fn_body;
6- use hir:: { db:: HirDatabase , HirDisplay , Semantics } ;
7- use ide_db:: { famous_defs:: FamousDefs , path_transform:: PathTransform , RootDatabase , SnippetCap } ;
6+ use hir:: { db:: HirDatabase , HirDisplay , InFile , Semantics } ;
7+ use ide_db:: {
8+ famous_defs:: FamousDefs , path_transform:: PathTransform ,
9+ syntax_helpers:: insert_whitespace_into_node:: insert_ws_into, RootDatabase , SnippetCap ,
10+ } ;
811use stdx:: format_to;
912use syntax:: {
1013 ast:: {
@@ -91,30 +94,21 @@ pub fn filter_assoc_items(
9194 sema : & Semantics < ' _ , RootDatabase > ,
9295 items : & [ hir:: AssocItem ] ,
9396 default_methods : DefaultMethods ,
94- ) -> Vec < ast:: AssocItem > {
95- fn has_def_name ( item : & ast:: AssocItem ) -> bool {
96- match item {
97- ast:: AssocItem :: Fn ( def) => def. name ( ) ,
98- ast:: AssocItem :: TypeAlias ( def) => def. name ( ) ,
99- ast:: AssocItem :: Const ( def) => def. name ( ) ,
100- ast:: AssocItem :: MacroCall ( _) => None ,
101- }
102- . is_some ( )
103- }
104-
105- items
97+ ) -> Vec < InFile < ast:: AssocItem > > {
98+ return items
10699 . iter ( )
107100 // Note: This throws away items with no source.
108- . filter_map ( |& i| {
109- let item = match i {
110- hir:: AssocItem :: Function ( i) => ast:: AssocItem :: Fn ( sema. source ( i) ?. value ) ,
111- hir:: AssocItem :: TypeAlias ( i) => ast:: AssocItem :: TypeAlias ( sema. source ( i) ?. value ) ,
112- hir:: AssocItem :: Const ( i) => ast:: AssocItem :: Const ( sema. source ( i) ?. value ) ,
101+ . copied ( )
102+ . filter_map ( |assoc_item| {
103+ let item = match assoc_item {
104+ hir:: AssocItem :: Function ( it) => sema. source ( it) ?. map ( ast:: AssocItem :: Fn ) ,
105+ hir:: AssocItem :: TypeAlias ( it) => sema. source ( it) ?. map ( ast:: AssocItem :: TypeAlias ) ,
106+ hir:: AssocItem :: Const ( it) => sema. source ( it) ?. map ( ast:: AssocItem :: Const ) ,
113107 } ;
114108 Some ( item)
115109 } )
116110 . filter ( has_def_name)
117- . filter ( |it| match it {
111+ . filter ( |it| match & it . value {
118112 ast:: AssocItem :: Fn ( def) => matches ! (
119113 ( default_methods, def. body( ) ) ,
120114 ( DefaultMethods :: Only , Some ( _) ) | ( DefaultMethods :: No , None )
@@ -125,26 +119,55 @@ pub fn filter_assoc_items(
125119 ) ,
126120 _ => default_methods == DefaultMethods :: No ,
127121 } )
128- . collect :: < Vec < _ > > ( )
122+ . collect ( ) ;
123+
124+ fn has_def_name ( item : & InFile < ast:: AssocItem > ) -> bool {
125+ match & item. value {
126+ ast:: AssocItem :: Fn ( def) => def. name ( ) ,
127+ ast:: AssocItem :: TypeAlias ( def) => def. name ( ) ,
128+ ast:: AssocItem :: Const ( def) => def. name ( ) ,
129+ ast:: AssocItem :: MacroCall ( _) => None ,
130+ }
131+ . is_some ( )
132+ }
129133}
130134
135+ /// Given `original_items` retrieved from the trait definition (usually by
136+ /// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it,
137+ /// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got
138+ /// inserted.
131139pub fn add_trait_assoc_items_to_impl (
132140 sema : & Semantics < ' _ , RootDatabase > ,
133- items : Vec < ast:: AssocItem > ,
141+ original_items : & [ InFile < ast:: AssocItem > ] ,
134142 trait_ : hir:: Trait ,
135143 impl_ : & ast:: Impl ,
136144 target_scope : hir:: SemanticsScope < ' _ > ,
137145) -> ast:: AssocItem {
138- let source_scope = sema. scope_for_def ( trait_) ;
139-
140- let transform = PathTransform :: trait_impl ( & target_scope, & source_scope, trait_, impl_. clone ( ) ) ;
141-
142146 let new_indent_level = IndentLevel :: from_node ( impl_. syntax ( ) ) + 1 ;
143- let items = items. into_iter ( ) . map ( |assoc_item| {
144- transform. apply ( assoc_item. syntax ( ) ) ;
145- assoc_item. remove_attrs_and_docs ( ) ;
146- assoc_item. reindent_to ( new_indent_level) ;
147- assoc_item
147+ let items = original_items. into_iter ( ) . map ( |InFile { file_id, value : original_item } | {
148+ let cloned_item = {
149+ if file_id. is_macro ( ) {
150+ if let Some ( formatted) =
151+ ast:: AssocItem :: cast ( insert_ws_into ( original_item. syntax ( ) . clone ( ) ) )
152+ {
153+ return formatted;
154+ } else {
155+ stdx:: never!( "formatted `AssocItem` could not be cast back to `AssocItem`" ) ;
156+ }
157+ }
158+ original_item. clone_for_update ( )
159+ } ;
160+
161+ if let Some ( source_scope) = sema. scope ( original_item. syntax ( ) ) {
162+ // FIXME: Paths in nested macros are not handled well. See
163+ // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test.
164+ let transform =
165+ PathTransform :: trait_impl ( & target_scope, & source_scope, trait_, impl_. clone ( ) ) ;
166+ transform. apply ( cloned_item. syntax ( ) ) ;
167+ }
168+ cloned_item. remove_attrs_and_docs ( ) ;
169+ cloned_item. reindent_to ( new_indent_level) ;
170+ cloned_item
148171 } ) ;
149172
150173 let assoc_item_list = impl_. get_or_create_assoc_item_list ( ) ;
0 commit comments