diff options
author | Laurențiu Nicola <[email protected]> | 2019-05-22 17:49:22 +0100 |
---|---|---|
committer | Laurențiu Nicola <[email protected]> | 2019-05-23 10:32:47 +0100 |
commit | 444e52e519a06e5ac397edf6fa2f4f2e06537e4e (patch) | |
tree | 21f3be8eeb51e97aae3bd848250e395710615937 /crates/ra_ide_api/src/name_ref_kind.rs | |
parent | a25e103e4542637047fe388a926aebddca07b3b7 (diff) |
Move NameRef classification logic out of reference_definition
Diffstat (limited to 'crates/ra_ide_api/src/name_ref_kind.rs')
-rw-r--r-- | crates/ra_ide_api/src/name_ref_kind.rs | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs new file mode 100644 index 000000000..b498fe495 --- /dev/null +++ b/crates/ra_ide_api/src/name_ref_kind.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | use ra_syntax::{AstNode, AstPtr, ast}; | ||
2 | use hir::Either; | ||
3 | use crate::db::RootDatabase; | ||
4 | use test_utils::tested_by; | ||
5 | |||
6 | pub enum NameRefKind { | ||
7 | Method(hir::Function), | ||
8 | Macro(hir::MacroByExampleDef), | ||
9 | FieldAccess(hir::StructField), | ||
10 | AssocItem(hir::ImplItem), | ||
11 | Def(hir::ModuleDef), | ||
12 | SelfType(hir::Ty), | ||
13 | Pat(AstPtr<ast::Pat>), | ||
14 | SelfParam(AstPtr<ast::SelfParam>), | ||
15 | GenericParam(u32), | ||
16 | } | ||
17 | |||
18 | pub(crate) fn classify_name_ref( | ||
19 | db: &RootDatabase, | ||
20 | analyzer: &hir::SourceAnalyzer, | ||
21 | name_ref: &ast::NameRef, | ||
22 | ) -> Option<NameRefKind> { | ||
23 | use NameRefKind::*; | ||
24 | |||
25 | // Check if it is a method | ||
26 | if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { | ||
27 | tested_by!(goto_definition_works_for_methods); | ||
28 | if let Some(func) = analyzer.resolve_method_call(method_call) { | ||
29 | return Some(Method(func)); | ||
30 | } | ||
31 | } | ||
32 | |||
33 | // It could be a macro call | ||
34 | if let Some(macro_call) = name_ref | ||
35 | .syntax() | ||
36 | .parent() | ||
37 | .and_then(|node| node.parent()) | ||
38 | .and_then(|node| node.parent()) | ||
39 | .and_then(ast::MacroCall::cast) | ||
40 | { | ||
41 | tested_by!(goto_definition_works_for_macros); | ||
42 | if let Some(mac) = analyzer.resolve_macro_call(macro_call) { | ||
43 | return Some(Macro(mac)); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | // It could also be a field access | ||
48 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { | ||
49 | tested_by!(goto_definition_works_for_fields); | ||
50 | if let Some(field) = analyzer.resolve_field(field_expr) { | ||
51 | return Some(FieldAccess(field)); | ||
52 | }; | ||
53 | } | ||
54 | |||
55 | // It could also be a named field | ||
56 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) { | ||
57 | tested_by!(goto_definition_works_for_named_fields); | ||
58 | |||
59 | let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast); | ||
60 | |||
61 | if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, lit.into())) { | ||
62 | if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() { | ||
63 | let hir_path = hir::Path::from_name_ref(name_ref); | ||
64 | let hir_name = hir_path.as_ident().unwrap(); | ||
65 | |||
66 | if let Some(field) = s.field(db, hir_name) { | ||
67 | return Some(FieldAccess(field)); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | // General case, a path or a local: | ||
74 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { | ||
75 | if let Some(resolved) = analyzer.resolve_path(db, path) { | ||
76 | return match resolved { | ||
77 | hir::PathResolution::Def(def) => Some(Def(def)), | ||
78 | hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)), | ||
79 | hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)), | ||
80 | hir::PathResolution::GenericParam(par) => { | ||
81 | // FIXME: get generic param def | ||
82 | Some(GenericParam(par)) | ||
83 | } | ||
84 | hir::PathResolution::Macro(def) => Some(Macro(def)), | ||
85 | hir::PathResolution::SelfType(impl_block) => { | ||
86 | let ty = impl_block.target_ty(db); | ||
87 | Some(SelfType(ty)) | ||
88 | } | ||
89 | hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)), | ||
90 | }; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | None | ||
95 | } | ||