@@ -2,7 +2,7 @@ use hir::{HasSource, HirDisplay, InFile};
2
2
use ide_db:: assists:: { AssistId , AssistKind } ;
3
3
use syntax:: {
4
4
ast:: { self , make, HasArgList } ,
5
- AstNode ,
5
+ match_ast , AstNode , SyntaxNode ,
6
6
} ;
7
7
8
8
use crate :: assist_context:: { AssistContext , Assists } ;
@@ -33,6 +33,7 @@ use crate::assist_context::{AssistContext, Assists};
33
33
// ```
34
34
pub ( crate ) fn generate_enum_variant ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
35
35
let path: ast:: Path = ctx. find_node_at_offset ( ) ?;
36
+ let parent = path_parent ( & path) ?;
36
37
37
38
if ctx. sema . resolve_path ( & path) . is_some ( ) {
38
39
// No need to generate anything if the path resolves
@@ -49,19 +50,65 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
49
50
ctx. sema . resolve_path ( & path. qualifier ( ) ?)
50
51
{
51
52
let target = path. syntax ( ) . text_range ( ) ;
52
- return add_variant_to_accumulator ( acc, ctx, target, e, & name_ref, & path ) ;
53
+ return add_variant_to_accumulator ( acc, ctx, target, e, & name_ref, parent ) ;
53
54
}
54
55
55
56
None
56
57
}
57
58
59
+ #[ derive( Debug ) ]
60
+ enum PathParent {
61
+ PathExpr ( ast:: PathExpr ) ,
62
+ RecordExpr ( ast:: RecordExpr ) ,
63
+ UseTree ( ast:: UseTree ) ,
64
+ }
65
+
66
+ impl PathParent {
67
+ fn syntax ( & self ) -> & SyntaxNode {
68
+ match self {
69
+ PathParent :: PathExpr ( it) => it. syntax ( ) ,
70
+ PathParent :: RecordExpr ( it) => it. syntax ( ) ,
71
+ PathParent :: UseTree ( it) => it. syntax ( ) ,
72
+ }
73
+ }
74
+
75
+ fn make_field_list ( & self , ctx : & AssistContext < ' _ > ) -> Option < ast:: FieldList > {
76
+ let scope = ctx. sema . scope ( self . syntax ( ) ) ?;
77
+
78
+ match self {
79
+ PathParent :: PathExpr ( it) => {
80
+ if let Some ( call_expr) = it. syntax ( ) . parent ( ) . and_then ( ast:: CallExpr :: cast) {
81
+ make_tuple_field_list ( call_expr, ctx, & scope)
82
+ } else {
83
+ None
84
+ }
85
+ }
86
+ PathParent :: RecordExpr ( it) => make_record_field_list ( it, ctx, & scope) ,
87
+ PathParent :: UseTree ( _) => None ,
88
+ }
89
+ }
90
+ }
91
+
92
+ fn path_parent ( path : & ast:: Path ) -> Option < PathParent > {
93
+ let parent = path. syntax ( ) . parent ( ) ?;
94
+
95
+ match_ast ! {
96
+ match parent {
97
+ ast:: PathExpr ( it) => Some ( PathParent :: PathExpr ( it) ) ,
98
+ ast:: RecordExpr ( it) => Some ( PathParent :: RecordExpr ( it) ) ,
99
+ ast:: UseTree ( it) => Some ( PathParent :: UseTree ( it) ) ,
100
+ _ => None
101
+ }
102
+ }
103
+ }
104
+
58
105
fn add_variant_to_accumulator (
59
106
acc : & mut Assists ,
60
107
ctx : & AssistContext < ' _ > ,
61
108
target : syntax:: TextRange ,
62
109
adt : hir:: Enum ,
63
110
name_ref : & ast:: NameRef ,
64
- path : & ast :: Path ,
111
+ parent : PathParent ,
65
112
) -> Option < ( ) > {
66
113
let db = ctx. db ( ) ;
67
114
let InFile { file_id, value : enum_node } = adt. source ( db) ?. original_ast_node ( db) ?;
@@ -73,7 +120,7 @@ fn add_variant_to_accumulator(
73
120
|builder| {
74
121
builder. edit_file ( file_id. original_file ( db) ) ;
75
122
let node = builder. make_mut ( enum_node) ;
76
- let variant = make_variant ( ctx, name_ref, & path ) ;
123
+ let variant = make_variant ( ctx, name_ref, parent ) ;
77
124
node. variant_list ( ) . map ( |it| it. add_variant ( variant. clone_for_update ( ) ) ) ;
78
125
} ,
79
126
)
@@ -82,27 +129,14 @@ fn add_variant_to_accumulator(
82
129
fn make_variant (
83
130
ctx : & AssistContext < ' _ > ,
84
131
name_ref : & ast:: NameRef ,
85
- path : & ast :: Path ,
132
+ parent : PathParent ,
86
133
) -> ast:: Variant {
87
- let field_list = make_field_list ( ctx, path ) ;
134
+ let field_list = parent . make_field_list ( ctx) ;
88
135
make:: variant ( make:: name ( & name_ref. text ( ) ) , field_list)
89
136
}
90
137
91
- fn make_field_list ( ctx : & AssistContext < ' _ > , path : & ast:: Path ) -> Option < ast:: FieldList > {
92
- let scope = ctx. sema . scope ( & path. syntax ( ) ) ?;
93
- if let Some ( call_expr) =
94
- path. syntax ( ) . parent ( ) . and_then ( |it| it. parent ( ) ) . and_then ( ast:: CallExpr :: cast)
95
- {
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)
99
- } else {
100
- None
101
- }
102
- }
103
-
104
138
fn make_record_field_list (
105
- record : ast:: RecordExpr ,
139
+ record : & ast:: RecordExpr ,
106
140
ctx : & AssistContext < ' _ > ,
107
141
scope : & hir:: SemanticsScope < ' _ > ,
108
142
) -> Option < ast:: FieldList > {
@@ -465,6 +499,37 @@ enum Foo {
465
499
fn main() {
466
500
Foo::Bar { x, y: x, s: Struct {} }
467
501
}
502
+ " ,
503
+ )
504
+ }
505
+
506
+ #[ test]
507
+ fn use_tree ( ) {
508
+ check_assist (
509
+ generate_enum_variant,
510
+ r"
511
+ //- /main.rs
512
+ mod foo;
513
+ use foo::Foo::Bar$0;
514
+
515
+ //- /foo.rs
516
+ enum Foo {}
517
+ " ,
518
+ r"
519
+ enum Foo {
520
+ Bar,
521
+ }
522
+ " ,
523
+ )
524
+ }
525
+
526
+ #[ test]
527
+ fn not_applicable_for_path_type ( ) {
528
+ check_assist_not_applicable (
529
+ generate_enum_variant,
530
+ r"
531
+ enum Foo {}
532
+ impl Foo::Bar$0 {}
468
533
" ,
469
534
)
470
535
}
0 commit comments