@@ -32,8 +32,7 @@ use crate::assist_context::{AssistContext, Assists};
3232// }
3333// ```
3434pub ( 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 ( ) ?;
3736
3837 if ctx. sema . resolve_path ( & path) . is_some ( ) {
3938 // 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
9594 path. syntax ( ) . parent ( ) . and_then ( |it| it. parent ( ) ) . and_then ( ast:: CallExpr :: cast)
9695 {
9796 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)
9899 } else {
99100 None
100101 }
101102}
102103
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+
103139fn make_tuple_field_list (
104140 call_expr : ast:: CallExpr ,
105141 ctx : & AssistContext < ' _ > ,
106142 scope : & hir:: SemanticsScope < ' _ > ,
107143) -> Option < ast:: FieldList > {
108144 let args = call_expr. arg_list ( ) ?. args ( ) ;
109145 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 ) ;
111147 make:: tuple_field ( None , ty)
112148 } ) ;
113149 Some ( make:: tuple_field_list ( tuple_fields) . into ( ) )
114150}
115151
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) )
122160}
123161
124162#[ cfg( test) ]
@@ -318,6 +356,115 @@ enum Foo {
318356fn main() {
319357 Foo::Bar(true, x, Struct {})
320358}
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+ }
321468" ,
322469 )
323470 }
0 commit comments