11use either:: Either ;
2+ use hir:: FileRangeWrapper ;
23use ide_db:: defs:: { Definition , NameRefClass } ;
4+ use std:: ops:: RangeInclusive ;
35use syntax:: {
4- SyntaxKind , SyntaxNode , T ,
6+ SyntaxElement , SyntaxKind , SyntaxNode , T , TextSize ,
57 ast:: { self , AstNode , HasAttrs , HasGenericParams , HasVisibility } ,
68 match_ast,
79 syntax_editor:: { Element , Position , SyntaxEditor } ,
@@ -80,8 +82,8 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
8082 |edit| {
8183 let names = generate_names ( tuple_fields. fields ( ) ) ;
8284 edit_field_references ( ctx, edit, tuple_fields. fields ( ) , & names) ;
83- edit_struct_references ( ctx, edit, strukt_def, & names) ;
8485 let mut editor = edit. make_editor ( syntax) ;
86+ edit_struct_references ( ctx, edit, strukt_def, & names) ;
8587 edit_struct_def ( & mut editor, & strukt_or_variant, tuple_fields, names) ;
8688 edit. add_file_edits ( ctx. vfs_file_id ( ) , editor) ;
8789 } ,
@@ -142,27 +144,21 @@ fn edit_struct_references(
142144 } ;
143145 let usages = strukt_def. usages ( & ctx. sema ) . include_self_refs ( ) . all ( ) ;
144146
145- let edit_node = |edit : & mut SourceChangeBuilder , node : SyntaxNode | -> Option < ( ) > {
147+ let edit_node = |node : SyntaxNode | -> Option < SyntaxNode > {
146148 match_ast ! {
147149 match node {
148150 ast:: TupleStructPat ( tuple_struct_pat) => {
149- let file_range = ctx. sema. original_range_opt( & node) ?;
150- edit. edit_file( file_range. file_id. file_id( ctx. db( ) ) ) ;
151- edit. replace(
152- file_range. range,
153- ast:: make:: record_pat_with_fields(
154- tuple_struct_pat. path( ) ?,
155- ast:: make:: record_pat_field_list( tuple_struct_pat. fields( ) . zip( names) . map(
156- |( pat, name) | {
157- ast:: make:: record_pat_field(
158- ast:: make:: name_ref( & name. to_string( ) ) ,
159- pat,
160- )
161- } ,
162- ) , None ) ,
163- )
164- . to_string( ) ,
165- ) ;
151+ Some ( ast:: make:: record_pat_with_fields(
152+ tuple_struct_pat. path( ) ?,
153+ ast:: make:: record_pat_field_list( tuple_struct_pat. fields( ) . zip( names) . map(
154+ |( pat, name) | {
155+ ast:: make:: record_pat_field(
156+ ast:: make:: name_ref( & name. to_string( ) ) ,
157+ pat,
158+ )
159+ } ,
160+ ) , None ) ,
161+ ) . syntax( ) . clone_for_update( ) )
166162 } ,
167163 // for tuple struct creations like Foo(42)
168164 ast:: CallExpr ( call_expr) => {
@@ -179,8 +175,7 @@ fn edit_struct_references(
179175
180176 let arg_list = call_expr. syntax( ) . descendants( ) . find_map( ast:: ArgList :: cast) ?;
181177
182- edit. replace(
183- ctx. sema. original_range( & node) . range,
178+ Some (
184179 ast:: make:: record_expr(
185180 path,
186181 ast:: make:: record_expr_field_list( arg_list. args( ) . zip( names) . map(
@@ -191,25 +186,58 @@ fn edit_struct_references(
191186 )
192187 } ,
193188 ) ) ,
194- )
195- . to_string( ) ,
196- ) ;
189+ ) . syntax( ) . clone_for_update( )
190+ )
197191 } ,
198192 _ => return None ,
199193 }
200194 }
201- Some ( ( ) )
202195 } ;
203196
204197 for ( file_id, refs) in usages {
205- edit. edit_file ( file_id. file_id ( ctx. db ( ) ) ) ;
206- for r in refs {
207- for node in r. name . syntax ( ) . ancestors ( ) {
208- if edit_node ( edit, node) . is_some ( ) {
209- break ;
198+ let source = ctx. sema . parse ( file_id) ;
199+ let source = source. syntax ( ) ;
200+
201+ let mut editor = edit. make_editor ( source) ;
202+ for r in refs. iter ( ) . rev ( ) {
203+ if let Some ( ( old_node, new_node) ) = r
204+ . name
205+ . syntax ( )
206+ . ancestors ( )
207+ . find_map ( |node| Some ( ( node. clone ( ) , edit_node ( node. clone ( ) ) ?) ) )
208+ {
209+ if let Some ( old_node) = ctx. sema . original_syntax_node_rooted ( & old_node) {
210+ editor. replace ( old_node, new_node) ;
211+ } else {
212+ let FileRangeWrapper { file_id : _, range } = ctx. sema . original_range ( & old_node) ;
213+ let parent = source. covering_element ( range) ;
214+ match parent {
215+ SyntaxElement :: Token ( token) => {
216+ editor. replace ( token, new_node. syntax_element ( ) ) ;
217+ }
218+ SyntaxElement :: Node ( parent_node) => {
219+ // replace the part of macro
220+ // ```
221+ // foo!(a, Test::A(0));
222+ // ^^^^^^^^^^^^^^^ // parent_node
223+ // ^^^^^^^^^^ // replace_range
224+ // ```
225+ let start = parent_node
226+ . children_with_tokens ( )
227+ . find ( |t| t. text_range ( ) . contains ( range. start ( ) ) ) ;
228+ let end = parent_node
229+ . children_with_tokens ( )
230+ . find ( |t| t. text_range ( ) . contains ( range. end ( ) - TextSize :: new ( 1 ) ) ) ;
231+ if let ( Some ( start) , Some ( end) ) = ( start, end) {
232+ let replace_range = RangeInclusive :: new ( start, end) ;
233+ editor. replace_all ( replace_range, vec ! [ new_node. into( ) ] ) ;
234+ }
235+ }
236+ }
210237 }
211238 }
212239 }
240+ edit. add_file_edits ( file_id. file_id ( ctx. db ( ) ) , editor) ;
213241 }
214242}
215243
@@ -227,12 +255,17 @@ fn edit_field_references(
227255 let def = Definition :: Field ( field) ;
228256 let usages = def. usages ( & ctx. sema ) . all ( ) ;
229257 for ( file_id, refs) in usages {
230- edit. edit_file ( file_id. file_id ( ctx. db ( ) ) ) ;
258+ let source = ctx. sema . parse ( file_id) ;
259+ let source = source. syntax ( ) ;
260+ let mut editor = edit. make_editor ( source) ;
231261 for r in refs {
232- if let Some ( name_ref) = r. name . as_name_ref ( ) {
233- edit. replace ( ctx. sema . original_range ( name_ref. syntax ( ) ) . range , name. text ( ) ) ;
262+ if let Some ( name_ref) = r. name . as_name_ref ( )
263+ && let Some ( original) = ctx. sema . original_ast_node ( name_ref. clone ( ) )
264+ {
265+ editor. replace ( original. syntax ( ) , name. syntax ( ) ) ;
234266 }
235267 }
268+ edit. add_file_edits ( file_id. file_id ( ctx. db ( ) ) , editor) ;
236269 }
237270 }
238271}
@@ -242,7 +275,7 @@ fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Nam
242275 . enumerate ( )
243276 . map ( |( i, _) | {
244277 let idx = i + 1 ;
245- ast:: make:: name ( & format ! ( "field{idx}" ) )
278+ ast:: make:: name ( & format ! ( "field{idx}" ) ) . clone_for_update ( )
246279 } )
247280 . collect ( )
248281}
0 commit comments