11use crate :: assist_context:: { AssistContext , Assists } ;
22use ide_db:: assists:: AssistId ;
33use 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 ,
611} ;
712
813// NOTES :
@@ -44,7 +49,7 @@ use syntax::{
4449// };
4550// }
4651//
47- // trait ${0:TraitName }<const N: usize> {
52+ // trait ${0:NewTrait }<const N: usize> {
4853// // Used as an associated constant.
4954// const CONST_ASSOC: usize = N * 4;
5055//
@@ -53,7 +58,7 @@ use syntax::{
5358// const_maker! {i32, 7}
5459// }
5560//
56- // impl<const N: usize> ${0:TraitName }<N> for Foo<N> {
61+ // impl<const N: usize> ${0:NewTrait }<N> for Foo<N> {
5762// // Used as an associated constant.
5863// const CONST_ASSOC: usize = N * 4;
5964//
@@ -94,8 +99,10 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
9499 "Generate trait from impl" ,
95100 impl_ast. syntax ( ) . text_range ( ) ,
96101 |builder| {
102+ let impl_ast = builder. make_mut ( impl_ast) ;
97103 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) ;
99106
100107 trait_items. assoc_items ( ) . for_each ( |item| {
101108 strip_body ( & item) ;
@@ -112,46 +119,42 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
112119 impl_ast. generic_param_list ( ) ,
113120 impl_ast. where_clause ( ) ,
114121 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 ( ) ;
116127
117128 // 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+ }
130139
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+ ) ;
146150
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( ) ] ,
151156 ) ;
152157 }
153-
154- builder. replace ( assoc_items. syntax ( ) . text_range ( ) , impl_items. to_string ( ) ) ;
155158 } ,
156159 ) ;
157160
@@ -160,23 +163,8 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
160163
161164/// `E0449` Trait items always share the visibility of their trait
162165fn 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 ) ;
180168 }
181169}
182170
@@ -404,12 +392,12 @@ impl<const N: usize> F$0oo<N> {
404392 r#"
405393struct Foo<const N: usize>([i32; N]);
406394
407- trait ${0:TraitName }<const N: usize> {
395+ trait ${0:NewTrait }<const N: usize> {
408396 // Used as an associated constant.
409397 const CONST: usize = N * 4;
410398}
411399
412- impl<const N: usize> ${0:TraitName }<N> for Foo<N> {
400+ impl<const N: usize> ${0:NewTrait }<N> for Foo<N> {
413401 // Used as an associated constant.
414402 const CONST: usize = N * 4;
415403}
0 commit comments