1
1
use ide_db:: { famous_defs:: FamousDefs , traits:: resolve_target_trait} ;
2
2
use syntax:: {
3
3
AstNode , T ,
4
- ast:: { self , edit_in_place:: Indent , make} ,
5
- ted,
4
+ ast:: {
5
+ self , HasAttrs , HasGenericParams , HasName ,
6
+ edit:: { AstNodeEdit , IndentLevel } ,
7
+ make,
8
+ } ,
9
+ syntax_editor:: { Element , Position , SyntaxEditor } ,
6
10
} ;
7
11
8
12
use crate :: { AssistContext , AssistId , Assists } ;
@@ -45,10 +49,10 @@ use crate::{AssistContext, AssistId, Assists};
45
49
// }
46
50
// ```
47
51
pub ( crate ) fn generate_mut_trait_impl ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
48
- let impl_def = ctx. find_node_at_offset :: < ast:: Impl > ( ) ?. clone_for_update ( ) ;
52
+ let impl_def = ctx. find_node_at_offset :: < ast:: Impl > ( ) ?;
49
53
let indent = impl_def. indent_level ( ) ;
50
54
51
- let ast:: Type :: PathType ( path) = impl_def. trait_ ( ) ? else {
55
+ let ast:: Type :: PathType ( path) = impl_def. trait_ ( ) ?. clone_subtree ( ) else {
52
56
return None ;
53
57
} ;
54
58
let trait_name = path. path ( ) ?. segment ( ) ?. name_ref ( ) ?;
@@ -59,75 +63,97 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
59
63
let trait_ = resolve_target_trait ( & ctx. sema , & impl_def) ?;
60
64
let trait_new = get_trait_mut ( & trait_, famous) ?;
61
65
62
- // Index -> IndexMut
63
- ted:: replace ( trait_name. syntax ( ) , make:: name_ref ( trait_new) . clone_for_update ( ) . syntax ( ) ) ;
66
+ let new_trait_type = {
67
+ let mut trait_type_editor = SyntaxEditor :: new ( path. syntax ( ) . clone ( ) ) ;
68
+ trait_type_editor
69
+ . replace ( trait_name. syntax ( ) , make:: name_ref ( trait_new) . syntax ( ) . clone_for_update ( ) ) ;
70
+ ast:: PathType :: cast ( trait_type_editor. finish ( ) . new_root ( ) . clone ( ) ) ?
71
+ } ;
64
72
65
- // index -> index_mut
66
- let ( trait_method_name, new_trait_method_name) = impl_def
73
+ let new_trait_method_name = impl_def
67
74
. syntax ( )
68
75
. descendants ( )
69
76
. filter_map ( ast:: Name :: cast)
70
77
. find_map ( process_method_name) ?;
71
- ted:: replace (
72
- trait_method_name. syntax ( ) ,
73
- make:: name ( new_trait_method_name) . clone_for_update ( ) . syntax ( ) ,
74
- ) ;
75
-
76
- if let Some ( type_alias) = impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: TypeAlias :: cast) {
77
- ted:: remove ( type_alias. syntax ( ) ) ;
78
- }
79
-
80
- // &self -> &mut self
81
- let mut_self_param = make:: mut_self_param ( ) ;
82
- let self_param: ast:: SelfParam =
83
- impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: SelfParam :: cast) ?;
84
- ted:: replace ( self_param. syntax ( ) , mut_self_param. clone_for_update ( ) . syntax ( ) ) ;
85
-
86
- // &Self::Output -> &mut Self::Output
87
- let ret_type = impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: RetType :: cast) ?;
88
- let new_ret_type = process_ret_type ( & ret_type) ?;
89
- ted:: replace ( ret_type. syntax ( ) , make:: ret_type ( new_ret_type) . clone_for_update ( ) . syntax ( ) ) ;
90
78
91
79
let fn_ = impl_def. assoc_item_list ( ) ?. assoc_items ( ) . find_map ( |it| match it {
92
80
ast:: AssocItem :: Fn ( f) => Some ( f) ,
93
81
_ => None ,
94
82
} ) ?;
95
- let _ = process_ref_mut ( & fn_) ;
96
-
97
- let assoc_list = make:: assoc_item_list ( None ) . clone_for_update ( ) ;
98
- ted:: replace ( impl_def. assoc_item_list ( ) ?. syntax ( ) , assoc_list. syntax ( ) ) ;
99
- impl_def. get_or_create_assoc_item_list ( ) . add_item ( syntax:: ast:: AssocItem :: Fn ( fn_) ) ;
83
+ let fn_ = ast:: AssocItem :: Fn ( generate_fn ( & fn_, new_trait_method_name) ?) . indent ( IndentLevel ( 1 ) ) ;
84
+
85
+ let assoc_list = make:: assoc_item_list ( Some ( vec ! [ fn_] ) ) ;
86
+ let new_impl = make:: impl_trait (
87
+ impl_def. attrs ( ) ,
88
+ impl_def. unsafe_token ( ) . is_some ( ) ,
89
+ impl_def. generic_param_list ( ) ,
90
+ None ,
91
+ None ,
92
+ None ,
93
+ false ,
94
+ ast:: Type :: PathType ( new_trait_type) ,
95
+ impl_def. self_ty ( ) ?,
96
+ impl_def. where_clause ( ) ,
97
+ None ,
98
+ Some ( assoc_list) ,
99
+ )
100
+ . indent ( indent) ;
100
101
101
102
let target = impl_def. syntax ( ) . text_range ( ) ;
102
103
acc. add (
103
104
AssistId :: generate ( "generate_mut_trait_impl" ) ,
104
105
format ! ( "Generate `{trait_new}` impl from this `{trait_name}` trait" ) ,
105
106
target,
106
107
|edit| {
107
- edit. insert (
108
- target . start ( ) ,
109
- if ctx . config . snippet_cap . is_some ( ) {
110
- format ! ( "$0{impl_def} \n \n {indent}" )
111
- } else {
112
- format ! ( "{impl_def} \n \n {indent}" )
113
- } ,
108
+ let mut editor = edit. make_editor ( impl_def . syntax ( ) ) ;
109
+ editor . insert_all (
110
+ Position :: before ( impl_def . syntax ( ) ) ,
111
+ vec ! [
112
+ new_impl . syntax ( ) . syntax_element ( ) ,
113
+ make :: tokens :: whitespace ( & format!( "\n \n {indent}" ) ) . syntax_element ( ) ,
114
+ ] ,
114
115
) ;
116
+ if let Some ( cap) = ctx. config . snippet_cap {
117
+ let tabstop_before = edit. make_tabstop_before ( cap) ;
118
+ editor. add_annotation ( new_impl. syntax ( ) , tabstop_before) ;
119
+ }
120
+ edit. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
115
121
} ,
116
122
)
117
123
}
118
124
119
- fn process_ref_mut ( fn_ : & ast:: Fn ) -> Option < ( ) > {
125
+ fn generate_fn ( fn_ : & ast:: Fn , new_method_name : & str ) -> Option < ast:: Fn > {
126
+ let fn_ = fn_. reset_indent ( ) . clone_subtree ( ) ;
127
+ let mut editor = SyntaxEditor :: new ( fn_. syntax ( ) . clone ( ) ) ;
128
+
129
+ // index -> index_mut
130
+ let fn_name = fn_. name ( ) ?;
131
+ let new_name = make:: name ( new_method_name) ;
132
+ editor. replace ( fn_name. syntax ( ) , new_name. syntax ( ) . clone_for_update ( ) ) ;
133
+
134
+ // &self -> &mut self
135
+ let self_param: ast:: SelfParam = fn_. syntax ( ) . descendants ( ) . find_map ( ast:: SelfParam :: cast) ?;
136
+ let mut_self_param = make:: mut_self_param ( ) ;
137
+ editor. replace ( self_param. syntax ( ) , mut_self_param. syntax ( ) . clone_for_update ( ) ) ;
138
+
139
+ // &Self::Output -> &mut Self::Output
140
+ let ret_type = fn_. ret_type ( ) ?;
141
+ let new_ret_type = make:: ret_type ( process_ret_type ( & ret_type) ?) . clone_for_update ( ) ;
142
+ editor. replace ( ret_type. syntax ( ) , new_ret_type. syntax ( ) ) ;
143
+
120
144
let expr = fn_. body ( ) ?. tail_expr ( ) ?;
121
145
match & expr {
122
146
ast:: Expr :: RefExpr ( ref_expr) if ref_expr. mut_token ( ) . is_none ( ) => {
123
- ted :: insert_all_raw (
124
- ted :: Position :: after ( ref_expr. amp_token ( ) ?) ,
147
+ editor . insert_all (
148
+ Position :: after ( ref_expr. amp_token ( ) ?) ,
125
149
vec ! [ make:: token( T ![ mut ] ) . into( ) , make:: tokens:: whitespace( " " ) . into( ) ] ,
126
150
) ;
127
151
}
128
152
_ => { }
129
153
}
130
- None
154
+
155
+ let fn_ = editor. finish ( ) . new_root ( ) . clone ( ) ;
156
+ ast:: Fn :: cast ( fn_)
131
157
}
132
158
133
159
fn get_trait_mut ( apply_trait : & hir:: Trait , famous : FamousDefs < ' _ , ' _ > ) -> Option < & ' static str > {
@@ -147,15 +173,15 @@ fn get_trait_mut(apply_trait: &hir::Trait, famous: FamousDefs<'_, '_>) -> Option
147
173
None
148
174
}
149
175
150
- fn process_method_name ( name : ast:: Name ) -> Option < ( ast :: Name , & ' static str ) > {
176
+ fn process_method_name ( name : ast:: Name ) -> Option < & ' static str > {
151
177
let new_name = match & * name. text ( ) {
152
178
"index" => "index_mut" ,
153
179
"as_ref" => "as_mut" ,
154
180
"borrow" => "borrow_mut" ,
155
181
"deref" => "deref_mut" ,
156
182
_ => return None ,
157
183
} ;
158
- Some ( ( name , new_name) )
184
+ Some ( new_name)
159
185
}
160
186
161
187
fn process_ret_type ( ref_ty : & ast:: RetType ) -> Option < ast:: Type > {
@@ -228,7 +254,9 @@ impl<T> core::ops::Index$0<Axis> for [T; 3] where T: Copy {
228
254
r#"
229
255
pub enum Axis { X = 0, Y = 1, Z = 2 }
230
256
231
- $0impl<T> core::ops::IndexMut<Axis> for [T; 3] where T: Copy {
257
+ $0impl<T> core::ops::IndexMut<Axis> for [T; 3]
258
+ where T: Copy
259
+ {
232
260
fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
233
261
let var_name = &self[index as usize];
234
262
var_name
@@ -332,7 +360,9 @@ mod foo {
332
360
mod foo {
333
361
pub enum Axis { X = 0, Y = 1, Z = 2 }
334
362
335
- $0impl<T> core::ops::IndexMut<Axis> for [T; 3] where T: Copy {
363
+ $0impl<T> core::ops::IndexMut<Axis> for [T; 3]
364
+ where T: Copy
365
+ {
336
366
fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
337
367
let var_name = &self[index as usize];
338
368
var_name
@@ -375,7 +405,9 @@ mod foo {
375
405
mod bar {
376
406
pub enum Axis { X = 0, Y = 1, Z = 2 }
377
407
378
- $0impl<T> core::ops::IndexMut<Axis> for [T; 3] where T: Copy {
408
+ $0impl<T> core::ops::IndexMut<Axis> for [T; 3]
409
+ where T: Copy
410
+ {
379
411
fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
380
412
let var_name = &self[index as usize];
381
413
var_name
0 commit comments