@@ -32,8 +32,7 @@ use crate::assist_context::{AssistContext, Assists};
32
32
// }
33
33
// ```
34
34
pub ( crate ) fn generate_enum_variant ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
35
- let path_expr: ast:: PathExpr = ctx. find_node_at_offset ( ) ?;
36
- let path = path_expr. path ( ) ?;
35
+ let path: ast:: Path = ctx. find_node_at_offset ( ) ?;
37
36
38
37
if ctx. sema . resolve_path ( & path) . is_some ( ) {
39
38
// No need to generate anything if the path resolves
@@ -95,30 +94,69 @@ fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option<ast::Fie
95
94
path. syntax ( ) . parent ( ) . and_then ( |it| it. parent ( ) ) . and_then ( ast:: CallExpr :: cast)
96
95
{
97
96
make_tuple_field_list ( call_expr, ctx, & scope)
97
+ } else if let Some ( record_expr) = path. syntax ( ) . parent ( ) . and_then ( ast:: RecordExpr :: cast) {
98
+ make_record_field_list ( record_expr, ctx, & scope)
98
99
} else {
99
100
None
100
101
}
101
102
}
102
103
104
+ fn make_record_field_list (
105
+ record : ast:: RecordExpr ,
106
+ ctx : & AssistContext < ' _ > ,
107
+ scope : & hir:: SemanticsScope < ' _ > ,
108
+ ) -> Option < ast:: FieldList > {
109
+ let fields = record. record_expr_field_list ( ) ?. fields ( ) ;
110
+ let record_fields = fields. map ( |field| {
111
+ let name = name_from_field ( & field) ;
112
+
113
+ let ty = field
114
+ . expr ( )
115
+ . and_then ( |it| expr_ty ( ctx, it, scope) )
116
+ . unwrap_or_else ( make:: ty_placeholder) ;
117
+
118
+ make:: record_field ( None , name, ty)
119
+ } ) ;
120
+ Some ( make:: record_field_list ( record_fields) . into ( ) )
121
+ }
122
+
123
+ fn name_from_field ( field : & ast:: RecordExprField ) -> ast:: Name {
124
+ let text = match field. name_ref ( ) {
125
+ Some ( it) => it. to_string ( ) ,
126
+ None => name_from_field_shorthand ( field) . unwrap_or ( "unknown" . to_string ( ) ) ,
127
+ } ;
128
+ make:: name ( & text)
129
+ }
130
+
131
+ fn name_from_field_shorthand ( field : & ast:: RecordExprField ) -> Option < String > {
132
+ let path = match field. expr ( ) ? {
133
+ ast:: Expr :: PathExpr ( path_expr) => path_expr. path ( ) ,
134
+ _ => None ,
135
+ } ?;
136
+ Some ( path. as_single_name_ref ( ) ?. to_string ( ) )
137
+ }
138
+
103
139
fn make_tuple_field_list (
104
140
call_expr : ast:: CallExpr ,
105
141
ctx : & AssistContext < ' _ > ,
106
142
scope : & hir:: SemanticsScope < ' _ > ,
107
143
) -> Option < ast:: FieldList > {
108
144
let args = call_expr. arg_list ( ) ?. args ( ) ;
109
145
let tuple_fields = args. map ( |arg| {
110
- let ty = expr_ty ( ctx, arg, & scope) ;
146
+ let ty = expr_ty ( ctx, arg, & scope) . unwrap_or_else ( make :: ty_placeholder ) ;
111
147
make:: tuple_field ( None , ty)
112
148
} ) ;
113
149
Some ( make:: tuple_field_list ( tuple_fields) . into ( ) )
114
150
}
115
151
116
- fn expr_ty ( ctx : & AssistContext < ' _ > , arg : ast:: Expr , scope : & hir:: SemanticsScope < ' _ > ) -> ast:: Type {
117
- let ty = ctx. sema . type_of_expr ( & arg) . map ( |it| it. adjusted ( ) ) ;
118
- let text = ty
119
- . and_then ( |it| it. display_source_code ( ctx. db ( ) , scope. module ( ) . into ( ) ) . ok ( ) )
120
- . unwrap_or_else ( || "_" . to_string ( ) ) ;
121
- make:: ty ( & text)
152
+ fn expr_ty (
153
+ ctx : & AssistContext < ' _ > ,
154
+ arg : ast:: Expr ,
155
+ scope : & hir:: SemanticsScope < ' _ > ,
156
+ ) -> Option < ast:: Type > {
157
+ let ty = ctx. sema . type_of_expr ( & arg) . map ( |it| it. adjusted ( ) ) ?;
158
+ let text = ty. display_source_code ( ctx. db ( ) , scope. module ( ) . into ( ) ) . ok ( ) ?;
159
+ Some ( make:: ty ( & text) )
122
160
}
123
161
124
162
#[ cfg( test) ]
@@ -318,6 +356,115 @@ enum Foo {
318
356
fn main() {
319
357
Foo::Bar(true, x, Struct {})
320
358
}
359
+ " ,
360
+ )
361
+ }
362
+
363
+ #[ test]
364
+ fn associated_record ( ) {
365
+ check_assist (
366
+ generate_enum_variant,
367
+ r"
368
+ enum Foo {}
369
+ fn main() {
370
+ Foo::$0Bar { x: true }
371
+ }
372
+ " ,
373
+ r"
374
+ enum Foo {
375
+ Bar { x: bool },
376
+ }
377
+ fn main() {
378
+ Foo::Bar { x: true }
379
+ }
380
+ " ,
381
+ )
382
+ }
383
+
384
+ #[ test]
385
+ fn associated_record_unknown_type ( ) {
386
+ check_assist (
387
+ generate_enum_variant,
388
+ r"
389
+ enum Foo {}
390
+ fn main() {
391
+ Foo::$0Bar { x: y }
392
+ }
393
+ " ,
394
+ r"
395
+ enum Foo {
396
+ Bar { x: _ },
397
+ }
398
+ fn main() {
399
+ Foo::Bar { x: y }
400
+ }
401
+ " ,
402
+ )
403
+ }
404
+
405
+ #[ test]
406
+ fn associated_record_field_shorthand ( ) {
407
+ check_assist (
408
+ generate_enum_variant,
409
+ r"
410
+ enum Foo {}
411
+ fn main() {
412
+ let x = true;
413
+ Foo::$0Bar { x }
414
+ }
415
+ " ,
416
+ r"
417
+ enum Foo {
418
+ Bar { x: bool },
419
+ }
420
+ fn main() {
421
+ let x = true;
422
+ Foo::Bar { x }
423
+ }
424
+ " ,
425
+ )
426
+ }
427
+
428
+ #[ test]
429
+ fn associated_record_field_shorthand_unknown_type ( ) {
430
+ check_assist (
431
+ generate_enum_variant,
432
+ r"
433
+ enum Foo {}
434
+ fn main() {
435
+ Foo::$0Bar { x }
436
+ }
437
+ " ,
438
+ r"
439
+ enum Foo {
440
+ Bar { x: _ },
441
+ }
442
+ fn main() {
443
+ Foo::Bar { x }
444
+ }
445
+ " ,
446
+ )
447
+ }
448
+
449
+ #[ test]
450
+ fn associated_record_field_multiple_fields ( ) {
451
+ check_assist (
452
+ generate_enum_variant,
453
+ r"
454
+ struct Struct {}
455
+ enum Foo {}
456
+ fn main() {
457
+ Foo::$0Bar { x, y: x, s: Struct {} }
458
+ }
459
+ " ,
460
+ r"
461
+ struct Struct {}
462
+ enum Foo {
463
+ Bar { x: _, y: _, s: Struct },
464
+ }
465
+ fn main() {
466
+ Foo::Bar { x, y: x, s: Struct {} }
467
+ }
321
468
" ,
322
469
)
323
470
}
0 commit comments