1
1
use ide_db:: { famous_defs:: FamousDefs , source_change:: SourceChangeBuilder } ;
2
2
use stdx:: { format_to, to_lower_snake_case} ;
3
3
use syntax:: {
4
- ast:: { self , AstNode , HasName , HasVisibility } ,
5
- TextRange ,
4
+ ast:: { self , edit_in_place :: Indent , make , AstNode , HasName , HasVisibility } ,
5
+ ted , TextRange ,
6
6
} ;
7
7
8
8
use crate :: {
9
- utils:: { convert_reference_type, find_impl_block_end , find_struct_impl, generate_impl_text } ,
9
+ utils:: { convert_reference_type, find_struct_impl, generate_impl } ,
10
10
AssistContext , AssistId , AssistKind , Assists , GroupLabel ,
11
11
} ;
12
12
@@ -214,14 +214,14 @@ fn generate_getter_from_info(
214
214
ctx : & AssistContext < ' _ > ,
215
215
info : & AssistInfo ,
216
216
record_field_info : & RecordFieldInfo ,
217
- ) -> String {
218
- let mut buf = String :: with_capacity ( 512 ) ;
219
-
220
- let vis = info. strukt . visibility ( ) . map_or ( String :: new ( ) , |v| format ! ( "{v} " ) ) ;
217
+ ) -> ast:: Fn {
221
218
let ( ty, body) = if matches ! ( info. assist_type, AssistType :: MutGet ) {
222
219
(
223
- format ! ( "&mut {}" , record_field_info. field_ty) ,
224
- format ! ( "&mut self.{}" , record_field_info. field_name) ,
220
+ make:: ty_ref ( record_field_info. field_ty . clone ( ) , true ) ,
221
+ make:: expr_ref (
222
+ make:: expr_field ( make:: ext:: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
223
+ true ,
224
+ ) ,
225
225
)
226
226
} else {
227
227
( || {
@@ -240,41 +240,52 @@ fn generate_getter_from_info(
240
240
} ) ( )
241
241
. unwrap_or_else ( || {
242
242
(
243
- format ! ( "&{}" , record_field_info. field_ty) ,
244
- format ! ( "&self.{}" , record_field_info. field_name) ,
243
+ make:: ty_ref ( record_field_info. field_ty . clone ( ) , false ) ,
244
+ make:: expr_ref (
245
+ make:: expr_field ( make:: ext:: expr_self ( ) , & record_field_info. field_name . text ( ) ) ,
246
+ false ,
247
+ ) ,
245
248
)
246
249
} )
247
250
} ;
248
251
249
- format_to ! (
250
- buf,
251
- " {}fn {}(&{}self) -> {} {{
252
- {}
253
- }}" ,
254
- vis,
255
- record_field_info. fn_name,
256
- matches!( info. assist_type, AssistType :: MutGet ) . then_some( "mut " ) . unwrap_or_default( ) ,
257
- ty,
258
- body,
259
- ) ;
252
+ let self_param = if matches ! ( info. assist_type, AssistType :: MutGet ) {
253
+ make:: mut_self_param ( )
254
+ } else {
255
+ make:: self_param ( )
256
+ } ;
260
257
261
- buf
258
+ let strukt = & info. strukt ;
259
+ let fn_name = make:: name ( & record_field_info. fn_name ) ;
260
+ let params = make:: param_list ( Some ( self_param) , [ ] ) ;
261
+ let ret_type = Some ( make:: ret_type ( ty) ) ;
262
+ let body = make:: block_expr ( [ ] , Some ( body) ) ;
263
+
264
+ make:: fn_ ( strukt. visibility ( ) , fn_name, None , None , params, body, ret_type, false , false , false )
262
265
}
263
266
264
- fn generate_setter_from_info ( info : & AssistInfo , record_field_info : & RecordFieldInfo ) -> String {
265
- let mut buf = String :: with_capacity ( 512 ) ;
267
+ fn generate_setter_from_info ( info : & AssistInfo , record_field_info : & RecordFieldInfo ) -> ast:: Fn {
266
268
let strukt = & info. strukt ;
267
- let fn_name = & record_field_info. fn_name ;
269
+ let field_name = & record_field_info. fn_name ;
270
+ let fn_name = make:: name ( & format ! ( "set_{field_name}" ) ) ;
268
271
let field_ty = & record_field_info. field_ty ;
269
- let vis = strukt. visibility ( ) . map_or ( String :: new ( ) , |v| format ! ( "{v} " ) ) ;
270
- format_to ! (
271
- buf,
272
- " {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{
273
- self.{fn_name} = {fn_name};
274
- }}"
275
- ) ;
276
272
277
- buf
273
+ // Make the param list
274
+ // `(&mut self, $field_name: $field_ty)`
275
+ let field_param =
276
+ make:: param ( make:: ident_pat ( false , false , make:: name ( field_name) ) . into ( ) , field_ty. clone ( ) ) ;
277
+ let params = make:: param_list ( Some ( make:: mut_self_param ( ) ) , [ field_param] ) ;
278
+
279
+ // Make the assignment body
280
+ // `self.$field_name = $field_name`
281
+ let self_expr = make:: ext:: expr_self ( ) ;
282
+ let lhs = make:: expr_field ( self_expr, field_name) ;
283
+ let rhs = make:: expr_path ( make:: ext:: ident_path ( field_name) ) ;
284
+ let assign_stmt = make:: expr_stmt ( make:: expr_assignment ( lhs, rhs) ) ;
285
+ let body = make:: block_expr ( [ assign_stmt. into ( ) ] , None ) ;
286
+
287
+ // Make the setter fn
288
+ make:: fn_ ( strukt. visibility ( ) , fn_name, None , None , params, body, None , false , false , false )
278
289
}
279
290
280
291
fn extract_and_parse (
@@ -367,74 +378,45 @@ fn build_source_change(
367
378
) {
368
379
let record_fields_count = info_of_record_fields. len ( ) ;
369
380
370
- let mut buf = String :: with_capacity ( 512 ) ;
381
+ let impl_def = if let Some ( impl_def) = & assist_info. impl_def {
382
+ // We have an existing impl to add to
383
+ builder. make_mut ( impl_def. clone ( ) )
384
+ } else {
385
+ // Generate a new impl to add the methods to
386
+ let impl_def = generate_impl ( & ast:: Adt :: Struct ( assist_info. strukt . clone ( ) ) ) ;
371
387
372
- // Check if an impl exists
373
- if let Some ( impl_def) = & assist_info. impl_def {
374
- // Check if impl is empty
375
- if let Some ( assoc_item_list) = impl_def. assoc_item_list ( ) {
376
- if assoc_item_list. assoc_items ( ) . next ( ) . is_some ( ) {
377
- // If not empty then only insert a new line
378
- buf. push ( '\n' ) ;
379
- }
380
- }
381
- }
388
+ // Insert it after the adt
389
+ let strukt = builder. make_mut ( assist_info. strukt . clone ( ) ) ;
390
+
391
+ ted:: insert_all_raw (
392
+ ted:: Position :: after ( strukt. syntax ( ) ) ,
393
+ vec ! [ make:: tokens:: blank_line( ) . into( ) , impl_def. syntax( ) . clone( ) . into( ) ] ,
394
+ ) ;
395
+
396
+ impl_def
397
+ } ;
398
+
399
+ let assoc_item_list = impl_def. get_or_create_assoc_item_list ( ) ;
382
400
383
401
for ( i, record_field_info) in info_of_record_fields. iter ( ) . enumerate ( ) {
384
- // this buf inserts a newline at the end of a getter
385
- // automatically, if one wants to add one more newline
386
- // for separating it from other assoc items, that needs
387
- // to be handled separately
388
- let mut getter_buf = match assist_info. assist_type {
402
+ // Make the new getter or setter fn
403
+ let new_fn = match assist_info. assist_type {
389
404
AssistType :: Set => generate_setter_from_info ( & assist_info, record_field_info) ,
390
405
_ => generate_getter_from_info ( ctx, & assist_info, record_field_info) ,
391
- } ;
392
-
393
- // Insert `$0` only for last getter we generate
394
- if i == record_fields_count - 1 && ctx. config . snippet_cap . is_some ( ) {
395
- getter_buf = getter_buf. replacen ( "fn " , "fn $0" , 1 ) ;
396
406
}
397
-
398
- // For first element we do not merge with '\n', as
399
- // that can be inserted by impl_def check defined
400
- // above, for other cases which are:
401
- //
402
- // - impl exists but it empty, here we would ideally
403
- // not want to keep newline between impl <struct> {
404
- // and fn <fn-name>() { line
405
- //
406
- // - next if impl itself does not exist, in this
407
- // case we ourselves generate a new impl and that
408
- // again ends up with the same reasoning as above
409
- // for not keeping newline
410
- if i == 0 {
411
- buf = buf + & getter_buf;
412
- } else {
413
- buf = buf + "\n " + & getter_buf;
414
- }
415
-
416
- // We don't insert a new line at the end of
417
- // last getter as it will end up in the end
418
- // of an impl where we would not like to keep
419
- // getter and end of impl ( i.e. `}` ) with an
420
- // extra line for no reason
421
- if i < record_fields_count - 1 {
422
- buf += "\n " ;
407
+ . clone_for_update ( ) ;
408
+ new_fn. indent ( 1 . into ( ) ) ;
409
+
410
+ // Insert a tabstop only for last method we generate
411
+ if i == record_fields_count - 1 {
412
+ if let Some ( cap) = ctx. config . snippet_cap {
413
+ if let Some ( name) = new_fn. name ( ) {
414
+ builder. add_tabstop_before ( cap, name) ;
415
+ }
416
+ }
423
417
}
424
- }
425
-
426
- let start_offset = assist_info
427
- . impl_def
428
- . as_ref ( )
429
- . and_then ( |impl_def| find_impl_block_end ( impl_def. to_owned ( ) , & mut buf) )
430
- . unwrap_or_else ( || {
431
- buf = generate_impl_text ( & ast:: Adt :: Struct ( assist_info. strukt . clone ( ) ) , & buf) ;
432
- assist_info. strukt . syntax ( ) . text_range ( ) . end ( )
433
- } ) ;
434
418
435
- match ctx. config . snippet_cap {
436
- Some ( cap) => builder. insert_snippet ( cap, start_offset, buf) ,
437
- None => builder. insert ( start_offset, buf) ,
419
+ assoc_item_list. add_item ( new_fn. clone ( ) . into ( ) ) ;
438
420
}
439
421
}
440
422
0 commit comments