@@ -5,12 +5,12 @@ use syntax::{
5
5
SyntaxKind :: WHITESPACE ,
6
6
T ,
7
7
ast:: { self , AstNode , HasName , make} ,
8
- ted :: { self , Position } ,
8
+ syntax_editor :: { Position , SyntaxEditor } ,
9
9
} ;
10
10
11
11
use crate :: {
12
12
AssistConfig , AssistId ,
13
- assist_context:: { AssistContext , Assists , SourceChangeBuilder } ,
13
+ assist_context:: { AssistContext , Assists } ,
14
14
utils:: {
15
15
DefaultMethods , IgnoreAssocItems , add_trait_assoc_items_to_impl, filter_assoc_items,
16
16
gen_trait_fn_body, generate_trait_impl,
@@ -126,9 +126,9 @@ fn add_assist(
126
126
let label = format ! ( "Convert to manual `impl {replace_trait_path} for {annotated_name}`" ) ;
127
127
128
128
acc. add ( AssistId :: refactor ( "replace_derive_with_manual_impl" ) , label, target, |builder| {
129
- let insert_after = ted :: Position :: after ( builder . make_mut ( adt. clone ( ) ) . syntax ( ) ) ;
129
+ let insert_after = Position :: after ( adt. syntax ( ) ) ;
130
130
let impl_is_unsafe = trait_. map ( |s| s. is_unsafe ( ctx. db ( ) ) ) . unwrap_or ( false ) ;
131
- let impl_def_with_items = impl_def_from_trait (
131
+ let impl_def = impl_def_from_trait (
132
132
& ctx. sema ,
133
133
ctx. config ,
134
134
adt,
@@ -137,39 +137,23 @@ fn add_assist(
137
137
replace_trait_path,
138
138
impl_is_unsafe,
139
139
) ;
140
- update_attribute ( builder, old_derives, old_tree, old_trait_path, attr) ;
141
140
142
- let trait_path = make:: ty_path ( replace_trait_path. clone ( ) ) ;
143
-
144
- match ( ctx. config . snippet_cap , impl_def_with_items) {
145
- ( None , None ) => {
146
- let impl_def = generate_trait_impl ( impl_is_unsafe, adt, trait_path) ;
141
+ let mut editor = builder. make_editor ( attr. syntax ( ) ) ;
142
+ update_attribute ( & mut editor, old_derives, old_tree, old_trait_path, attr) ;
147
143
148
- ted:: insert_all (
149
- insert_after,
150
- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
151
- ) ;
152
- }
153
- ( None , Some ( ( impl_def, _) ) ) => {
154
- ted:: insert_all (
155
- insert_after,
156
- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
157
- ) ;
158
- }
159
- ( Some ( cap) , None ) => {
160
- let impl_def = generate_trait_impl ( impl_is_unsafe, adt, trait_path) ;
144
+ let trait_path = make:: ty_path ( replace_trait_path. clone ( ) ) ;
161
145
162
- if let Some ( l_curly) = impl_def. assoc_item_list ( ) . and_then ( |it| it. l_curly_token ( ) )
163
- {
164
- builder. add_tabstop_after_token ( cap, l_curly) ;
165
- }
146
+ let ( impl_def, first_assoc_item) = if let Some ( impl_def) = impl_def {
147
+ (
148
+ impl_def. clone ( ) ,
149
+ impl_def. assoc_item_list ( ) . and_then ( |list| list. assoc_items ( ) . next ( ) ) ,
150
+ )
151
+ } else {
152
+ ( generate_trait_impl ( impl_is_unsafe, adt, trait_path) , None )
153
+ } ;
166
154
167
- ted:: insert_all (
168
- insert_after,
169
- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
170
- ) ;
171
- }
172
- ( Some ( cap) , Some ( ( impl_def, first_assoc_item) ) ) => {
155
+ if let Some ( cap) = ctx. config . snippet_cap {
156
+ if let Some ( first_assoc_item) = first_assoc_item {
173
157
if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item
174
158
&& let Some ( m) = func. syntax ( ) . descendants ( ) . find_map ( ast:: MacroCall :: cast)
175
159
&& m. syntax ( ) . text ( ) == "todo!()"
@@ -180,13 +164,18 @@ fn add_assist(
180
164
// If we haven't already added a snippet, add a tabstop before the generated function
181
165
builder. add_tabstop_before ( cap, first_assoc_item) ;
182
166
}
183
-
184
- ted:: insert_all (
185
- insert_after,
186
- vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
187
- ) ;
167
+ } else if let Some ( l_curly) =
168
+ impl_def. assoc_item_list ( ) . and_then ( |it| it. l_curly_token ( ) )
169
+ {
170
+ builder. add_tabstop_after_token ( cap, l_curly) ;
188
171
}
189
- } ;
172
+ }
173
+
174
+ editor. insert_all (
175
+ insert_after,
176
+ vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
177
+ ) ;
178
+ builder. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
190
179
} )
191
180
}
192
181
@@ -198,7 +187,7 @@ fn impl_def_from_trait(
198
187
trait_ : Option < hir:: Trait > ,
199
188
trait_path : & ast:: Path ,
200
189
impl_is_unsafe : bool ,
201
- ) -> Option < ( ast:: Impl , ast :: AssocItem ) > {
190
+ ) -> Option < ast:: Impl > {
202
191
let trait_ = trait_?;
203
192
let target_scope = sema. scope ( annotated_name. syntax ( ) ) ?;
204
193
@@ -217,23 +206,25 @@ fn impl_def_from_trait(
217
206
}
218
207
let impl_def = generate_trait_impl ( impl_is_unsafe, adt, make:: ty_path ( trait_path. clone ( ) ) ) ;
219
208
220
- let first_assoc_item =
209
+ let _ =
221
210
add_trait_assoc_items_to_impl ( sema, config, & trait_items, trait_, & impl_def, & target_scope) ;
222
-
211
+ let impl_def = impl_def. clone_subtree ( ) ;
212
+ let mut editor = SyntaxEditor :: new ( impl_def. syntax ( ) . clone ( ) ) ;
213
+ let first_assoc_item = impl_def. assoc_item_list ( ) . and_then ( |item| item. assoc_items ( ) . next ( ) ) ?;
223
214
// Generate a default `impl` function body for the derived trait.
224
215
if let ast:: AssocItem :: Fn ( ref func) = first_assoc_item {
225
216
if let Some ( body) = gen_trait_fn_body ( func, trait_path, adt, None )
226
217
&& let Some ( func_body) = func. body ( )
227
218
{
228
- ted :: replace ( func_body. syntax ( ) , body. syntax ( ) ) ;
219
+ editor . replace ( func_body. syntax ( ) , body. syntax ( ) ) ;
229
220
}
230
221
} ;
231
-
232
- Some ( ( impl_def, first_assoc_item ) )
222
+ let impl_def = ast :: Impl :: cast ( editor . finish ( ) . new_root ( ) . clone ( ) ) ? ;
223
+ Some ( impl_def)
233
224
}
234
225
235
226
fn update_attribute (
236
- builder : & mut SourceChangeBuilder ,
227
+ editor : & mut SyntaxEditor ,
237
228
old_derives : & [ ast:: Path ] ,
238
229
old_tree : & ast:: TokenTree ,
239
230
old_trait_path : & ast:: Path ,
@@ -246,8 +237,6 @@ fn update_attribute(
246
237
let has_more_derives = !new_derives. is_empty ( ) ;
247
238
248
239
if has_more_derives {
249
- let old_tree = builder. make_mut ( old_tree. clone ( ) ) ;
250
-
251
240
// Make the paths into flat lists of tokens in a vec
252
241
let tt = new_derives. iter ( ) . map ( |path| path. syntax ( ) . clone ( ) ) . map ( |node| {
253
242
node. descendants_with_tokens ( )
@@ -262,18 +251,17 @@ fn update_attribute(
262
251
let tt = tt. collect :: < Vec < _ > > ( ) ;
263
252
264
253
let new_tree = make:: token_tree ( T ! [ '(' ] , tt) . clone_for_update ( ) ;
265
- ted :: replace ( old_tree. syntax ( ) , new_tree. syntax ( ) ) ;
254
+ editor . replace ( old_tree. syntax ( ) , new_tree. syntax ( ) ) ;
266
255
} else {
267
256
// Remove the attr and any trailing whitespace
268
- let attr = builder. make_mut ( attr. clone ( ) ) ;
269
257
270
258
if let Some ( line_break) =
271
259
attr. syntax ( ) . next_sibling_or_token ( ) . filter ( |t| t. kind ( ) == WHITESPACE )
272
260
{
273
- ted :: remove ( line_break)
261
+ editor . delete ( line_break)
274
262
}
275
263
276
- ted :: remove ( attr. syntax ( ) )
264
+ editor . delete ( attr. syntax ( ) )
277
265
}
278
266
}
279
267
0 commit comments