Add find usages for enum constructors

This commit is contained in:
Daiki Ihara 2020-12-15 00:39:42 +09:00
parent 8cba423109
commit 36a9daac70
2 changed files with 130 additions and 0 deletions

View file

@ -97,6 +97,9 @@ pub(crate) fn find_all_refs(
get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
{
(Some(name), ReferenceKind::StructLiteral)
} else if let Some(name) = get_enum_def_name_for_struct_literal_search(&sema, &syntax, position)
{
(Some(name), ReferenceKind::EnumLiteral)
} else {
(
sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset),
@ -198,6 +201,33 @@ fn get_struct_def_name_for_struct_literal_search(
None
}
fn get_enum_def_name_for_struct_literal_search(
sema: &Semantics<RootDatabase>,
syntax: &SyntaxNode,
position: FilePosition,
) -> Option<ast::Name> {
if let TokenAtOffset::Between(ref left, ref right) = syntax.token_at_offset(position.offset) {
if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN {
return None;
}
if let Some(name) =
sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start())
{
return name.syntax().ancestors().find_map(ast::Enum::cast).and_then(|l| l.name());
}
if sema
.find_node_at_offset_with_descend::<ast::GenericParamList>(
&syntax,
left.text_range().start(),
)
.is_some()
{
return left.ancestors().find_map(ast::Enum::cast).and_then(|l| l.name());
}
}
None
}
fn try_find_self_references(
syntax: &SyntaxNode,
position: FilePosition,
@ -356,6 +386,91 @@ fn main() {
);
}
#[test]
fn test_enum_after_space() {
check(
r#"
enum Foo <|>{
A,
B,
}
fn main() {
let f: Foo;
f = Foo::A;
}
"#,
expect![[r#"
Foo ENUM FileId(0) 0..26 5..8 Other
FileId(0) 63..66 EnumLiteral
"#]],
);
}
#[test]
fn test_enum_before_space() {
check(
r#"
enum Foo<|> {
A,
B,
}
fn main() {
let f: Foo;
f = Foo::A;
}
"#,
expect![[r#"
Foo ENUM FileId(0) 0..26 5..8 Other
FileId(0) 50..53 Other
FileId(0) 63..66 EnumLiteral
"#]],
);
}
#[test]
fn test_enum_with_generic_type() {
check(
r#"
enum Foo<T> <|>{
A(T),
B,
}
fn main() {
let f: Foo<i8>;
f = Foo::A(1);
}
"#,
expect![[r#"
Foo ENUM FileId(0) 0..32 5..8 Other
FileId(0) 73..76 EnumLiteral
"#]],
);
}
#[test]
fn test_enum_for_tuple() {
check(
r#"
enum Foo<|>{
A(i8),
B(i8),
}
fn main() {
let f: Foo;
f = Foo::A(1);
}
"#,
expect![[r#"
Foo ENUM FileId(0) 0..33 5..8 Other
FileId(0) 70..73 EnumLiteral
"#]],
);
}
#[test]
fn test_find_all_refs_for_local() {
check(

View file

@ -32,6 +32,7 @@ pub enum ReferenceKind {
StructLiteral,
RecordFieldExprOrPat,
SelfKw,
EnumLiteral,
Other,
}
@ -284,6 +285,8 @@ impl<'a> FindUsages<'a> {
ReferenceKind::RecordFieldExprOrPat
} else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
ReferenceKind::StructLiteral
} else if is_enum_lit_name_ref(&name_ref) {
ReferenceKind::EnumLiteral
} else {
ReferenceKind::Other
};
@ -402,3 +405,15 @@ fn is_record_field_expr_or_pat(name_ref: &ast::NameRef) -> bool {
false
}
}
fn is_enum_lit_name_ref(name_ref: &ast::NameRef) -> bool {
name_ref
.syntax()
.ancestors()
.find_map(ast::PathExpr::cast)
.and_then(|p| p.path())
.and_then(|p| p.qualifier())
.and_then(|p| p.segment())
.map(|p| p.name_ref().as_ref() == Some(name_ref))
.unwrap_or(false)
}