3
3
use std:: ops;
4
4
5
5
pub ( 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
+ } ;
8
11
use stdx:: format_to;
9
12
use syntax:: {
10
13
ast:: {
@@ -91,30 +94,21 @@ pub fn filter_assoc_items(
91
94
sema : & Semantics < ' _ , RootDatabase > ,
92
95
items : & [ hir:: AssocItem ] ,
93
96
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
106
99
. iter ( )
107
100
// 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 ) ,
113
107
} ;
114
108
Some ( item)
115
109
} )
116
110
. filter ( has_def_name)
117
- . filter ( |it| match it {
111
+ . filter ( |it| match & it . value {
118
112
ast:: AssocItem :: Fn ( def) => matches ! (
119
113
( default_methods, def. body( ) ) ,
120
114
( DefaultMethods :: Only , Some ( _) ) | ( DefaultMethods :: No , None )
@@ -125,26 +119,55 @@ pub fn filter_assoc_items(
125
119
) ,
126
120
_ => default_methods == DefaultMethods :: No ,
127
121
} )
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
+ }
129
133
}
130
134
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.
131
139
pub fn add_trait_assoc_items_to_impl (
132
140
sema : & Semantics < ' _ , RootDatabase > ,
133
- items : Vec < ast:: AssocItem > ,
141
+ original_items : & [ InFile < ast:: AssocItem > ] ,
134
142
trait_ : hir:: Trait ,
135
143
impl_ : & ast:: Impl ,
136
144
target_scope : hir:: SemanticsScope < ' _ > ,
137
145
) -> 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
-
142
146
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
148
171
} ) ;
149
172
150
173
let assoc_item_list = impl_. get_or_create_assoc_item_list ( ) ;
0 commit comments