11use  either:: Either ; 
2+ use  hir:: FileRangeWrapper ; 
23use  ide_db:: defs:: { Definition ,  NameRefClass } ; 
4+ use  std:: ops:: RangeInclusive ; 
35use  syntax:: { 
4-     SyntaxKind ,  SyntaxNode , 
5-     ast:: { self ,  AstNode ,  HasAttrs ,  HasGenericParams ,  HasVisibility } , 
6-     match_ast,  ted, 
6+     SyntaxElement ,  SyntaxKind ,  SyntaxNode ,  T ,  TextSize , 
7+     ast:: { 
8+         self ,  AstNode ,  HasAttrs ,  HasGenericParams ,  HasVisibility ,  syntax_factory:: SyntaxFactory , 
9+     } , 
10+     match_ast, 
11+     syntax_editor:: { Element ,  Position ,  SyntaxEditor } , 
712} ; 
813
914use  crate :: { AssistContext ,  AssistId ,  Assists ,  assist_context:: SourceChangeBuilder } ; 
@@ -71,66 +76,63 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
7176        Either :: Right ( v)  => Either :: Right ( ctx. sema . to_def ( v) ?) , 
7277    } ; 
7378    let  target = strukt_or_variant. as_ref ( ) . either ( |s| s. syntax ( ) ,  |v| v. syntax ( ) ) . text_range ( ) ; 
74- 
79+      let  syntax = strukt_or_variant . as_ref ( ) . either ( |s| s . syntax ( ) ,  |v| v . syntax ( ) ) ; 
7580    acc. add ( 
7681        AssistId :: refactor_rewrite ( "convert_tuple_struct_to_named_struct" ) , 
7782        "Convert to named struct" , 
7883        target, 
7984        |edit| { 
8085            let  names = generate_names ( tuple_fields. fields ( ) ) ; 
8186            edit_field_references ( ctx,  edit,  tuple_fields. fields ( ) ,  & names) ; 
87+             let  mut  editor = edit. make_editor ( syntax) ; 
8288            edit_struct_references ( ctx,  edit,  strukt_def,  & names) ; 
83-             edit_struct_def ( ctx,  edit,  & strukt_or_variant,  tuple_fields,  names) ; 
89+             edit_struct_def ( & mut  editor,  & strukt_or_variant,  tuple_fields,  names) ; 
90+             edit. add_file_edits ( ctx. vfs_file_id ( ) ,  editor) ; 
8491        } , 
8592    ) 
8693} 
8794
8895fn  edit_struct_def ( 
89-     ctx :  & AssistContext < ' _ > , 
90-     edit :  & mut  SourceChangeBuilder , 
96+     editor :  & mut  SyntaxEditor , 
9197    strukt :  & Either < ast:: Struct ,  ast:: Variant > , 
9298    tuple_fields :  ast:: TupleFieldList , 
9399    names :  Vec < ast:: Name > , 
94100)  { 
95101    let  record_fields = tuple_fields. fields ( ) . zip ( names) . filter_map ( |( f,  name) | { 
96-         let  field = ast:: make:: record_field ( f. visibility ( ) ,  name,  f. ty ( ) ?) . clone_for_update ( ) ; 
97-         ted:: insert_all ( 
98-             ted:: Position :: first_child_of ( field. syntax ( ) ) , 
102+         let  field = ast:: make:: record_field ( f. visibility ( ) ,  name,  f. ty ( ) ?) ; 
103+         let  mut  field_editor = SyntaxEditor :: new ( field. syntax ( ) . clone ( ) ) ; 
104+         field_editor. insert_all ( 
105+             Position :: first_child_of ( field. syntax ( ) ) , 
99106            f. attrs ( ) . map ( |attr| attr. syntax ( ) . clone_subtree ( ) . clone_for_update ( ) . into ( ) ) . collect ( ) , 
100107        ) ; 
101-         Some ( field ) 
108+         ast :: RecordField :: cast ( field_editor . finish ( ) . new_root ( ) . clone ( ) ) 
102109    } ) ; 
103-     let  record_fields = ast:: make:: record_field_list ( record_fields) ; 
104-     let  tuple_fields_text_range = tuple_fields. syntax ( ) . text_range ( ) ; 
105- 
106-     edit. edit_file ( ctx. vfs_file_id ( ) ) ; 
110+     let  make = SyntaxFactory :: without_mappings ( ) ; 
111+     let  record_fields = make. record_field_list ( record_fields) ; 
112+     let  tuple_fields_before = Position :: before ( tuple_fields. syntax ( ) ) ; 
107113
108114    if  let  Either :: Left ( strukt)  = strukt { 
109115        if  let  Some ( w)  = strukt. where_clause ( )  { 
110-             edit. delete ( w. syntax ( ) . text_range ( ) ) ; 
111-             edit. insert ( 
112-                 tuple_fields_text_range. start ( ) , 
113-                 ast:: make:: tokens:: single_newline ( ) . text ( ) , 
114-             ) ; 
115-             edit. insert ( tuple_fields_text_range. start ( ) ,  w. syntax ( ) . text ( ) ) ; 
116+             editor. delete ( w. syntax ( ) ) ; 
117+             let  mut  insert_element = Vec :: new ( ) ; 
118+             insert_element. push ( ast:: make:: tokens:: single_newline ( ) . syntax_element ( ) ) ; 
119+             insert_element. push ( w. syntax ( ) . clone_for_update ( ) . syntax_element ( ) ) ; 
116120            if  w. syntax ( ) . last_token ( ) . is_none_or ( |t| t. kind ( )  != SyntaxKind :: COMMA )  { 
117-                 edit . insert ( tuple_fields_text_range . start ( ) ,   "," ) ; 
121+                 insert_element . push ( ast :: make :: token ( T ! [ , ] ) . into ( ) ) ; 
118122            } 
119-             edit. insert ( 
120-                 tuple_fields_text_range. start ( ) , 
121-                 ast:: make:: tokens:: single_newline ( ) . text ( ) , 
122-             ) ; 
123+             insert_element. push ( ast:: make:: tokens:: single_newline ( ) . syntax_element ( ) ) ; 
124+             editor. insert_all ( tuple_fields_before,  insert_element) ; 
123125        }  else  { 
124-             edit . insert ( tuple_fields_text_range . start ( ) ,  ast:: make:: tokens:: single_space ( ) . text ( ) ) ; 
126+             editor . insert ( tuple_fields_before ,  ast:: make:: tokens:: single_space ( ) ) ; 
125127        } 
126128        if  let  Some ( t)  = strukt. semicolon_token ( )  { 
127-             edit . delete ( t. text_range ( ) ) ; 
129+             editor . delete ( t) ; 
128130        } 
129131    }  else  { 
130-         edit . insert ( tuple_fields_text_range . start ( ) ,  ast:: make:: tokens:: single_space ( ) . text ( ) ) ; 
132+         editor . insert ( tuple_fields_before ,  ast:: make:: tokens:: single_space ( ) ) ; 
131133    } 
132134
133-     edit . replace ( tuple_fields_text_range ,  record_fields. to_string ( ) ) ; 
135+     editor . replace ( tuple_fields . syntax ( ) ,  record_fields. syntax ( ) ) ; 
134136} 
135137
136138fn  edit_struct_references ( 
@@ -145,27 +147,22 @@ fn edit_struct_references(
145147    } ; 
146148    let  usages = strukt_def. usages ( & ctx. sema ) . include_self_refs ( ) . all ( ) ; 
147149
148-     let  edit_node = |edit :  & mut  SourceChangeBuilder ,  node :  SyntaxNode | -> Option < ( ) >  { 
150+     let  edit_node = |node :  SyntaxNode | -> Option < SyntaxNode >  { 
151+         let  make = SyntaxFactory :: without_mappings ( ) ; 
149152        match_ast !  { 
150153            match  node { 
151154                ast:: TupleStructPat ( tuple_struct_pat)  => { 
152-                     let  file_range = ctx. sema. original_range_opt( & node) ?; 
153-                     edit. edit_file( file_range. file_id. file_id( ctx. db( ) ) ) ; 
154-                     edit. replace( 
155-                         file_range. range, 
156-                         ast:: make:: record_pat_with_fields( 
157-                             tuple_struct_pat. path( ) ?, 
158-                             ast:: make:: record_pat_field_list( tuple_struct_pat. fields( ) . zip( names) . map( 
159-                                 |( pat,  name) | { 
160-                                     ast:: make:: record_pat_field( 
161-                                         ast:: make:: name_ref( & name. to_string( ) ) , 
162-                                         pat, 
163-                                     ) 
164-                                 } , 
165-                             ) ,  None ) , 
166-                         ) 
167-                         . to_string( ) , 
168-                     ) ; 
155+                     Some ( make. record_pat_with_fields( 
156+                         tuple_struct_pat. path( ) ?, 
157+                         ast:: make:: record_pat_field_list( tuple_struct_pat. fields( ) . zip( names) . map( 
158+                             |( pat,  name) | { 
159+                                 ast:: make:: record_pat_field( 
160+                                     ast:: make:: name_ref( & name. to_string( ) ) , 
161+                                     pat, 
162+                                 ) 
163+                             } , 
164+                         ) ,  None ) , 
165+                     ) . syntax( ) . clone( ) ) 
169166                } , 
170167                // for tuple struct creations like Foo(42) 
171168                ast:: CallExpr ( call_expr)  => { 
@@ -181,10 +178,8 @@ fn edit_struct_references(
181178                    } 
182179
183180                    let  arg_list = call_expr. syntax( ) . descendants( ) . find_map( ast:: ArgList :: cast) ?; 
184- 
185-                     edit. replace( 
186-                         ctx. sema. original_range( & node) . range, 
187-                         ast:: make:: record_expr( 
181+                     Some ( 
182+                         make. record_expr( 
188183                            path, 
189184                            ast:: make:: record_expr_field_list( arg_list. args( ) . zip( names) . map( 
190185                                |( expr,  name) | { 
@@ -194,25 +189,58 @@ fn edit_struct_references(
194189                                    ) 
195190                                } , 
196191                            ) ) , 
197-                         ) 
198-                         . to_string( ) , 
199-                     ) ; 
192+                         ) . syntax( ) . clone( ) 
193+                     ) 
200194                } , 
201195                _ => return  None , 
202196            } 
203197        } 
204-         Some ( ( ) ) 
205198    } ; 
206199
207200    for  ( file_id,  refs)  in  usages { 
208-         edit. edit_file ( file_id. file_id ( ctx. db ( ) ) ) ; 
209-         for  r in  refs { 
210-             for  node in  r. name . syntax ( ) . ancestors ( )  { 
211-                 if  edit_node ( edit,  node) . is_some ( )  { 
212-                     break ; 
201+         let  source = ctx. sema . parse ( file_id) ; 
202+         let  source = source. syntax ( ) ; 
203+ 
204+         let  mut  editor = edit. make_editor ( source) ; 
205+         for  r in  refs. iter ( ) . rev ( )  { 
206+             if  let  Some ( ( old_node,  new_node) )  = r
207+                 . name 
208+                 . syntax ( ) 
209+                 . ancestors ( ) 
210+                 . find_map ( |node| Some ( ( node. clone ( ) ,  edit_node ( node. clone ( ) ) ?) ) ) 
211+             { 
212+                 if  let  Some ( old_node)  = ctx. sema . original_syntax_node_rooted ( & old_node)  { 
213+                     editor. replace ( old_node,  new_node) ; 
214+                 }  else  { 
215+                     let  FileRangeWrapper  {  file_id :  _,  range }  = ctx. sema . original_range ( & old_node) ; 
216+                     let  parent = source. covering_element ( range) ; 
217+                     match  parent { 
218+                         SyntaxElement :: Token ( token)  => { 
219+                             editor. replace ( token,  new_node. syntax_element ( ) ) ; 
220+                         } 
221+                         SyntaxElement :: Node ( parent_node)  => { 
222+                             // replace the part of macro 
223+                             // ``` 
224+                             // foo!(a, Test::A(0)); 
225+                             //     ^^^^^^^^^^^^^^^ // parent_node 
226+                             //         ^^^^^^^^^^  // replace_range 
227+                             // ``` 
228+                             let  start = parent_node
229+                                 . children_with_tokens ( ) 
230+                                 . find ( |t| t. text_range ( ) . contains ( range. start ( ) ) ) ; 
231+                             let  end = parent_node
232+                                 . children_with_tokens ( ) 
233+                                 . find ( |t| t. text_range ( ) . contains ( range. end ( )  - TextSize :: new ( 1 ) ) ) ; 
234+                             if  let  ( Some ( start) ,  Some ( end) )  = ( start,  end)  { 
235+                                 let  replace_range = RangeInclusive :: new ( start,  end) ; 
236+                                 editor. replace_all ( replace_range,  vec ! [ new_node. into( ) ] ) ; 
237+                             } 
238+                         } 
239+                     } 
213240                } 
214241            } 
215242        } 
243+         edit. add_file_edits ( file_id. file_id ( ctx. db ( ) ) ,  editor) ; 
216244    } 
217245} 
218246
@@ -230,22 +258,28 @@ fn edit_field_references(
230258        let  def = Definition :: Field ( field) ; 
231259        let  usages = def. usages ( & ctx. sema ) . all ( ) ; 
232260        for  ( file_id,  refs)  in  usages { 
233-             edit. edit_file ( file_id. file_id ( ctx. db ( ) ) ) ; 
261+             let  source = ctx. sema . parse ( file_id) ; 
262+             let  source = source. syntax ( ) ; 
263+             let  mut  editor = edit. make_editor ( source) ; 
234264            for  r in  refs { 
235-                 if  let  Some ( name_ref)  = r. name . as_name_ref ( )  { 
236-                     edit. replace ( ctx. sema . original_range ( name_ref. syntax ( ) ) . range ,  name. text ( ) ) ; 
265+                 if  let  Some ( name_ref)  = r. name . as_name_ref ( ) 
266+                     && let  Some ( original)  = ctx. sema . original_ast_node ( name_ref. clone ( ) ) 
267+                 { 
268+                     editor. replace ( original. syntax ( ) ,  name. syntax ( ) ) ; 
237269                } 
238270            } 
271+             edit. add_file_edits ( file_id. file_id ( ctx. db ( ) ) ,  editor) ; 
239272        } 
240273    } 
241274} 
242275
243276fn  generate_names ( fields :  impl  Iterator < Item  = ast:: TupleField > )  -> Vec < ast:: Name >  { 
277+     let  make = SyntaxFactory :: without_mappings ( ) ; 
244278    fields
245279        . enumerate ( ) 
246280        . map ( |( i,  _) | { 
247281            let  idx = i + 1 ; 
248-             ast :: make:: name ( & format ! ( "field{idx}" ) ) 
282+             make. name ( & format ! ( "field{idx}" ) ) 
249283        } ) 
250284        . collect ( ) 
251285} 
@@ -1013,8 +1047,7 @@ where
10131047pub struct $0Foo(#[my_custom_attr] u32); 
10141048"# , 
10151049            r#" 
1016- pub struct Foo { #[my_custom_attr] 
1017- field1: u32 } 
1050+ pub struct Foo { #[my_custom_attr]field1: u32 } 
10181051"# , 
10191052        ) ; 
10201053    } 
0 commit comments