1
1
use crate :: assist_context:: { AssistContext , Assists } ;
2
2
use ide_db:: assists:: AssistId ;
3
3
use syntax:: {
4
- ast:: { self , edit:: IndentLevel , make, HasGenericParams , HasVisibility } ,
5
- ted, AstNode , SyntaxKind ,
4
+ ast:: {
5
+ self ,
6
+ edit_in_place:: { HasVisibilityEdit , Indent } ,
7
+ make, HasGenericParams , HasName ,
8
+ } ,
9
+ ted:: { self , Position } ,
10
+ AstNode , SyntaxKind , T ,
6
11
} ;
7
12
8
13
// NOTES :
@@ -44,7 +49,7 @@ use syntax::{
44
49
// };
45
50
// }
46
51
//
47
- // trait ${0:TraitName }<const N: usize> {
52
+ // trait ${0:NewTrait }<const N: usize> {
48
53
// // Used as an associated constant.
49
54
// const CONST_ASSOC: usize = N * 4;
50
55
//
@@ -53,7 +58,7 @@ use syntax::{
53
58
// const_maker! {i32, 7}
54
59
// }
55
60
//
56
- // impl<const N: usize> ${0:TraitName }<N> for Foo<N> {
61
+ // impl<const N: usize> ${0:NewTrait }<N> for Foo<N> {
57
62
// // Used as an associated constant.
58
63
// const CONST_ASSOC: usize = N * 4;
59
64
//
@@ -94,8 +99,10 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
94
99
"Generate trait from impl" ,
95
100
impl_ast. syntax ( ) . text_range ( ) ,
96
101
|builder| {
102
+ let impl_ast = builder. make_mut ( impl_ast) ;
97
103
let trait_items = assoc_items. clone_for_update ( ) ;
98
- let impl_items = assoc_items. clone_for_update ( ) ;
104
+ let impl_items = builder. make_mut ( assoc_items) ;
105
+ let impl_name = builder. make_mut ( impl_name) ;
99
106
100
107
trait_items. assoc_items ( ) . for_each ( |item| {
101
108
strip_body ( & item) ;
@@ -112,46 +119,42 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
112
119
impl_ast. generic_param_list ( ) ,
113
120
impl_ast. where_clause ( ) ,
114
121
trait_items,
115
- ) ;
122
+ )
123
+ . clone_for_update ( ) ;
124
+
125
+ let trait_name = trait_ast. name ( ) . expect ( "new trait should have a name" ) ;
126
+ let trait_name_ref = make:: name_ref ( & trait_name. to_string ( ) ) . clone_for_update ( ) ;
116
127
117
128
// Change `impl Foo` to `impl NewTrait for Foo`
118
- let arg_list = if let Some ( genpars) = impl_ast. generic_param_list ( ) {
119
- genpars. to_generic_args ( ) . to_string ( )
120
- } else {
121
- "" . to_owned ( )
122
- } ;
123
-
124
- if let Some ( snippet_cap) = ctx. config . snippet_cap {
125
- builder. replace_snippet (
126
- snippet_cap,
127
- impl_name. syntax ( ) . text_range ( ) ,
128
- format ! ( "${{0:TraitName}}{} for {}" , arg_list, impl_name) ,
129
- ) ;
129
+ let mut elements = vec ! [
130
+ trait_name_ref. syntax( ) . clone( ) . into( ) ,
131
+ make:: tokens:: single_space( ) . into( ) ,
132
+ make:: token( T ![ for ] ) . into( ) ,
133
+ ] ;
134
+
135
+ if let Some ( params) = impl_ast. generic_param_list ( ) {
136
+ let gen_args = & params. to_generic_args ( ) . clone_for_update ( ) ;
137
+ elements. insert ( 1 , gen_args. syntax ( ) . clone ( ) . into ( ) ) ;
138
+ }
130
139
131
- // Insert trait before TraitImpl
132
- builder. insert_snippet (
133
- snippet_cap,
134
- impl_ast. syntax ( ) . text_range ( ) . start ( ) ,
135
- format ! (
136
- "{}\n \n {}" ,
137
- trait_ast. to_string( ) . replace( "NewTrait" , "${0:TraitName}" ) ,
138
- IndentLevel :: from_node( impl_ast. syntax( ) )
139
- ) ,
140
- ) ;
141
- } else {
142
- builder. replace (
143
- impl_name. syntax ( ) . text_range ( ) ,
144
- format ! ( "NewTrait{} for {}" , arg_list, impl_name) ,
145
- ) ;
140
+ ted:: insert_all ( Position :: before ( impl_name. syntax ( ) ) , elements) ;
141
+
142
+ // Insert trait before TraitImpl
143
+ ted:: insert_all_raw (
144
+ Position :: before ( impl_ast. syntax ( ) ) ,
145
+ vec ! [
146
+ trait_ast. syntax( ) . clone( ) . into( ) ,
147
+ make:: tokens:: whitespace( & format!( "\n \n {}" , impl_ast. indent_level( ) ) ) . into( ) ,
148
+ ] ,
149
+ ) ;
146
150
147
- // Insert trait before TraitImpl
148
- builder. insert (
149
- impl_ast. syntax ( ) . text_range ( ) . start ( ) ,
150
- format ! ( "{}\n \n {}" , trait_ast, IndentLevel :: from_node( impl_ast. syntax( ) ) ) ,
151
+ // Link the trait name & trait ref names together as a placeholder snippet group
152
+ if let Some ( cap) = ctx. config . snippet_cap {
153
+ builder. add_placeholder_snippet_group (
154
+ cap,
155
+ vec ! [ trait_name. syntax( ) . clone( ) , trait_name_ref. syntax( ) . clone( ) ] ,
151
156
) ;
152
157
}
153
-
154
- builder. replace ( assoc_items. syntax ( ) . text_range ( ) , impl_items. to_string ( ) ) ;
155
158
} ,
156
159
) ;
157
160
@@ -160,23 +163,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
160
163
161
164
/// `E0449` Trait items always share the visibility of their trait
162
165
fn remove_items_visibility ( item : & ast:: AssocItem ) {
163
- match item {
164
- ast:: AssocItem :: Const ( c) => {
165
- if let Some ( vis) = c. visibility ( ) {
166
- ted:: remove ( vis. syntax ( ) ) ;
167
- }
168
- }
169
- ast:: AssocItem :: Fn ( f) => {
170
- if let Some ( vis) = f. visibility ( ) {
171
- ted:: remove ( vis. syntax ( ) ) ;
172
- }
173
- }
174
- ast:: AssocItem :: TypeAlias ( t) => {
175
- if let Some ( vis) = t. visibility ( ) {
176
- ted:: remove ( vis. syntax ( ) ) ;
177
- }
178
- }
179
- _ => ( ) ,
166
+ if let Some ( has_vis) = ast:: AnyHasVisibility :: cast ( item. syntax ( ) . clone ( ) ) {
167
+ has_vis. set_visibility ( None ) ;
180
168
}
181
169
}
182
170
@@ -404,12 +392,12 @@ impl<const N: usize> F$0oo<N> {
404
392
r#"
405
393
struct Foo<const N: usize>([i32; N]);
406
394
407
- trait ${0:TraitName }<const N: usize> {
395
+ trait ${0:NewTrait }<const N: usize> {
408
396
// Used as an associated constant.
409
397
const CONST: usize = N * 4;
410
398
}
411
399
412
- impl<const N: usize> ${0:TraitName }<N> for Foo<N> {
400
+ impl<const N: usize> ${0:NewTrait }<N> for Foo<N> {
413
401
// Used as an associated constant.
414
402
const CONST: usize = N * 4;
415
403
}
0 commit comments