diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-06-30 12:30:51 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-30 12:30:51 +0100 |
commit | 6a73d544f4117b942b300afb8bda98216fc92356 (patch) | |
tree | 18b444a0d447465a7de75ec5a0153c90b8566a7f /crates | |
parent | 5a0fb3caff745d20face2d7ab02fa4da63faef9c (diff) | |
parent | af7e300041b1af68e671446fe22d2b9e5d30f83d (diff) |
Merge #5137
5137: Make gotodef tests more data-driven r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/test_db.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 45 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 1063 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_implementation.rs | 193 | ||||
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 9 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 12 |
9 files changed, 636 insertions, 737 deletions
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 4a3ba57da..1ddacc1f6 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -80,7 +80,7 @@ pub struct FilePosition { | |||
80 | pub offset: TextSize, | 80 | pub offset: TextSize, |
81 | } | 81 | } |
82 | 82 | ||
83 | #[derive(Clone, Copy, Debug)] | 83 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
84 | pub struct FileRange { | 84 | pub struct FileRange { |
85 | pub file_id: FileId, | 85 | pub file_id: FileId, |
86 | pub range: TextRange, | 86 | pub range: TextRange, |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index 0481a7b12..fddf0604d 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -8,8 +8,10 @@ use std::{ | |||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; |
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | use rustc_hash::FxHashSet; | 11 | use ra_syntax::TextRange; |
12 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
12 | use stdx::format_to; | 13 | use stdx::format_to; |
14 | use test_utils::extract_annotations; | ||
13 | 15 | ||
14 | use crate::{ | 16 | use crate::{ |
15 | db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator, | 17 | db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator, |
@@ -155,17 +157,27 @@ impl TestDB { | |||
155 | (buf, count) | 157 | (buf, count) |
156 | } | 158 | } |
157 | 159 | ||
158 | pub fn all_files(&self) -> Vec<FileId> { | 160 | pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { |
159 | let mut res = Vec::new(); | 161 | let mut files = Vec::new(); |
160 | let crate_graph = self.crate_graph(); | 162 | let crate_graph = self.crate_graph(); |
161 | for krate in crate_graph.iter() { | 163 | for krate in crate_graph.iter() { |
162 | let crate_def_map = self.crate_def_map(krate); | 164 | let crate_def_map = self.crate_def_map(krate); |
163 | for (module_id, _) in crate_def_map.modules.iter() { | 165 | for (module_id, _) in crate_def_map.modules.iter() { |
164 | let file_id = crate_def_map[module_id].origin.file_id(); | 166 | let file_id = crate_def_map[module_id].origin.file_id(); |
165 | res.extend(file_id) | 167 | files.extend(file_id) |
166 | } | 168 | } |
167 | } | 169 | } |
168 | res | 170 | files |
171 | .into_iter() | ||
172 | .filter_map(|file_id| { | ||
173 | let text = self.file_text(file_id); | ||
174 | let annotations = extract_annotations(&text); | ||
175 | if annotations.is_empty() { | ||
176 | return None; | ||
177 | } | ||
178 | Some((file_id, annotations)) | ||
179 | }) | ||
180 | .collect() | ||
169 | } | 181 | } |
170 | } | 182 | } |
171 | 183 | ||
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 5424e6bb1..9084c3bed 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -28,7 +28,6 @@ use ra_syntax::{ | |||
28 | SyntaxNode, | 28 | SyntaxNode, |
29 | }; | 29 | }; |
30 | use stdx::format_to; | 30 | use stdx::format_to; |
31 | use test_utils::extract_annotations; | ||
32 | 31 | ||
33 | use crate::{ | 32 | use crate::{ |
34 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, | 33 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, |
@@ -49,9 +48,7 @@ fn check_types_source_code(ra_fixture: &str) { | |||
49 | fn check_types_impl(ra_fixture: &str, display_source: bool) { | 48 | fn check_types_impl(ra_fixture: &str, display_source: bool) { |
50 | let db = TestDB::with_files(ra_fixture); | 49 | let db = TestDB::with_files(ra_fixture); |
51 | let mut checked_one = false; | 50 | let mut checked_one = false; |
52 | for file_id in db.all_files() { | 51 | for (file_id, annotations) in db.extract_annotations() { |
53 | let text = db.parse(file_id).syntax_node().to_string(); | ||
54 | let annotations = extract_annotations(&text); | ||
55 | for (range, expected) in annotations { | 52 | for (range, expected) in annotations { |
56 | let ty = type_at_range(&db, FileRange { file_id, range }); | 53 | let ty = type_at_range(&db, FileRange { file_id, range }); |
57 | let actual = if display_source { | 54 | let actual = if display_source { |
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 0b52b01ab..8bf2428ed 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | TextRange, | 11 | TextRange, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{FileRange, FileSymbol}; | 14 | use crate::FileSymbol; |
15 | 15 | ||
16 | use super::short_label::ShortLabel; | 16 | use super::short_label::ShortLabel; |
17 | 17 | ||
@@ -47,6 +47,19 @@ impl NavigationTarget { | |||
47 | pub fn range(&self) -> TextRange { | 47 | pub fn range(&self) -> TextRange { |
48 | self.focus_range.unwrap_or(self.full_range) | 48 | self.focus_range.unwrap_or(self.full_range) |
49 | } | 49 | } |
50 | /// A "most interesting" range withing the `full_range`. | ||
51 | /// | ||
52 | /// Typically, `full_range` is the whole syntax node, | ||
53 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
54 | pub fn focus_range(&self) -> Option<TextRange> { | ||
55 | self.focus_range | ||
56 | } | ||
57 | pub fn full_range(&self) -> TextRange { | ||
58 | self.full_range | ||
59 | } | ||
60 | pub fn file_id(&self) -> FileId { | ||
61 | self.file_id | ||
62 | } | ||
50 | 63 | ||
51 | pub fn name(&self) -> &SmolStr { | 64 | pub fn name(&self) -> &SmolStr { |
52 | &self.name | 65 | &self.name |
@@ -60,18 +73,6 @@ impl NavigationTarget { | |||
60 | self.kind | 73 | self.kind |
61 | } | 74 | } |
62 | 75 | ||
63 | pub fn file_id(&self) -> FileId { | ||
64 | self.file_id | ||
65 | } | ||
66 | |||
67 | pub fn file_range(&self) -> FileRange { | ||
68 | FileRange { file_id: self.file_id, range: self.full_range } | ||
69 | } | ||
70 | |||
71 | pub fn full_range(&self) -> TextRange { | ||
72 | self.full_range | ||
73 | } | ||
74 | |||
75 | pub fn docs(&self) -> Option<&str> { | 76 | pub fn docs(&self) -> Option<&str> { |
76 | self.docs.as_deref() | 77 | self.docs.as_deref() |
77 | } | 78 | } |
@@ -80,14 +81,6 @@ impl NavigationTarget { | |||
80 | self.description.as_deref() | 81 | self.description.as_deref() |
81 | } | 82 | } |
82 | 83 | ||
83 | /// A "most interesting" range withing the `full_range`. | ||
84 | /// | ||
85 | /// Typically, `full_range` is the whole syntax node, | ||
86 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
87 | pub fn focus_range(&self) -> Option<TextRange> { | ||
88 | self.focus_range | ||
89 | } | ||
90 | |||
91 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 84 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
92 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 85 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
93 | if let Some(src) = module.declaration_source(db) { | 86 | if let Some(src) = module.declaration_source(db) { |
@@ -278,16 +271,22 @@ impl ToNav for hir::Module { | |||
278 | impl ToNav for hir::ImplDef { | 271 | impl ToNav for hir::ImplDef { |
279 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 272 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
280 | let src = self.source(db); | 273 | let src = self.source(db); |
281 | let frange = if let Some(item) = self.is_builtin_derive(db) { | 274 | let derive_attr = self.is_builtin_derive(db); |
275 | let frange = if let Some(item) = &derive_attr { | ||
282 | original_range(db, item.syntax()) | 276 | original_range(db, item.syntax()) |
283 | } else { | 277 | } else { |
284 | original_range(db, src.as_ref().map(|it| it.syntax())) | 278 | original_range(db, src.as_ref().map(|it| it.syntax())) |
285 | }; | 279 | }; |
280 | let focus_range = if derive_attr.is_some() { | ||
281 | None | ||
282 | } else { | ||
283 | src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range) | ||
284 | }; | ||
286 | 285 | ||
287 | NavigationTarget::from_syntax( | 286 | NavigationTarget::from_syntax( |
288 | frange.file_id, | 287 | frange.file_id, |
289 | "impl".into(), | 288 | "impl".into(), |
290 | None, | 289 | focus_range, |
291 | frange.range, | 290 | frange.range, |
292 | src.value.syntax().kind(), | 291 | src.value.syntax().kind(), |
293 | ) | 292 | ) |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 969d5e0ff..4c78fa214 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -103,67 +103,32 @@ pub(crate) fn reference_definition( | |||
103 | 103 | ||
104 | #[cfg(test)] | 104 | #[cfg(test)] |
105 | mod tests { | 105 | mod tests { |
106 | use expect::{expect, Expect}; | 106 | use ra_db::FileRange; |
107 | use test_utils::assert_eq_text; | 107 | use ra_syntax::{TextRange, TextSize}; |
108 | 108 | ||
109 | use crate::mock_analysis::analysis_and_position; | 109 | use crate::mock_analysis::MockAnalysis; |
110 | 110 | ||
111 | fn check_goto(ra_fixture: &str, expected: &str, expected_range: &str) { | 111 | fn check(ra_fixture: &str) { |
112 | let (analysis, pos) = analysis_and_position(ra_fixture); | 112 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); |
113 | 113 | let (mut expected, data) = mock.annotation(); | |
114 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | 114 | let analysis = mock.analysis(); |
115 | if navs.len() == 0 { | 115 | match data.as_str() { |
116 | panic!("unresolved reference") | 116 | "" => (), |
117 | } | 117 | "file" => { |
118 | assert_eq!(navs.len(), 1); | 118 | expected.range = |
119 | 119 | TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap())) | |
120 | let nav = navs.pop().unwrap(); | 120 | } |
121 | let file_text = analysis.file_text(nav.file_id()).unwrap(); | 121 | data => panic!("bad data: {}", data), |
122 | |||
123 | let mut actual = file_text[nav.full_range()].to_string(); | ||
124 | if let Some(focus) = nav.focus_range() { | ||
125 | actual += "|"; | ||
126 | actual += &file_text[focus]; | ||
127 | } | ||
128 | |||
129 | if !expected_range.contains("...") { | ||
130 | test_utils::assert_eq_text!(&actual, expected_range); | ||
131 | } else { | ||
132 | let mut parts = expected_range.split("..."); | ||
133 | let prefix = parts.next().unwrap(); | ||
134 | let suffix = parts.next().unwrap(); | ||
135 | assert!( | ||
136 | actual.starts_with(prefix) && actual.ends_with(suffix), | ||
137 | "\nExpected: {}\n Actual: {}\n", | ||
138 | expected_range, | ||
139 | actual | ||
140 | ); | ||
141 | } | 122 | } |
142 | 123 | ||
143 | nav.assert_match(expected); | 124 | let mut navs = analysis.goto_definition(position).unwrap().unwrap().info; |
144 | } | ||
145 | |||
146 | fn check(ra_fixture: &str, expect: Expect) { | ||
147 | let (analysis, pos) = analysis_and_position(ra_fixture); | ||
148 | |||
149 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | ||
150 | if navs.len() == 0 { | 125 | if navs.len() == 0 { |
151 | panic!("unresolved reference") | 126 | panic!("unresolved reference") |
152 | } | 127 | } |
153 | assert_eq!(navs.len(), 1); | 128 | assert_eq!(navs.len(), 1); |
154 | 129 | ||
155 | let nav = navs.pop().unwrap(); | 130 | let nav = navs.pop().unwrap(); |
156 | let file_text = analysis.file_text(nav.file_id()).unwrap(); | 131 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); |
157 | |||
158 | let mut actual = nav.debug_render(); | ||
159 | actual += "\n"; | ||
160 | actual += &file_text[nav.full_range()].to_string(); | ||
161 | if let Some(focus) = nav.focus_range() { | ||
162 | actual += "|"; | ||
163 | actual += &file_text[focus]; | ||
164 | actual += "\n"; | ||
165 | } | ||
166 | expect.assert_eq(&actual); | ||
167 | } | 132 | } |
168 | 133 | ||
169 | #[test] | 134 | #[test] |
@@ -171,162 +136,116 @@ mod tests { | |||
171 | check( | 136 | check( |
172 | r#" | 137 | r#" |
173 | struct Foo; | 138 | struct Foo; |
139 | //^^^ | ||
174 | enum E { X(Foo<|>) } | 140 | enum E { X(Foo<|>) } |
175 | "#, | 141 | "#, |
176 | expect![[r#" | ||
177 | Foo STRUCT_DEF FileId(1) 0..11 7..10 | ||
178 | struct Foo;|Foo | ||
179 | "#]], | ||
180 | ); | 142 | ); |
181 | } | 143 | } |
182 | 144 | ||
183 | #[test] | 145 | #[test] |
184 | fn goto_def_at_start_of_item() { | 146 | fn goto_def_at_start_of_item() { |
185 | check_goto( | 147 | check( |
186 | " | 148 | r#" |
187 | //- /lib.rs | 149 | struct Foo; |
188 | struct Foo; | 150 | //^^^ |
189 | enum E { X(<|>Foo) } | 151 | enum E { X(<|>Foo) } |
190 | ", | 152 | "#, |
191 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
192 | "struct Foo;|Foo", | ||
193 | ); | 153 | ); |
194 | } | 154 | } |
195 | 155 | ||
196 | #[test] | 156 | #[test] |
197 | fn goto_definition_resolves_correct_name() { | 157 | fn goto_definition_resolves_correct_name() { |
198 | check_goto( | 158 | check( |
199 | " | 159 | r#" |
200 | //- /lib.rs | 160 | //- /lib.rs |
201 | use a::Foo; | 161 | use a::Foo; |
202 | mod a; | 162 | mod a; |
203 | mod b; | 163 | mod b; |
204 | enum E { X(Foo<|>) } | 164 | enum E { X(Foo<|>) } |
205 | |||
206 | //- /a.rs | ||
207 | struct Foo; | ||
208 | 165 | ||
209 | //- /b.rs | 166 | //- /a.rs |
210 | struct Foo; | 167 | struct Foo; |
211 | ", | 168 | //^^^ |
212 | "Foo STRUCT_DEF FileId(2) 0..11 7..10", | 169 | //- /b.rs |
213 | "struct Foo;|Foo", | 170 | struct Foo; |
171 | "#, | ||
214 | ); | 172 | ); |
215 | } | 173 | } |
216 | 174 | ||
217 | #[test] | 175 | #[test] |
218 | fn goto_def_for_module_declaration() { | 176 | fn goto_def_for_module_declaration() { |
219 | check_goto( | 177 | check( |
220 | r#" | 178 | r#" |
221 | //- /lib.rs | 179 | //- /lib.rs |
222 | mod <|>foo; | 180 | mod <|>foo; |
223 | 181 | ||
224 | //- /foo.rs | 182 | //- /foo.rs |
225 | // empty | 183 | // empty |
184 | //^ file | ||
226 | "#, | 185 | "#, |
227 | "foo SOURCE_FILE FileId(2) 0..9", | ||
228 | "// empty\n", | ||
229 | ); | 186 | ); |
230 | 187 | ||
231 | check_goto( | 188 | check( |
232 | r#" | 189 | r#" |
233 | //- /lib.rs | 190 | //- /lib.rs |
234 | mod <|>foo; | 191 | mod <|>foo; |
235 | 192 | ||
236 | //- /foo/mod.rs | 193 | //- /foo/mod.rs |
237 | // empty | 194 | // empty |
195 | //^ file | ||
238 | "#, | 196 | "#, |
239 | "foo SOURCE_FILE FileId(2) 0..9", | ||
240 | "// empty\n", | ||
241 | ); | 197 | ); |
242 | } | 198 | } |
243 | 199 | ||
244 | #[test] | 200 | #[test] |
245 | fn goto_def_for_macros() { | 201 | fn goto_def_for_macros() { |
246 | check_goto( | 202 | check( |
247 | " | 203 | r#" |
248 | //- /lib.rs | 204 | macro_rules! foo { () => { () } } |
249 | macro_rules! foo { () => { () } } | 205 | //^^^ |
250 | 206 | fn bar() { | |
251 | fn bar() { | 207 | <|>foo!(); |
252 | <|>foo!(); | 208 | } |
253 | } | 209 | "#, |
254 | ", | ||
255 | "foo MACRO_CALL FileId(1) 0..33 13..16", | ||
256 | "macro_rules! foo { () => { () } }|foo", | ||
257 | ); | 210 | ); |
258 | } | 211 | } |
259 | 212 | ||
260 | #[test] | 213 | #[test] |
261 | fn goto_def_for_macros_from_other_crates() { | 214 | fn goto_def_for_macros_from_other_crates() { |
262 | check_goto( | 215 | check( |
263 | " | ||
264 | //- /lib.rs | ||
265 | use foo::foo; | ||
266 | fn bar() { | ||
267 | <|>foo!(); | ||
268 | } | ||
269 | |||
270 | //- /foo/lib.rs | ||
271 | #[macro_export] | ||
272 | macro_rules! foo { () => { () } } | ||
273 | ", | ||
274 | "foo MACRO_CALL FileId(2) 0..49 29..32", | ||
275 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
276 | ); | ||
277 | } | ||
278 | |||
279 | #[test] | ||
280 | fn goto_def_for_use_alias() { | ||
281 | check_goto( | ||
282 | r#" | 216 | r#" |
283 | //- /lib.rs | 217 | //- /lib.rs |
284 | use foo as bar<|>; | 218 | use foo::foo; |
219 | fn bar() { | ||
220 | <|>foo!(); | ||
221 | } | ||
285 | 222 | ||
286 | //- /foo/lib.rs | 223 | //- /foo/lib.rs |
287 | #[macro_export] | 224 | #[macro_export] |
288 | macro_rules! foo { () => { () } } | 225 | macro_rules! foo { () => { () } } |
226 | //^^^ | ||
289 | "#, | 227 | "#, |
290 | "SOURCE_FILE FileId(2) 0..50", | ||
291 | "#[macro_export]\nmacro_rules! foo { () => { () } }\n", | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn goto_def_for_use_alias_foo_macro() { | ||
297 | check_goto( | ||
298 | " | ||
299 | //- /lib.rs | ||
300 | use foo::foo as bar<|>; | ||
301 | |||
302 | //- /foo/lib.rs | ||
303 | #[macro_export] | ||
304 | macro_rules! foo { () => { () } } | ||
305 | ", | ||
306 | "foo MACRO_CALL FileId(2) 0..49 29..32", | ||
307 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
308 | ); | 228 | ); |
309 | } | 229 | } |
310 | 230 | ||
311 | #[test] | 231 | #[test] |
312 | fn goto_def_for_macros_in_use_tree() { | 232 | fn goto_def_for_macros_in_use_tree() { |
313 | check_goto( | 233 | check( |
314 | " | 234 | r#" |
315 | //- /lib.rs | 235 | //- /lib.rs |
316 | use foo::foo<|>; | 236 | use foo::foo<|>; |
317 | 237 | ||
318 | //- /foo/lib.rs | 238 | //- /foo/lib.rs |
319 | #[macro_export] | 239 | #[macro_export] |
320 | macro_rules! foo { () => { () } } | 240 | macro_rules! foo { () => { () } } |
321 | ", | 241 | //^^^ |
322 | "foo MACRO_CALL FileId(2) 0..49 29..32", | 242 | "#, |
323 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
324 | ); | 243 | ); |
325 | } | 244 | } |
326 | 245 | ||
327 | #[test] | 246 | #[test] |
328 | fn goto_def_for_macro_defined_fn_with_arg() { | 247 | fn goto_def_for_macro_defined_fn_with_arg() { |
329 | check_goto( | 248 | check( |
330 | r#" | 249 | r#" |
331 | //- /lib.rs | 250 | //- /lib.rs |
332 | macro_rules! define_fn { | 251 | macro_rules! define_fn { |
@@ -334,522 +253,478 @@ macro_rules! define_fn { | |||
334 | } | 253 | } |
335 | 254 | ||
336 | define_fn!(foo); | 255 | define_fn!(foo); |
256 | //^^^ | ||
337 | 257 | ||
338 | fn bar() { | 258 | fn bar() { |
339 | <|>foo(); | 259 | <|>foo(); |
340 | } | 260 | } |
341 | "#, | 261 | "#, |
342 | "foo FN_DEF FileId(1) 65..81 76..79", | ||
343 | "define_fn!(foo);|foo", | ||
344 | ); | 262 | ); |
345 | } | 263 | } |
346 | 264 | ||
347 | #[test] | 265 | #[test] |
348 | fn goto_def_for_macro_defined_fn_no_arg() { | 266 | fn goto_def_for_macro_defined_fn_no_arg() { |
349 | check_goto( | 267 | check( |
350 | r#" | 268 | r#" |
351 | //- /lib.rs | 269 | //- /lib.rs |
352 | macro_rules! define_fn { | 270 | macro_rules! define_fn { |
353 | () => (fn foo() {}) | 271 | () => (fn foo() {}) |
354 | } | 272 | } |
355 | 273 | ||
356 | define_fn!(); | 274 | define_fn!(); |
275 | //^^^^^^^^^^^^^ | ||
357 | 276 | ||
358 | fn bar() { | 277 | fn bar() { |
359 | <|>foo(); | 278 | <|>foo(); |
360 | } | 279 | } |
361 | "#, | 280 | "#, |
362 | "foo FN_DEF FileId(1) 52..65 52..65", | ||
363 | "define_fn!();|define_fn!();", | ||
364 | ); | 281 | ); |
365 | } | 282 | } |
366 | 283 | ||
367 | #[test] | 284 | #[test] |
368 | fn goto_definition_works_for_macro_inside_pattern() { | 285 | fn goto_definition_works_for_macro_inside_pattern() { |
369 | check_goto( | 286 | check( |
370 | " | 287 | r#" |
371 | //- /lib.rs | 288 | //- /lib.rs |
372 | macro_rules! foo {() => {0}} | 289 | macro_rules! foo {() => {0}} |
373 | 290 | //^^^ | |
374 | fn bar() { | 291 | |
375 | match (0,1) { | 292 | fn bar() { |
376 | (<|>foo!(), _) => {} | 293 | match (0,1) { |
377 | } | 294 | (<|>foo!(), _) => {} |
378 | } | 295 | } |
379 | ", | 296 | } |
380 | "foo MACRO_CALL FileId(1) 0..28 13..16", | 297 | "#, |
381 | "macro_rules! foo {() => {0}}|foo", | ||
382 | ); | 298 | ); |
383 | } | 299 | } |
384 | 300 | ||
385 | #[test] | 301 | #[test] |
386 | fn goto_definition_works_for_macro_inside_match_arm_lhs() { | 302 | fn goto_definition_works_for_macro_inside_match_arm_lhs() { |
387 | check_goto( | 303 | check( |
388 | " | 304 | r#" |
389 | //- /lib.rs | 305 | //- /lib.rs |
390 | macro_rules! foo {() => {0}} | 306 | macro_rules! foo {() => {0}} |
391 | 307 | //^^^ | |
392 | fn bar() { | 308 | fn bar() { |
393 | match 0 { | 309 | match 0 { |
394 | <|>foo!() => {} | 310 | <|>foo!() => {} |
395 | } | 311 | } |
396 | } | 312 | } |
397 | ", | 313 | "#, |
398 | "foo MACRO_CALL FileId(1) 0..28 13..16", | 314 | ); |
399 | "macro_rules! foo {() => {0}}|foo", | 315 | } |
316 | |||
317 | #[test] | ||
318 | fn goto_def_for_use_alias() { | ||
319 | check( | ||
320 | r#" | ||
321 | //- /lib.rs | ||
322 | use foo as bar<|>; | ||
323 | |||
324 | //- /foo/lib.rs | ||
325 | // empty | ||
326 | //^ file | ||
327 | "#, | ||
328 | ); | ||
329 | } | ||
330 | |||
331 | #[test] | ||
332 | fn goto_def_for_use_alias_foo_macro() { | ||
333 | check( | ||
334 | r#" | ||
335 | //- /lib.rs | ||
336 | use foo::foo as bar<|>; | ||
337 | |||
338 | //- /foo/lib.rs | ||
339 | #[macro_export] | ||
340 | macro_rules! foo { () => { () } } | ||
341 | //^^^ | ||
342 | "#, | ||
400 | ); | 343 | ); |
401 | } | 344 | } |
402 | 345 | ||
403 | #[test] | 346 | #[test] |
404 | fn goto_def_for_methods() { | 347 | fn goto_def_for_methods() { |
405 | check_goto( | 348 | check( |
406 | " | 349 | r#" |
407 | //- /lib.rs | 350 | //- /lib.rs |
408 | struct Foo; | 351 | struct Foo; |
409 | impl Foo { | 352 | impl Foo { |
410 | fn frobnicate(&self) { } | 353 | fn frobnicate(&self) { } |
411 | } | 354 | //^^^^^^^^^^ |
355 | } | ||
412 | 356 | ||
413 | fn bar(foo: &Foo) { | 357 | fn bar(foo: &Foo) { |
414 | foo.frobnicate<|>(); | 358 | foo.frobnicate<|>(); |
415 | } | 359 | } |
416 | ", | 360 | "#, |
417 | "frobnicate FN_DEF FileId(1) 27..51 30..40", | ||
418 | "fn frobnicate(&self) { }|frobnicate", | ||
419 | ); | 361 | ); |
420 | } | 362 | } |
421 | 363 | ||
422 | #[test] | 364 | #[test] |
423 | fn goto_def_for_fields() { | 365 | fn goto_def_for_fields() { |
424 | check_goto( | 366 | check( |
425 | r" | 367 | r#" |
426 | //- /lib.rs | 368 | struct Foo { |
427 | struct Foo { | 369 | spam: u32, |
428 | spam: u32, | 370 | } //^^^^ |
429 | } | ||
430 | 371 | ||
431 | fn bar(foo: &Foo) { | 372 | fn bar(foo: &Foo) { |
432 | foo.spam<|>; | 373 | foo.spam<|>; |
433 | } | 374 | } |
434 | ", | 375 | "#, |
435 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
436 | "spam: u32|spam", | ||
437 | ); | 376 | ); |
438 | } | 377 | } |
439 | 378 | ||
440 | #[test] | 379 | #[test] |
441 | fn goto_def_for_record_fields() { | 380 | fn goto_def_for_record_fields() { |
442 | check_goto( | 381 | check( |
443 | r" | 382 | r#" |
444 | //- /lib.rs | 383 | //- /lib.rs |
445 | struct Foo { | 384 | struct Foo { |
446 | spam: u32, | 385 | spam: u32, |
447 | } | 386 | } //^^^^ |
448 | 387 | ||
449 | fn bar() -> Foo { | 388 | fn bar() -> Foo { |
450 | Foo { | 389 | Foo { |
451 | spam<|>: 0, | 390 | spam<|>: 0, |
452 | } | 391 | } |
453 | } | 392 | } |
454 | ", | 393 | "#, |
455 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
456 | "spam: u32|spam", | ||
457 | ); | 394 | ); |
458 | } | 395 | } |
459 | 396 | ||
460 | #[test] | 397 | #[test] |
461 | fn goto_def_for_record_pat_fields() { | 398 | fn goto_def_for_record_pat_fields() { |
462 | check_goto( | 399 | check( |
463 | r" | 400 | r#" |
464 | //- /lib.rs | 401 | //- /lib.rs |
465 | struct Foo { | 402 | struct Foo { |
466 | spam: u32, | 403 | spam: u32, |
467 | } | 404 | } //^^^^ |
468 | 405 | ||
469 | fn bar(foo: Foo) -> Foo { | 406 | fn bar(foo: Foo) -> Foo { |
470 | let Foo { spam<|>: _, } = foo | 407 | let Foo { spam<|>: _, } = foo |
471 | } | 408 | } |
472 | ", | 409 | "#, |
473 | "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21", | ||
474 | "spam: u32|spam", | ||
475 | ); | 410 | ); |
476 | } | 411 | } |
477 | 412 | ||
478 | #[test] | 413 | #[test] |
479 | fn goto_def_for_record_fields_macros() { | 414 | fn goto_def_for_record_fields_macros() { |
480 | check_goto( | 415 | check( |
481 | r" | 416 | r" |
482 | //- /lib.rs | 417 | macro_rules! m { () => { 92 };} |
483 | macro_rules! m { () => { 92 };} | 418 | struct Foo { spam: u32 } |
484 | struct Foo { spam: u32 } | 419 | //^^^^ |
485 | 420 | ||
486 | fn bar() -> Foo { | 421 | fn bar() -> Foo { |
487 | Foo { spam<|>: m!() } | 422 | Foo { spam<|>: m!() } |
488 | } | 423 | } |
489 | ", | 424 | ", |
490 | "spam RECORD_FIELD_DEF FileId(1) 45..54 45..49", | ||
491 | "spam: u32|spam", | ||
492 | ); | 425 | ); |
493 | } | 426 | } |
494 | 427 | ||
495 | #[test] | 428 | #[test] |
496 | fn goto_for_tuple_fields() { | 429 | fn goto_for_tuple_fields() { |
497 | check_goto( | 430 | check( |
498 | " | 431 | r#" |
499 | //- /lib.rs | 432 | struct Foo(u32); |
500 | struct Foo(u32); | 433 | //^^^ |
501 | 434 | ||
502 | fn bar() { | 435 | fn bar() { |
503 | let foo = Foo(0); | 436 | let foo = Foo(0); |
504 | foo.<|>0; | 437 | foo.<|>0; |
505 | } | 438 | } |
506 | ", | 439 | "#, |
507 | "TUPLE_FIELD_DEF FileId(1) 11..14", | ||
508 | "u32", | ||
509 | ); | 440 | ); |
510 | } | 441 | } |
511 | 442 | ||
512 | #[test] | 443 | #[test] |
513 | fn goto_def_for_ufcs_inherent_methods() { | 444 | fn goto_def_for_ufcs_inherent_methods() { |
514 | check_goto( | 445 | check( |
515 | " | 446 | r#" |
516 | //- /lib.rs | 447 | struct Foo; |
517 | struct Foo; | 448 | impl Foo { |
518 | impl Foo { | 449 | fn frobnicate() { } |
519 | fn frobnicate() { } | 450 | } //^^^^^^^^^^ |
520 | } | ||
521 | 451 | ||
522 | fn bar(foo: &Foo) { | 452 | fn bar(foo: &Foo) { |
523 | Foo::frobnicate<|>(); | 453 | Foo::frobnicate<|>(); |
524 | } | 454 | } |
525 | ", | 455 | "#, |
526 | "frobnicate FN_DEF FileId(1) 27..46 30..40", | ||
527 | "fn frobnicate() { }|frobnicate", | ||
528 | ); | 456 | ); |
529 | } | 457 | } |
530 | 458 | ||
531 | #[test] | 459 | #[test] |
532 | fn goto_def_for_ufcs_trait_methods_through_traits() { | 460 | fn goto_def_for_ufcs_trait_methods_through_traits() { |
533 | check_goto( | 461 | check( |
534 | " | 462 | r#" |
535 | //- /lib.rs | 463 | trait Foo { |
536 | trait Foo { | 464 | fn frobnicate(); |
537 | fn frobnicate(); | 465 | } //^^^^^^^^^^ |
538 | } | ||
539 | 466 | ||
540 | fn bar() { | 467 | fn bar() { |
541 | Foo::frobnicate<|>(); | 468 | Foo::frobnicate<|>(); |
542 | } | 469 | } |
543 | ", | 470 | "#, |
544 | "frobnicate FN_DEF FileId(1) 16..32 19..29", | ||
545 | "fn frobnicate();|frobnicate", | ||
546 | ); | 471 | ); |
547 | } | 472 | } |
548 | 473 | ||
549 | #[test] | 474 | #[test] |
550 | fn goto_def_for_ufcs_trait_methods_through_self() { | 475 | fn goto_def_for_ufcs_trait_methods_through_self() { |
551 | check_goto( | 476 | check( |
552 | " | 477 | r#" |
553 | //- /lib.rs | 478 | struct Foo; |
554 | struct Foo; | 479 | trait Trait { |
555 | trait Trait { | 480 | fn frobnicate(); |
556 | fn frobnicate(); | 481 | } //^^^^^^^^^^ |
557 | } | 482 | impl Trait for Foo {} |
558 | impl Trait for Foo {} | ||
559 | 483 | ||
560 | fn bar() { | 484 | fn bar() { |
561 | Foo::frobnicate<|>(); | 485 | Foo::frobnicate<|>(); |
562 | } | 486 | } |
563 | ", | 487 | "#, |
564 | "frobnicate FN_DEF FileId(1) 30..46 33..43", | ||
565 | "fn frobnicate();|frobnicate", | ||
566 | ); | 488 | ); |
567 | } | 489 | } |
568 | 490 | ||
569 | #[test] | 491 | #[test] |
570 | fn goto_definition_on_self() { | 492 | fn goto_definition_on_self() { |
571 | check_goto( | 493 | check( |
572 | " | 494 | r#" |
573 | //- /lib.rs | 495 | struct Foo; |
574 | struct Foo; | 496 | impl Foo { |
575 | impl Foo { | 497 | //^^^ |
576 | pub fn new() -> Self { | 498 | pub fn new() -> Self { |
577 | Self<|> {} | 499 | Self<|> {} |
578 | } | 500 | } |
579 | } | 501 | } |
580 | ", | 502 | "#, |
581 | "impl IMPL_DEF FileId(1) 12..73", | 503 | ); |
582 | "impl Foo {...}", | 504 | check( |
583 | ); | 505 | r#" |
584 | 506 | struct Foo; | |
585 | check_goto( | 507 | impl Foo { |
586 | " | 508 | //^^^ |
587 | //- /lib.rs | 509 | pub fn new() -> Self<|> { |
588 | struct Foo; | 510 | Self {} |
589 | impl Foo { | 511 | } |
590 | pub fn new() -> Self<|> { | 512 | } |
591 | Self {} | 513 | "#, |
592 | } | 514 | ); |
593 | } | 515 | |
594 | ", | 516 | check( |
595 | "impl IMPL_DEF FileId(1) 12..73", | 517 | r#" |
596 | "impl Foo {...}", | 518 | enum Foo { A } |
597 | ); | 519 | impl Foo { |
598 | 520 | //^^^ | |
599 | check_goto( | 521 | pub fn new() -> Self<|> { |
600 | " | 522 | Foo::A |
601 | //- /lib.rs | 523 | } |
602 | enum Foo { A } | 524 | } |
603 | impl Foo { | 525 | "#, |
604 | pub fn new() -> Self<|> { | 526 | ); |
605 | Foo::A | 527 | |
606 | } | 528 | check( |
607 | } | 529 | r#" |
608 | ", | 530 | enum Foo { A } |
609 | "impl IMPL_DEF FileId(1) 15..75", | 531 | impl Foo { |
610 | "impl Foo {...}", | 532 | //^^^ |
611 | ); | 533 | pub fn thing(a: &Self<|>) { |
612 | 534 | } | |
613 | check_goto( | 535 | } |
614 | " | 536 | "#, |
615 | //- /lib.rs | ||
616 | enum Foo { A } | ||
617 | impl Foo { | ||
618 | pub fn thing(a: &Self<|>) { | ||
619 | } | ||
620 | } | ||
621 | ", | ||
622 | "impl IMPL_DEF FileId(1) 15..62", | ||
623 | "impl Foo {...}", | ||
624 | ); | 537 | ); |
625 | } | 538 | } |
626 | 539 | ||
627 | #[test] | 540 | #[test] |
628 | fn goto_definition_on_self_in_trait_impl() { | 541 | fn goto_definition_on_self_in_trait_impl() { |
629 | check_goto( | 542 | check( |
630 | " | 543 | r#" |
631 | //- /lib.rs | 544 | struct Foo; |
632 | struct Foo; | 545 | trait Make { |
633 | trait Make { | 546 | fn new() -> Self; |
634 | fn new() -> Self; | 547 | } |
635 | } | 548 | impl Make for Foo { |
636 | impl Make for Foo { | 549 | //^^^ |
637 | fn new() -> Self { | 550 | fn new() -> Self { |
638 | Self<|> {} | 551 | Self<|> {} |
639 | } | 552 | } |
640 | } | 553 | } |
641 | ", | 554 | "#, |
642 | "impl IMPL_DEF FileId(1) 49..115", | ||
643 | "impl Make for Foo {...}", | ||
644 | ); | 555 | ); |
645 | 556 | ||
646 | check_goto( | 557 | check( |
647 | " | 558 | r#" |
648 | //- /lib.rs | 559 | struct Foo; |
649 | struct Foo; | 560 | trait Make { |
650 | trait Make { | 561 | fn new() -> Self; |
651 | fn new() -> Self; | 562 | } |
652 | } | 563 | impl Make for Foo { |
653 | impl Make for Foo { | 564 | //^^^ |
654 | fn new() -> Self<|> { | 565 | fn new() -> Self<|> { |
655 | Self {} | 566 | Self {} |
656 | } | 567 | } |
657 | } | 568 | } |
658 | ", | 569 | "#, |
659 | "impl IMPL_DEF FileId(1) 49..115", | ||
660 | "impl Make for Foo {...}", | ||
661 | ); | 570 | ); |
662 | } | 571 | } |
663 | 572 | ||
664 | #[test] | 573 | #[test] |
665 | fn goto_def_when_used_on_definition_name_itself() { | 574 | fn goto_def_when_used_on_definition_name_itself() { |
666 | check_goto( | 575 | check( |
667 | " | 576 | r#" |
668 | //- /lib.rs | 577 | struct Foo<|> { value: u32 } |
669 | struct Foo<|> { value: u32 } | 578 | //^^^ |
670 | ", | 579 | "#, |
671 | "Foo STRUCT_DEF FileId(1) 0..25 7..10", | ||
672 | "struct Foo { value: u32 }|Foo", | ||
673 | ); | 580 | ); |
674 | 581 | ||
675 | check_goto( | 582 | check( |
676 | r#" | 583 | r#" |
677 | //- /lib.rs | 584 | struct Foo { |
678 | struct Foo { | 585 | field<|>: string, |
679 | field<|>: string, | 586 | } //^^^^^ |
680 | } | 587 | "#, |
681 | "#, | ||
682 | "field RECORD_FIELD_DEF FileId(1) 17..30 17..22", | ||
683 | "field: string|field", | ||
684 | ); | 588 | ); |
685 | 589 | ||
686 | check_goto( | 590 | check( |
687 | " | 591 | r#" |
688 | //- /lib.rs | 592 | fn foo_test<|>() { } |
689 | fn foo_test<|>() { } | 593 | //^^^^^^^^ |
690 | ", | 594 | "#, |
691 | "foo_test FN_DEF FileId(1) 0..17 3..11", | ||
692 | "fn foo_test() { }|foo_test", | ||
693 | ); | 595 | ); |
694 | 596 | ||
695 | check_goto( | 597 | check( |
696 | " | 598 | r#" |
697 | //- /lib.rs | 599 | enum Foo<|> { Variant } |
698 | enum Foo<|> { | 600 | //^^^ |
699 | Variant, | 601 | "#, |
700 | } | ||
701 | ", | ||
702 | "Foo ENUM_DEF FileId(1) 0..25 5..8", | ||
703 | "enum Foo {...}|Foo", | ||
704 | ); | ||
705 | |||
706 | check_goto( | ||
707 | " | ||
708 | //- /lib.rs | ||
709 | enum Foo { | ||
710 | Variant1, | ||
711 | Variant2<|>, | ||
712 | Variant3, | ||
713 | } | ||
714 | ", | ||
715 | "Variant2 ENUM_VARIANT FileId(1) 29..37 29..37", | ||
716 | "Variant2|Variant2", | ||
717 | ); | 602 | ); |
718 | 603 | ||
719 | check_goto( | 604 | check( |
720 | r#" | 605 | r#" |
721 | //- /lib.rs | 606 | enum Foo { |
722 | static INNER<|>: &str = ""; | 607 | Variant1, |
723 | "#, | 608 | Variant2<|>, |
724 | "INNER STATIC_DEF FileId(1) 0..24 7..12", | 609 | //^^^^^^^^ |
725 | "static INNER: &str = \"\";|INNER", | 610 | Variant3, |
611 | } | ||
612 | "#, | ||
726 | ); | 613 | ); |
727 | 614 | ||
728 | check_goto( | 615 | check( |
729 | r#" | 616 | r#" |
730 | //- /lib.rs | 617 | static INNER<|>: &str = ""; |
731 | const INNER<|>: &str = ""; | 618 | //^^^^^ |
732 | "#, | 619 | "#, |
733 | "INNER CONST_DEF FileId(1) 0..23 6..11", | ||
734 | "const INNER: &str = \"\";|INNER", | ||
735 | ); | 620 | ); |
736 | 621 | ||
737 | check_goto( | 622 | check( |
738 | r#" | 623 | r#" |
739 | //- /lib.rs | 624 | const INNER<|>: &str = ""; |
740 | type Thing<|> = Option<()>; | 625 | //^^^^^ |
741 | "#, | 626 | "#, |
742 | "Thing TYPE_ALIAS_DEF FileId(1) 0..24 5..10", | ||
743 | "type Thing = Option<()>;|Thing", | ||
744 | ); | 627 | ); |
745 | 628 | ||
746 | check_goto( | 629 | check( |
747 | r#" | 630 | r#" |
748 | //- /lib.rs | 631 | type Thing<|> = Option<()>; |
749 | trait Foo<|> { } | 632 | //^^^^^ |
750 | "#, | 633 | "#, |
751 | "Foo TRAIT_DEF FileId(1) 0..13 6..9", | ||
752 | "trait Foo { }|Foo", | ||
753 | ); | 634 | ); |
754 | 635 | ||
755 | check_goto( | 636 | check( |
756 | r#" | 637 | r#" |
757 | //- /lib.rs | 638 | trait Foo<|> { } |
758 | mod bar<|> { } | 639 | //^^^ |
759 | "#, | 640 | "#, |
760 | "bar MODULE FileId(1) 0..11 4..7", | 641 | ); |
761 | "mod bar { }|bar", | 642 | |
643 | check( | ||
644 | r#" | ||
645 | mod bar<|> { } | ||
646 | //^^^ | ||
647 | "#, | ||
762 | ); | 648 | ); |
763 | } | 649 | } |
764 | 650 | ||
765 | #[test] | 651 | #[test] |
766 | fn goto_from_macro() { | 652 | fn goto_from_macro() { |
767 | check_goto( | 653 | check( |
768 | " | 654 | r#" |
769 | //- /lib.rs | 655 | macro_rules! id { |
770 | macro_rules! id { | 656 | ($($tt:tt)*) => { $($tt)* } |
771 | ($($tt:tt)*) => { $($tt)* } | 657 | } |
772 | } | 658 | fn foo() {} |
773 | fn foo() {} | 659 | //^^^ |
774 | id! { | 660 | id! { |
775 | fn bar() { | 661 | fn bar() { |
776 | fo<|>o(); | 662 | fo<|>o(); |
777 | } | 663 | } |
778 | } | 664 | } |
779 | mod confuse_index { fn foo(); } | 665 | mod confuse_index { fn foo(); } |
780 | ", | 666 | "#, |
781 | "foo FN_DEF FileId(1) 52..63 55..58", | ||
782 | "fn foo() {}|foo", | ||
783 | ); | 667 | ); |
784 | } | 668 | } |
785 | 669 | ||
786 | #[test] | 670 | #[test] |
787 | fn goto_through_format() { | 671 | fn goto_through_format() { |
788 | check_goto( | 672 | check( |
789 | " | 673 | r#" |
790 | //- /lib.rs | 674 | #[macro_export] |
791 | #[macro_export] | 675 | macro_rules! format { |
792 | macro_rules! format { | 676 | ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) |
793 | ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) | 677 | } |
794 | } | 678 | #[rustc_builtin_macro] |
795 | #[rustc_builtin_macro] | 679 | #[macro_export] |
796 | #[macro_export] | 680 | macro_rules! format_args { |
797 | macro_rules! format_args { | 681 | ($fmt:expr) => ({ /* compiler built-in */ }); |
798 | ($fmt:expr) => ({ /* compiler built-in */ }); | 682 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) |
799 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | 683 | } |
800 | } | 684 | pub mod __export { |
801 | pub mod __export { | 685 | pub use crate::format_args; |
802 | pub use crate::format_args; | 686 | fn foo() {} // for index confusion |
803 | fn foo() {} // for index confusion | 687 | } |
804 | } | 688 | fn foo() -> i8 {} |
805 | fn foo() -> i8 {} | 689 | //^^^ |
806 | fn test() { | 690 | fn test() { |
807 | format!(\"{}\", fo<|>o()) | 691 | format!("{}", fo<|>o()) |
808 | } | 692 | } |
809 | ", | 693 | "#, |
810 | "foo FN_DEF FileId(1) 398..415 401..404", | ||
811 | "fn foo() -> i8 {}|foo", | ||
812 | ); | 694 | ); |
813 | } | 695 | } |
814 | 696 | ||
815 | #[test] | 697 | #[test] |
816 | fn goto_for_type_param() { | 698 | fn goto_for_type_param() { |
817 | check_goto( | 699 | check( |
818 | r#" | 700 | r#" |
819 | //- /lib.rs | 701 | struct Foo<T: Clone> { t: <|>T } |
820 | struct Foo<T: Clone> { | 702 | //^ |
821 | t: <|>T, | 703 | "#, |
822 | } | ||
823 | "#, | ||
824 | "T TYPE_PARAM FileId(1) 11..19 11..12", | ||
825 | "T: Clone|T", | ||
826 | ); | 704 | ); |
827 | } | 705 | } |
828 | 706 | ||
829 | #[test] | 707 | #[test] |
830 | fn goto_within_macro() { | 708 | fn goto_within_macro() { |
831 | check_goto( | 709 | check( |
832 | r#" | 710 | r#" |
833 | //- /lib.rs | ||
834 | macro_rules! id { | 711 | macro_rules! id { |
835 | ($($tt:tt)*) => ($($tt)*) | 712 | ($($tt:tt)*) => ($($tt)*) |
836 | } | 713 | } |
837 | 714 | ||
838 | fn foo() { | 715 | fn foo() { |
839 | let x = 1; | 716 | let x = 1; |
717 | //^ | ||
840 | id!({ | 718 | id!({ |
841 | let y = <|>x; | 719 | let y = <|>x; |
842 | let z = y; | 720 | let z = y; |
843 | }); | 721 | }); |
844 | } | 722 | } |
845 | "#, | 723 | "#, |
846 | "x BIND_PAT FileId(1) 70..71", | ||
847 | "x", | ||
848 | ); | 724 | ); |
849 | 725 | ||
850 | check_goto( | 726 | check( |
851 | r#" | 727 | r#" |
852 | //- /lib.rs | ||
853 | macro_rules! id { | 728 | macro_rules! id { |
854 | ($($tt:tt)*) => ($($tt)*) | 729 | ($($tt:tt)*) => ($($tt)*) |
855 | } | 730 | } |
@@ -858,159 +733,125 @@ fn foo() { | |||
858 | let x = 1; | 733 | let x = 1; |
859 | id!({ | 734 | id!({ |
860 | let y = x; | 735 | let y = x; |
736 | //^ | ||
861 | let z = <|>y; | 737 | let z = <|>y; |
862 | }); | 738 | }); |
863 | } | 739 | } |
864 | "#, | 740 | "#, |
865 | "y BIND_PAT FileId(1) 99..100", | ||
866 | "y", | ||
867 | ); | 741 | ); |
868 | } | 742 | } |
869 | 743 | ||
870 | #[test] | 744 | #[test] |
871 | fn goto_def_in_local_fn() { | 745 | fn goto_def_in_local_fn() { |
872 | check_goto( | 746 | check( |
873 | " | 747 | r#" |
874 | //- /lib.rs | 748 | fn main() { |
875 | fn main() { | 749 | fn foo() { |
876 | fn foo() { | 750 | let x = 92; |
877 | let x = 92; | 751 | //^ |
878 | <|>x; | 752 | <|>x; |
879 | } | 753 | } |
880 | } | 754 | } |
881 | ", | 755 | "#, |
882 | "x BIND_PAT FileId(1) 39..40", | ||
883 | "x", | ||
884 | ); | 756 | ); |
885 | } | 757 | } |
886 | 758 | ||
887 | #[test] | 759 | #[test] |
888 | fn goto_def_in_local_macro() { | 760 | fn goto_def_in_local_macro() { |
889 | check_goto( | 761 | check( |
890 | r" | 762 | r#" |
891 | //- /lib.rs | 763 | fn bar() { |
892 | fn bar() { | 764 | macro_rules! foo { () => { () } } |
893 | macro_rules! foo { () => { () } } | 765 | //^^^ |
894 | <|>foo!(); | 766 | <|>foo!(); |
895 | } | 767 | } |
896 | ", | 768 | "#, |
897 | "foo MACRO_CALL FileId(1) 15..48 28..31", | ||
898 | "macro_rules! foo { () => { () } }|foo", | ||
899 | ); | 769 | ); |
900 | } | 770 | } |
901 | 771 | ||
902 | #[test] | 772 | #[test] |
903 | fn goto_def_for_field_init_shorthand() { | 773 | fn goto_def_for_field_init_shorthand() { |
904 | check_goto( | 774 | check( |
905 | " | 775 | r#" |
906 | //- /lib.rs | 776 | struct Foo { x: i32 } |
907 | struct Foo { x: i32 } | 777 | fn main() { |
908 | fn main() { | 778 | let x = 92; |
909 | let x = 92; | 779 | //^ |
910 | Foo { x<|> }; | 780 | Foo { x<|> }; |
911 | } | 781 | } |
912 | ", | 782 | "#, |
913 | "x BIND_PAT FileId(1) 42..43", | ||
914 | "x", | ||
915 | ) | 783 | ) |
916 | } | 784 | } |
917 | 785 | ||
918 | #[test] | 786 | #[test] |
919 | fn goto_def_for_enum_variant_field() { | 787 | fn goto_def_for_enum_variant_field() { |
920 | check_goto( | 788 | check( |
921 | " | 789 | r#" |
922 | //- /lib.rs | 790 | enum Foo { |
923 | enum Foo { | 791 | Bar { x: i32 } |
924 | Bar { x: i32 } | 792 | } //^ |
925 | } | 793 | fn baz(foo: Foo) { |
926 | fn baz(foo: Foo) { | 794 | match foo { |
927 | match foo { | 795 | Foo::Bar { x<|> } => x |
928 | Foo::Bar { x<|> } => x | 796 | }; |
929 | }; | 797 | } |
930 | } | 798 | "#, |
931 | ", | ||
932 | "x RECORD_FIELD_DEF FileId(1) 21..27 21..22", | ||
933 | "x: i32|x", | ||
934 | ); | 799 | ); |
935 | } | 800 | } |
936 | 801 | ||
937 | #[test] | 802 | #[test] |
938 | fn goto_def_for_enum_variant_self_pattern_const() { | 803 | fn goto_def_for_enum_variant_self_pattern_const() { |
939 | check_goto( | 804 | check( |
940 | " | 805 | r#" |
941 | //- /lib.rs | 806 | enum Foo { Bar } |
942 | enum Foo { | 807 | //^^^ |
943 | Bar, | 808 | impl Foo { |
944 | } | 809 | fn baz(self) { |
945 | impl Foo { | 810 | match self { Self::Bar<|> => {} } |
946 | fn baz(self) { | 811 | } |
947 | match self { | 812 | } |
948 | Self::Bar<|> => {} | 813 | "#, |
949 | } | ||
950 | } | ||
951 | } | ||
952 | ", | ||
953 | "Bar ENUM_VARIANT FileId(1) 15..18 15..18", | ||
954 | "Bar|Bar", | ||
955 | ); | 814 | ); |
956 | } | 815 | } |
957 | 816 | ||
958 | #[test] | 817 | #[test] |
959 | fn goto_def_for_enum_variant_self_pattern_record() { | 818 | fn goto_def_for_enum_variant_self_pattern_record() { |
960 | check_goto( | 819 | check( |
961 | " | 820 | r#" |
962 | //- /lib.rs | 821 | enum Foo { Bar { val: i32 } } |
963 | enum Foo { | 822 | //^^^ |
964 | Bar { val: i32 }, | 823 | impl Foo { |
965 | } | 824 | fn baz(self) -> i32 { |
966 | impl Foo { | 825 | match self { Self::Bar<|> { val } => {} } |
967 | fn baz(self) -> i32 { | 826 | } |
968 | match self { | 827 | } |
969 | Self::Bar<|> { val } => {} | 828 | "#, |
970 | } | ||
971 | } | ||
972 | } | ||
973 | ", | ||
974 | "Bar ENUM_VARIANT FileId(1) 15..31 15..18", | ||
975 | "Bar { val: i32 }|Bar", | ||
976 | ); | 829 | ); |
977 | } | 830 | } |
978 | 831 | ||
979 | #[test] | 832 | #[test] |
980 | fn goto_def_for_enum_variant_self_expr_const() { | 833 | fn goto_def_for_enum_variant_self_expr_const() { |
981 | check_goto( | 834 | check( |
982 | " | 835 | r#" |
983 | //- /lib.rs | 836 | enum Foo { Bar } |
984 | enum Foo { | 837 | //^^^ |
985 | Bar, | 838 | impl Foo { |
986 | } | 839 | fn baz(self) { Self::Bar<|>; } |
987 | impl Foo { | 840 | } |
988 | fn baz(self) { | 841 | "#, |
989 | Self::Bar<|>; | ||
990 | } | ||
991 | } | ||
992 | ", | ||
993 | "Bar ENUM_VARIANT FileId(1) 15..18 15..18", | ||
994 | "Bar|Bar", | ||
995 | ); | 842 | ); |
996 | } | 843 | } |
997 | 844 | ||
998 | #[test] | 845 | #[test] |
999 | fn goto_def_for_enum_variant_self_expr_record() { | 846 | fn goto_def_for_enum_variant_self_expr_record() { |
1000 | check_goto( | 847 | check( |
1001 | " | 848 | r#" |
1002 | //- /lib.rs | 849 | enum Foo { Bar { val: i32 } } |
1003 | enum Foo { | 850 | //^^^ |
1004 | Bar { val: i32 }, | 851 | impl Foo { |
1005 | } | 852 | fn baz(self) { Self::Bar<|> {val: 4}; } |
1006 | impl Foo { | 853 | } |
1007 | fn baz(self) { | 854 | "#, |
1008 | Self::Bar<|> {val: 4}; | ||
1009 | } | ||
1010 | } | ||
1011 | ", | ||
1012 | "Bar ENUM_VARIANT FileId(1) 15..31 15..18", | ||
1013 | "Bar { val: i32 }|Bar", | ||
1014 | ); | 855 | ); |
1015 | } | 856 | } |
1016 | } | 857 | } |
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 0cec0657e..99a7022a4 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs | |||
@@ -74,135 +74,152 @@ fn impls_for_trait( | |||
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
76 | mod tests { | 76 | mod tests { |
77 | use crate::mock_analysis::analysis_and_position; | 77 | use ra_db::FileRange; |
78 | 78 | ||
79 | fn check_goto(fixture: &str, expected: &[&str]) { | 79 | use crate::mock_analysis::MockAnalysis; |
80 | let (analysis, pos) = analysis_and_position(fixture); | ||
81 | 80 | ||
82 | let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info; | 81 | fn check(ra_fixture: &str) { |
83 | assert_eq!(navs.len(), expected.len()); | 82 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); |
84 | navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start())); | 83 | let annotations = mock.annotations(); |
85 | navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); | 84 | let analysis = mock.analysis(); |
85 | |||
86 | let navs = analysis.goto_implementation(position).unwrap().unwrap().info; | ||
87 | |||
88 | let key = |frange: &FileRange| (frange.file_id, frange.range.start()); | ||
89 | |||
90 | let mut expected = annotations | ||
91 | .into_iter() | ||
92 | .map(|(range, data)| { | ||
93 | assert!(data.is_empty()); | ||
94 | range | ||
95 | }) | ||
96 | .collect::<Vec<_>>(); | ||
97 | expected.sort_by_key(key); | ||
98 | |||
99 | let mut actual = navs | ||
100 | .into_iter() | ||
101 | .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() }) | ||
102 | .collect::<Vec<_>>(); | ||
103 | actual.sort_by_key(key); | ||
104 | |||
105 | assert_eq!(expected, actual); | ||
86 | } | 106 | } |
87 | 107 | ||
88 | #[test] | 108 | #[test] |
89 | fn goto_implementation_works() { | 109 | fn goto_implementation_works() { |
90 | check_goto( | 110 | check( |
91 | " | 111 | r#" |
92 | //- /lib.rs | 112 | struct Foo<|>; |
93 | struct Foo<|>; | 113 | impl Foo {} |
94 | impl Foo {} | 114 | //^^^ |
95 | ", | 115 | "#, |
96 | &["impl IMPL_DEF FileId(1) 12..23"], | ||
97 | ); | 116 | ); |
98 | } | 117 | } |
99 | 118 | ||
100 | #[test] | 119 | #[test] |
101 | fn goto_implementation_works_multiple_blocks() { | 120 | fn goto_implementation_works_multiple_blocks() { |
102 | check_goto( | 121 | check( |
103 | " | 122 | r#" |
104 | //- /lib.rs | 123 | struct Foo<|>; |
105 | struct Foo<|>; | 124 | impl Foo {} |
106 | impl Foo {} | 125 | //^^^ |
107 | impl Foo {} | 126 | impl Foo {} |
108 | ", | 127 | //^^^ |
109 | &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"], | 128 | "#, |
110 | ); | 129 | ); |
111 | } | 130 | } |
112 | 131 | ||
113 | #[test] | 132 | #[test] |
114 | fn goto_implementation_works_multiple_mods() { | 133 | fn goto_implementation_works_multiple_mods() { |
115 | check_goto( | 134 | check( |
116 | " | 135 | r#" |
117 | //- /lib.rs | 136 | struct Foo<|>; |
118 | struct Foo<|>; | 137 | mod a { |
119 | mod a { | 138 | impl super::Foo {} |
120 | impl super::Foo {} | 139 | //^^^^^^^^^^ |
121 | } | 140 | } |
122 | mod b { | 141 | mod b { |
123 | impl super::Foo {} | 142 | impl super::Foo {} |
124 | } | 143 | //^^^^^^^^^^ |
125 | ", | 144 | } |
126 | &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"], | 145 | "#, |
127 | ); | 146 | ); |
128 | } | 147 | } |
129 | 148 | ||
130 | #[test] | 149 | #[test] |
131 | fn goto_implementation_works_multiple_files() { | 150 | fn goto_implementation_works_multiple_files() { |
132 | check_goto( | 151 | check( |
133 | " | 152 | r#" |
134 | //- /lib.rs | 153 | //- /lib.rs |
135 | struct Foo<|>; | 154 | struct Foo<|>; |
136 | mod a; | 155 | mod a; |
137 | mod b; | 156 | mod b; |
138 | //- /a.rs | 157 | //- /a.rs |
139 | impl crate::Foo {} | 158 | impl crate::Foo {} |
140 | //- /b.rs | 159 | //^^^^^^^^^^ |
141 | impl crate::Foo {} | 160 | //- /b.rs |
142 | ", | 161 | impl crate::Foo {} |
143 | &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"], | 162 | //^^^^^^^^^^ |
163 | "#, | ||
144 | ); | 164 | ); |
145 | } | 165 | } |
146 | 166 | ||
147 | #[test] | 167 | #[test] |
148 | fn goto_implementation_for_trait() { | 168 | fn goto_implementation_for_trait() { |
149 | check_goto( | 169 | check( |
150 | " | 170 | r#" |
151 | //- /lib.rs | 171 | trait T<|> {} |
152 | trait T<|> {} | 172 | struct Foo; |
153 | struct Foo; | 173 | impl T for Foo {} |
154 | impl T for Foo {} | 174 | //^^^ |
155 | ", | 175 | "#, |
156 | &["impl IMPL_DEF FileId(1) 23..40"], | ||
157 | ); | 176 | ); |
158 | } | 177 | } |
159 | 178 | ||
160 | #[test] | 179 | #[test] |
161 | fn goto_implementation_for_trait_multiple_files() { | 180 | fn goto_implementation_for_trait_multiple_files() { |
162 | check_goto( | 181 | check( |
163 | " | 182 | r#" |
164 | //- /lib.rs | 183 | //- /lib.rs |
165 | trait T<|> {}; | 184 | trait T<|> {}; |
166 | struct Foo; | 185 | struct Foo; |
167 | mod a; | 186 | mod a; |
168 | mod b; | 187 | mod b; |
169 | //- /a.rs | 188 | //- /a.rs |
170 | impl crate::T for crate::Foo {} | 189 | impl crate::T for crate::Foo {} |
171 | //- /b.rs | 190 | //^^^^^^^^^^ |
172 | impl crate::T for crate::Foo {} | 191 | //- /b.rs |
173 | ", | 192 | impl crate::T for crate::Foo {} |
174 | &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"], | 193 | //^^^^^^^^^^ |
194 | "#, | ||
175 | ); | 195 | ); |
176 | } | 196 | } |
177 | 197 | ||
178 | #[test] | 198 | #[test] |
179 | fn goto_implementation_all_impls() { | 199 | fn goto_implementation_all_impls() { |
180 | check_goto( | 200 | check( |
181 | " | 201 | r#" |
182 | //- /lib.rs | 202 | //- /lib.rs |
183 | trait T {} | 203 | trait T {} |
184 | struct Foo<|>; | 204 | struct Foo<|>; |
185 | impl Foo {} | 205 | impl Foo {} |
186 | impl T for Foo {} | 206 | //^^^ |
187 | impl T for &Foo {} | 207 | impl T for Foo {} |
188 | ", | 208 | //^^^ |
189 | &[ | 209 | impl T for &Foo {} |
190 | "impl IMPL_DEF FileId(1) 23..34", | 210 | //^^^^ |
191 | "impl IMPL_DEF FileId(1) 35..52", | 211 | "#, |
192 | "impl IMPL_DEF FileId(1) 53..71", | ||
193 | ], | ||
194 | ); | 212 | ); |
195 | } | 213 | } |
196 | 214 | ||
197 | #[test] | 215 | #[test] |
198 | fn goto_implementation_to_builtin_derive() { | 216 | fn goto_implementation_to_builtin_derive() { |
199 | check_goto( | 217 | check( |
200 | " | 218 | r#" |
201 | //- /lib.rs | 219 | #[derive(Copy)] |
202 | #[derive(Copy)] | 220 | //^^^^^^^^^^^^^^^ |
203 | struct Foo<|>; | 221 | struct Foo<|>; |
204 | ", | 222 | "#, |
205 | &["impl IMPL_DEF FileId(1) 0..15"], | ||
206 | ); | 223 | ); |
207 | } | 224 | } |
208 | } | 225 | } |
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 889b84c59..db6d50694 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -3,7 +3,9 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use ra_cfg::CfgOptions; | 4 | use ra_cfg::CfgOptions; |
5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; | 5 | use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; |
6 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; | 6 | use test_utils::{ |
7 | extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, | ||
8 | }; | ||
7 | 9 | ||
8 | use crate::{ | 10 | use crate::{ |
9 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, | 11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
@@ -77,6 +79,24 @@ impl MockAnalysis { | |||
77 | .expect("no file in this mock"); | 79 | .expect("no file in this mock"); |
78 | FileId(idx as u32 + 1) | 80 | FileId(idx as u32 + 1) |
79 | } | 81 | } |
82 | pub fn annotations(&self) -> Vec<(FileRange, String)> { | ||
83 | self.files | ||
84 | .iter() | ||
85 | .enumerate() | ||
86 | .flat_map(|(idx, fixture)| { | ||
87 | let file_id = FileId(idx as u32 + 1); | ||
88 | let annotations = extract_annotations(&fixture.text); | ||
89 | annotations | ||
90 | .into_iter() | ||
91 | .map(move |(range, data)| (FileRange { file_id, range }, data)) | ||
92 | }) | ||
93 | .collect() | ||
94 | } | ||
95 | pub fn annotation(&self) -> (FileRange, String) { | ||
96 | let mut all = self.annotations(); | ||
97 | assert_eq!(all.len(), 1); | ||
98 | all.pop().unwrap() | ||
99 | } | ||
80 | pub fn analysis_host(self) -> AnalysisHost { | 100 | pub fn analysis_host(self) -> AnalysisHost { |
81 | let mut host = AnalysisHost::default(); | 101 | let mut host = AnalysisHost::default(); |
82 | let mut change = AnalysisChange::new(); | 102 | let mut change = AnalysisChange::new(); |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 0940fcc28..25bcd80af 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -330,11 +330,12 @@ pub(crate) fn handle_workspace_symbol( | |||
330 | fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { | 330 | fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { |
331 | let mut res = Vec::new(); | 331 | let mut res = Vec::new(); |
332 | for nav in snap.analysis.symbol_search(query)? { | 332 | for nav in snap.analysis.symbol_search(query)? { |
333 | let container_name = nav.container_name().map(|v| v.to_string()); | ||
333 | let info = SymbolInformation { | 334 | let info = SymbolInformation { |
334 | name: nav.name().to_string(), | 335 | name: nav.name().to_string(), |
335 | kind: to_proto::symbol_kind(nav.kind()), | 336 | kind: to_proto::symbol_kind(nav.kind()), |
336 | location: to_proto::location(snap, nav.file_range())?, | 337 | location: to_proto::location_from_nav(snap, nav)?, |
337 | container_name: nav.container_name().map(|v| v.to_string()), | 338 | container_name, |
338 | deprecated: None, | 339 | deprecated: None, |
339 | }; | 340 | }; |
340 | res.push(info); | 341 | res.push(info); |
@@ -1213,8 +1214,8 @@ fn show_impl_command_link( | |||
1213 | let position = to_proto::position(&line_index, position.offset); | 1214 | let position = to_proto::position(&line_index, position.offset); |
1214 | let locations: Vec<_> = nav_data | 1215 | let locations: Vec<_> = nav_data |
1215 | .info | 1216 | .info |
1216 | .iter() | 1217 | .into_iter() |
1217 | .filter_map(|it| to_proto::location(snap, it.file_range()).ok()) | 1218 | .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) |
1218 | .collect(); | 1219 | .collect(); |
1219 | let title = implementation_title(locations.len()); | 1220 | let title = implementation_title(locations.len()); |
1220 | let command = show_references_command(title, &uri, position, locations); | 1221 | let command = show_references_command(title, &uri, position, locations); |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index a03222ae9..a0a58f689 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -446,6 +446,18 @@ pub(crate) fn location( | |||
446 | Ok(loc) | 446 | Ok(loc) |
447 | } | 447 | } |
448 | 448 | ||
449 | /// Perefer using `location_link`, if the client has the cap. | ||
450 | pub(crate) fn location_from_nav( | ||
451 | snap: &GlobalStateSnapshot, | ||
452 | nav: NavigationTarget, | ||
453 | ) -> Result<lsp_types::Location> { | ||
454 | let url = url(snap, nav.file_id()); | ||
455 | let line_index = snap.analysis.file_line_index(nav.file_id())?; | ||
456 | let range = range(&line_index, nav.full_range()); | ||
457 | let loc = lsp_types::Location::new(url, range); | ||
458 | Ok(loc) | ||
459 | } | ||
460 | |||
449 | pub(crate) fn location_link( | 461 | pub(crate) fn location_link( |
450 | snap: &GlobalStateSnapshot, | 462 | snap: &GlobalStateSnapshot, |
451 | src: Option<FileRange>, | 463 | src: Option<FileRange>, |