From 36a9daac70fe99d837ff3f5b2fb89d226423c1ba Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Tue, 15 Dec 2020 00:39:42 +0900 Subject: [PATCH] Add find usages for enum constructors --- crates/ide/src/references.rs | 115 +++++++++++++++++++++++++++++++++++ crates/ide_db/src/search.rs | 15 +++++ 2 files changed, 130 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 7395b81bd29..66f0f7950f4 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -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::(&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, + syntax: &SyntaxNode, + position: FilePosition, +) -> Option { + 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::(&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::( + &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 <|>{ + A(T), + B, +} +fn main() { + let f: Foo; + 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( diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 607185ca97f..3936c7390fc 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -32,6 +32,7 @@ pub enum ReferenceKind { StructLiteral, RecordFieldExprOrPat, SelfKw, + EnumLiteral, Other, } @@ -284,6 +285,8 @@ fn found_name_ref( 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) +}