aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/goto_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/goto_definition.rs')
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs104
1 files changed, 25 insertions, 79 deletions
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index adae29e9c..9c56f17f2 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,12 +1,19 @@
1use ra_db::{FileId, SourceDatabase}; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast,
4 algo::{find_node_at_offset, visit::{visitor, Visitor}}, 4 algo::{
5 find_node_at_offset,
6 visit::{visitor, Visitor},
7 },
5 SyntaxNode, 8 SyntaxNode,
6}; 9};
7use test_utils::tested_by;
8 10
9use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; 11use crate::{
12 FilePosition, NavigationTarget,
13 db::RootDatabase,
14 RangeInfo,
15 name_ref_kind::{NameRefKind::*, classify_name_ref},
16};
10 17
11pub(crate) fn goto_definition( 18pub(crate) fn goto_definition(
12 db: &RootDatabase, 19 db: &RootDatabase,
@@ -50,85 +57,24 @@ pub(crate) fn reference_definition(
50 57
51 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 58 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
52 59
53 // Special cases: 60 match classify_name_ref(db, &analyzer, name_ref) {
54 61 Some(Method(func)) => return Exact(NavigationTarget::from_function(db, func)),
55 // Check if it is a method 62 Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
56 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { 63 Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)),
57 tested_by!(goto_definition_works_for_methods); 64 Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_impl_item(db, assoc)),
58 if let Some(func) = analyzer.resolve_method_call(method_call) { 65 Some(Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
59 return Exact(NavigationTarget::from_function(db, func)); 66 Some(SelfType(ty)) => {
60 } 67 if let Some((def_id, _)) = ty.as_adt() {
61 } 68 return Exact(NavigationTarget::from_adt_def(db, def_id));
62
63 //it could be a macro call
64 if let Some(macro_call) = name_ref
65 .syntax()
66 .parent()
67 .and_then(|node| node.parent())
68 .and_then(|node| node.parent())
69 .and_then(ast::MacroCall::cast)
70 {
71 tested_by!(goto_definition_works_for_macros);
72 if let Some(macro_call) = analyzer.resolve_macro_call(macro_call) {
73 return Exact(NavigationTarget::from_macro_def(db, macro_call));
74 }
75 }
76
77 // It could also be a field access
78 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) {
79 tested_by!(goto_definition_works_for_fields);
80 if let Some(field) = analyzer.resolve_field(field_expr) {
81 return Exact(NavigationTarget::from_field(db, field));
82 };
83 }
84
85 // It could also be a named field
86 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) {
87 tested_by!(goto_definition_works_for_named_fields);
88
89 let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast);
90
91 if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, lit.into())) {
92 if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
93 let hir_path = hir::Path::from_name_ref(name_ref);
94 let hir_name = hir_path.as_ident().unwrap();
95
96 if let Some(field) = s.field(db, hir_name) {
97 return Exact(NavigationTarget::from_field(db, field));
98 }
99 } 69 }
100 } 70 }
101 } 71 Some(Pat(pat)) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
102 72 Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
103 // General case, a path or a local: 73 Some(GenericParam(_)) => {
104 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { 74 // FIXME: go to the generic param def
105 if let Some(resolved) = analyzer.resolve_path(db, path) {
106 match resolved {
107 hir::PathResolution::Def(def) => return Exact(NavigationTarget::from_def(db, def)),
108 hir::PathResolution::LocalBinding(pat) => {
109 let nav = NavigationTarget::from_pat(db, file_id, pat);
110 return Exact(nav);
111 }
112 hir::PathResolution::GenericParam(..) => {
113 // FIXME: go to the generic param def
114 }
115 hir::PathResolution::Macro(def) => {
116 let nav = NavigationTarget::from_macro_def(db, def);
117 return Exact(nav);
118 }
119 hir::PathResolution::SelfType(impl_block) => {
120 let ty = impl_block.target_ty(db);
121
122 if let Some((def_id, _)) = ty.as_adt() {
123 return Exact(NavigationTarget::from_adt_def(db, def_id));
124 }
125 }
126 hir::PathResolution::AssocItem(assoc) => {
127 return Exact(NavigationTarget::from_impl_item(db, assoc));
128 }
129 }
130 } 75 }
131 } 76 None => {}
77 };
132 78
133 // Fallback index based approach: 79 // Fallback index based approach:
134 let navs = crate::symbol_index::index_resolve(db, name_ref) 80 let navs = crate::symbol_index::index_resolve(db, name_ref)