Skip to content

Commit 111694d

Browse files
committed
Be more strict about supported Paths in generate_enum_variant
PathType path parents don't support this assist
1 parent e4638de commit 111694d

File tree

1 file changed

+85
-20
lines changed

1 file changed

+85
-20
lines changed

crates/ide-assists/src/handlers/generate_enum_variant.rs

Lines changed: 85 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use hir::{HasSource, HirDisplay, InFile};
22
use ide_db::assists::{AssistId, AssistKind};
33
use syntax::{
44
ast::{self, make, HasArgList},
5-
AstNode,
5+
match_ast, AstNode, SyntaxNode,
66
};
77

88
use crate::assist_context::{AssistContext, Assists};
@@ -33,6 +33,7 @@ use crate::assist_context::{AssistContext, Assists};
3333
// ```
3434
pub(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+
58105
fn 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(
82129
fn 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-
104138
fn 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 {
465499
fn 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

Comments
 (0)