1
- use hir:: { HasSource , InFile } ;
1
+ use hir:: { HasSource , HirDisplay , InFile } ;
2
2
use ide_db:: assists:: { AssistId , AssistKind } ;
3
3
use syntax:: {
4
- ast:: { self , make} ,
4
+ ast:: { self , make, HasArgList } ,
5
5
AstNode ,
6
6
} ;
7
7
@@ -50,7 +50,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
50
50
ctx. sema . resolve_path ( & path. qualifier ( ) ?)
51
51
{
52
52
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 ) ;
54
54
}
55
55
56
56
None
@@ -62,23 +62,65 @@ fn add_variant_to_accumulator(
62
62
target : syntax:: TextRange ,
63
63
adt : hir:: Enum ,
64
64
name_ref : & ast:: NameRef ,
65
+ path : & ast:: Path ,
65
66
) -> Option < ( ) > {
66
67
let db = ctx. db ( ) ;
67
68
let InFile { file_id, value : enum_node } = adt. source ( db) ?. original_ast_node ( db) ?;
68
69
69
- let variant = make:: variant ( make:: name ( & name_ref. text ( ) ) , None ) ;
70
70
acc. add (
71
71
AssistId ( "generate_enum_variant" , AssistKind :: Generate ) ,
72
72
"Generate variant" ,
73
73
target,
74
74
|builder| {
75
75
builder. edit_file ( file_id. original_file ( db) ) ;
76
76
let node = builder. make_mut ( enum_node) ;
77
+ let variant = make_variant ( ctx, name_ref, & path) ;
77
78
node. variant_list ( ) . map ( |it| it. add_variant ( variant. clone_for_update ( ) ) ) ;
78
79
} ,
79
80
)
80
81
}
81
82
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
+
82
124
#[ cfg( test) ]
83
125
mod tests {
84
126
use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -211,6 +253,71 @@ mod m {
211
253
fn main() {
212
254
m::Foo::Baz
213
255
}
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
+ }
214
321
" ,
215
322
)
216
323
}
0 commit comments