@@ -2,7 +2,7 @@ use hir::{HasSource, HirDisplay, InFile};
22use ide_db:: assists:: { AssistId , AssistKind } ;
33use syntax:: {
44 ast:: { self , make, HasArgList } ,
5- AstNode ,
5+ match_ast , AstNode , SyntaxNode ,
66} ;
77
88use crate :: assist_context:: { AssistContext , Assists } ;
@@ -33,6 +33,7 @@ use crate::assist_context::{AssistContext, Assists};
3333// ```
3434pub ( crate ) fn generate_enum_variant ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
3535 let path: ast:: Path = ctx. find_node_at_offset ( ) ?;
36+ let parent = path_parent ( & path) ?;
3637
3738 if ctx. sema . resolve_path ( & path) . is_some ( ) {
3839 // No need to generate anything if the path resolves
@@ -49,19 +50,65 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>)
4950 ctx. sema . resolve_path ( & path. qualifier ( ) ?)
5051 {
5152 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 ) ;
5354 }
5455
5556 None
5657}
5758
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+
58105fn add_variant_to_accumulator (
59106 acc : & mut Assists ,
60107 ctx : & AssistContext < ' _ > ,
61108 target : syntax:: TextRange ,
62109 adt : hir:: Enum ,
63110 name_ref : & ast:: NameRef ,
64- path : & ast :: Path ,
111+ parent : PathParent ,
65112) -> Option < ( ) > {
66113 let db = ctx. db ( ) ;
67114 let InFile { file_id, value : enum_node } = adt. source ( db) ?. original_ast_node ( db) ?;
@@ -73,7 +120,7 @@ fn add_variant_to_accumulator(
73120 |builder| {
74121 builder. edit_file ( file_id. original_file ( db) ) ;
75122 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 ) ;
77124 node. variant_list ( ) . map ( |it| it. add_variant ( variant. clone_for_update ( ) ) ) ;
78125 } ,
79126 )
@@ -82,27 +129,14 @@ fn add_variant_to_accumulator(
82129fn make_variant (
83130 ctx : & AssistContext < ' _ > ,
84131 name_ref : & ast:: NameRef ,
85- path : & ast :: Path ,
132+ parent : PathParent ,
86133) -> ast:: Variant {
87- let field_list = make_field_list ( ctx, path ) ;
134+ let field_list = parent . make_field_list ( ctx) ;
88135 make:: variant ( make:: name ( & name_ref. text ( ) ) , field_list)
89136}
90137
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-
104138fn make_record_field_list (
105- record : ast:: RecordExpr ,
139+ record : & ast:: RecordExpr ,
106140 ctx : & AssistContext < ' _ > ,
107141 scope : & hir:: SemanticsScope < ' _ > ,
108142) -> Option < ast:: FieldList > {
@@ -465,6 +499,37 @@ enum Foo {
465499fn main() {
466500 Foo::Bar { x, y: x, s: Struct {} }
467501}
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 {}
468533" ,
469534 )
470535 }
0 commit comments