1- use hir:: { HasSource , InFile } ;
1+ use hir:: { HasSource , HirDisplay , InFile } ;
22use ide_db:: assists:: { AssistId , AssistKind } ;
33use syntax:: {
4- ast:: { self , make} ,
4+ ast:: { self , make, HasArgList } ,
55 AstNode ,
66} ;
77
@@ -50,7 +50,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
5050 ctx. sema . resolve_path ( & path. qualifier ( ) ?)
5151 {
5252 let target = path. syntax ( ) . text_range ( ) ;
53- return add_variant_to_accumulator ( acc, ctx, target, e, & name_ref) ;
53+ return add_variant_to_accumulator ( acc, ctx, target, e, & name_ref, & path ) ;
5454 }
5555
5656 None
@@ -62,23 +62,65 @@ fn add_variant_to_accumulator(
6262 target : syntax:: TextRange ,
6363 adt : hir:: Enum ,
6464 name_ref : & ast:: NameRef ,
65+ path : & ast:: Path ,
6566) -> Option < ( ) > {
6667 let db = ctx. db ( ) ;
6768 let InFile { file_id, value : enum_node } = adt. source ( db) ?. original_ast_node ( db) ?;
6869
69- let variant = make:: variant ( make:: name ( & name_ref. text ( ) ) , None ) ;
7070 acc. add (
7171 AssistId ( "generate_enum_variant" , AssistKind :: Generate ) ,
7272 "Generate variant" ,
7373 target,
7474 |builder| {
7575 builder. edit_file ( file_id. original_file ( db) ) ;
7676 let node = builder. make_mut ( enum_node) ;
77+ let variant = make_variant ( ctx, name_ref, & path) ;
7778 node. variant_list ( ) . map ( |it| it. add_variant ( variant. clone_for_update ( ) ) ) ;
7879 } ,
7980 )
8081}
8182
83+ fn make_variant (
84+ ctx : & AssistContext < ' _ > ,
85+ name_ref : & ast:: NameRef ,
86+ path : & ast:: Path ,
87+ ) -> ast:: Variant {
88+ let field_list = make_field_list ( ctx, path) ;
89+ make:: variant ( make:: name ( & name_ref. text ( ) ) , field_list)
90+ }
91+
92+ fn make_field_list ( ctx : & AssistContext < ' _ > , path : & ast:: Path ) -> Option < ast:: FieldList > {
93+ let scope = ctx. sema . scope ( & path. syntax ( ) ) ?;
94+ if let Some ( call_expr) =
95+ path. syntax ( ) . parent ( ) . and_then ( |it| it. parent ( ) ) . and_then ( ast:: CallExpr :: cast)
96+ {
97+ make_tuple_field_list ( call_expr, ctx, & scope)
98+ } else {
99+ None
100+ }
101+ }
102+
103+ fn make_tuple_field_list (
104+ call_expr : ast:: CallExpr ,
105+ ctx : & AssistContext < ' _ > ,
106+ scope : & hir:: SemanticsScope < ' _ > ,
107+ ) -> Option < ast:: FieldList > {
108+ let args = call_expr. arg_list ( ) ?. args ( ) ;
109+ let tuple_fields = args. map ( |arg| {
110+ let ty = expr_ty ( ctx, arg, & scope) ;
111+ make:: tuple_field ( None , ty)
112+ } ) ;
113+ Some ( make:: tuple_field_list ( tuple_fields) . into ( ) )
114+ }
115+
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)
122+ }
123+
82124#[ cfg( test) ]
83125mod tests {
84126 use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -211,6 +253,71 @@ mod m {
211253fn main() {
212254 m::Foo::Baz
213255}
256+ " ,
257+ )
258+ }
259+
260+ #[ test]
261+ fn associated_single_element_tuple ( ) {
262+ check_assist (
263+ generate_enum_variant,
264+ r"
265+ enum Foo {}
266+ fn main() {
267+ Foo::Bar$0(true)
268+ }
269+ " ,
270+ r"
271+ enum Foo {
272+ Bar(bool),
273+ }
274+ fn main() {
275+ Foo::Bar(true)
276+ }
277+ " ,
278+ )
279+ }
280+
281+ #[ test]
282+ fn associated_single_element_tuple_unknown_type ( ) {
283+ check_assist (
284+ generate_enum_variant,
285+ r"
286+ enum Foo {}
287+ fn main() {
288+ Foo::Bar$0(x)
289+ }
290+ " ,
291+ r"
292+ enum Foo {
293+ Bar(_),
294+ }
295+ fn main() {
296+ Foo::Bar(x)
297+ }
298+ " ,
299+ )
300+ }
301+
302+ #[ test]
303+ fn associated_multi_element_tuple ( ) {
304+ check_assist (
305+ generate_enum_variant,
306+ r"
307+ struct Struct {}
308+ enum Foo {}
309+ fn main() {
310+ Foo::Bar$0(true, x, Struct {})
311+ }
312+ " ,
313+ r"
314+ struct Struct {}
315+ enum Foo {
316+ Bar(bool, _, Struct),
317+ }
318+ fn main() {
319+ Foo::Bar(true, x, Struct {})
320+ }
214321" ,
215322 )
216323 }
0 commit comments