aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/goto_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/goto_definition.rs')
-rw-r--r--crates/ide/src/goto_definition.rs105
1 files changed, 32 insertions, 73 deletions
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a1d2bce1d..abed1969e 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -2,16 +2,14 @@ use either::Either;
2use hir::{HasAttrs, ModuleDef, Semantics}; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 defs::{Definition, NameClass, NameRefClass}, 4 defs::{Definition, NameClass, NameRefClass},
5 symbol_index, RootDatabase, 5 RootDatabase,
6}; 6};
7use syntax::{ 7use syntax::{
8 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, 8 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 display::{ToNav, TryToNav}, 12 display::TryToNav, doc_links::extract_definitions_from_markdown, runnables::doc_owner_to_def,
13 doc_links::extract_definitions_from_markdown,
14 runnables::doc_owner_to_def,
15 FilePosition, NavigationTarget, RangeInfo, 13 FilePosition, NavigationTarget, RangeInfo,
16}; 14};
17 15
@@ -33,33 +31,31 @@ pub(crate) fn goto_definition(
33 let original_token = pick_best(file.token_at_offset(position.offset))?; 31 let original_token = pick_best(file.token_at_offset(position.offset))?;
34 let token = sema.descend_into_macros(original_token.clone()); 32 let token = sema.descend_into_macros(original_token.clone());
35 let parent = token.parent(); 33 let parent = token.parent();
36 if let Some(comment) = ast::Comment::cast(token.clone()) { 34 if let Some(comment) = ast::Comment::cast(token) {
37 let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?; 35 let nav = def_for_doc_comment(&sema, position, &comment)?.try_to_nav(db)?;
38 return Some(RangeInfo::new(original_token.text_range(), vec![nav])); 36 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
39 } 37 }
40 38
41 let nav_targets = match_ast! { 39 let nav = match_ast! {
42 match parent { 40 match parent {
43 ast::NameRef(name_ref) => { 41 ast::NameRef(name_ref) => {
44 reference_definition(&sema, Either::Right(&name_ref)).to_vec() 42 reference_definition(&sema, Either::Right(&name_ref))
45 }, 43 },
46 ast::Name(name) => { 44 ast::Name(name) => {
47 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); 45 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
48 let nav = def.try_to_nav(sema.db)?; 46 def.try_to_nav(sema.db)
49 vec![nav]
50 }, 47 },
51 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { 48 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
52 let def = name_class.referenced_or_defined(sema.db); 49 let def = name_class.referenced_or_defined(sema.db);
53 let nav = def.try_to_nav(sema.db)?; 50 def.try_to_nav(sema.db)
54 vec![nav]
55 } else { 51 } else {
56 reference_definition(&sema, Either::Left(&lt)).to_vec() 52 reference_definition(&sema, Either::Left(&lt))
57 }, 53 },
58 _ => return None, 54 _ => return None,
59 } 55 }
60 }; 56 };
61 57
62 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 58 Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect()))
63} 59}
64 60
65fn def_for_doc_comment( 61fn def_for_doc_comment(
@@ -120,63 +116,26 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
120 } 116 }
121} 117}
122 118
123#[derive(Debug)]
124pub(crate) enum ReferenceResult {
125 Exact(NavigationTarget),
126 Approximate(Vec<NavigationTarget>),
127}
128
129impl ReferenceResult {
130 fn to_vec(self) -> Vec<NavigationTarget> {
131 match self {
132 ReferenceResult::Exact(target) => vec![target],
133 ReferenceResult::Approximate(vec) => vec,
134 }
135 }
136}
137
138pub(crate) fn reference_definition( 119pub(crate) fn reference_definition(
139 sema: &Semantics<RootDatabase>, 120 sema: &Semantics<RootDatabase>,
140 name_ref: Either<&ast::Lifetime, &ast::NameRef>, 121 name_ref: Either<&ast::Lifetime, &ast::NameRef>,
141) -> ReferenceResult { 122) -> Option<NavigationTarget> {
142 let name_kind = name_ref.either( 123 let name_kind = name_ref.either(
143 |lifetime| NameRefClass::classify_lifetime(sema, lifetime), 124 |lifetime| NameRefClass::classify_lifetime(sema, lifetime),
144 |name_ref| NameRefClass::classify(sema, name_ref), 125 |name_ref| NameRefClass::classify(sema, name_ref),
145 ); 126 )?;
146 if let Some(def) = name_kind { 127 let def = name_kind.referenced(sema.db);
147 let def = def.referenced(sema.db); 128 def.try_to_nav(sema.db)
148 return match def.try_to_nav(sema.db) {
149 Some(nav) => ReferenceResult::Exact(nav),
150 None => ReferenceResult::Approximate(Vec::new()),
151 };
152 }
153
154 // Fallback index based approach:
155 let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text);
156 let navs =
157 symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect();
158 ReferenceResult::Approximate(navs)
159} 129}
160 130
161#[cfg(test)] 131#[cfg(test)]
162mod tests { 132mod tests {
163 use ide_db::base_db::FileRange; 133 use ide_db::base_db::FileRange;
164 use syntax::{TextRange, TextSize};
165 134
166 use crate::fixture; 135 use crate::fixture;
167 136
168 fn check(ra_fixture: &str) { 137 fn check(ra_fixture: &str) {
169 let (analysis, position, mut annotations) = fixture::annotations(ra_fixture); 138 let (analysis, position, expected) = fixture::nav_target_annotation(ra_fixture);
170 let (mut expected, data) = annotations.pop().unwrap();
171 match data.as_str() {
172 "" => (),
173 "file" => {
174 expected.range =
175 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
176 }
177 data => panic!("bad data: {}", data),
178 }
179
180 let mut navs = 139 let mut navs =
181 analysis.goto_definition(position).unwrap().expect("no definition found").info; 140 analysis.goto_definition(position).unwrap().expect("no definition found").info;
182 if navs.len() == 0 { 141 if navs.len() == 0 {
@@ -192,12 +151,12 @@ mod tests {
192 fn goto_def_for_extern_crate() { 151 fn goto_def_for_extern_crate() {
193 check( 152 check(
194 r#" 153 r#"
195 //- /main.rs crate:main deps:std 154//- /main.rs crate:main deps:std
196 extern crate std$0; 155extern crate std$0;
197 //- /std/lib.rs crate:std 156//- /std/lib.rs crate:std
198 // empty 157// empty
199 //^ file 158//^ file
200 "#, 159"#,
201 ) 160 )
202 } 161 }
203 162
@@ -205,12 +164,12 @@ mod tests {
205 fn goto_def_for_renamed_extern_crate() { 164 fn goto_def_for_renamed_extern_crate() {
206 check( 165 check(
207 r#" 166 r#"
208 //- /main.rs crate:main deps:std 167//- /main.rs crate:main deps:std
209 extern crate std as abc$0; 168extern crate std as abc$0;
210 //- /std/lib.rs crate:std 169//- /std/lib.rs crate:std
211 // empty 170// empty
212 //^ file 171//^ file
213 "#, 172"#,
214 ) 173 )
215 } 174 }
216 175
@@ -297,13 +256,13 @@ fn bar() {
297 fn goto_def_for_macros_from_other_crates() { 256 fn goto_def_for_macros_from_other_crates() {
298 check( 257 check(
299 r#" 258 r#"
300//- /lib.rs 259//- /lib.rs crate:main deps:foo
301use foo::foo; 260use foo::foo;
302fn bar() { 261fn bar() {
303 $0foo!(); 262 $0foo!();
304} 263}
305 264
306//- /foo/lib.rs 265//- /foo/lib.rs crate:foo
307#[macro_export] 266#[macro_export]
308macro_rules! foo { () => { () } } 267macro_rules! foo { () => { () } }
309 //^^^ 268 //^^^
@@ -315,10 +274,10 @@ macro_rules! foo { () => { () } }
315 fn goto_def_for_macros_in_use_tree() { 274 fn goto_def_for_macros_in_use_tree() {
316 check( 275 check(
317 r#" 276 r#"
318//- /lib.rs 277//- /lib.rs crate:main deps:foo
319use foo::foo$0; 278use foo::foo$0;
320 279
321//- /foo/lib.rs 280//- /foo/lib.rs crate:foo
322#[macro_export] 281#[macro_export]
323macro_rules! foo { () => { () } } 282macro_rules! foo { () => { () } }
324 //^^^ 283 //^^^
@@ -976,10 +935,10 @@ type Alias<T> = T$0;
976 fn goto_def_for_macro_container() { 935 fn goto_def_for_macro_container() {
977 check( 936 check(
978 r#" 937 r#"
979//- /lib.rs 938//- /lib.rs crate:main deps:foo
980foo::module$0::mac!(); 939foo::module$0::mac!();
981 940
982//- /foo/lib.rs 941//- /foo/lib.rs crate:foo
983pub mod module { 942pub mod module {
984 //^^^^^^ 943 //^^^^^^
985 #[macro_export] 944 #[macro_export]