diff options
author | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-12-23 14:35:31 +0000 |
commit | b21d9337d9200e2cfdc90b386591c72c302dc03e (patch) | |
tree | f81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_ide/src/goto_definition.rs | |
parent | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff) | |
parent | ce07a2daa9e53aa86a769f8641b14c2878444fbc (diff) |
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_ide/src/goto_definition.rs')
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 393 |
1 files changed, 314 insertions, 79 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index c10a6c844..79d332e8c 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -1,9 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{db::AstDatabase, Source}; | 3 | use hir::{db::AstDatabase, InFile}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, DocCommentsOwner}, | 5 | ast::{self, DocCommentsOwner}, |
6 | match_ast, AstNode, SyntaxNode, | 6 | match_ast, AstNode, |
7 | SyntaxKind::*, | ||
8 | SyntaxNode, SyntaxToken, TokenAtOffset, | ||
7 | }; | 9 | }; |
8 | 10 | ||
9 | use crate::{ | 11 | use crate::{ |
@@ -19,25 +21,33 @@ pub(crate) fn goto_definition( | |||
19 | position: FilePosition, | 21 | position: FilePosition, |
20 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { | 22 | ) -> Option<RangeInfo<Vec<NavigationTarget>>> { |
21 | let file = db.parse_or_expand(position.file_id.into())?; | 23 | let file = db.parse_or_expand(position.file_id.into())?; |
22 | let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; | 24 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
23 | let token = descend_into_macros(db, position.file_id, token); | 25 | let token = descend_into_macros(db, position.file_id, original_token.clone()); |
24 | 26 | ||
25 | let res = match_ast! { | 27 | let nav_targets = match_ast! { |
26 | match (token.value.parent()) { | 28 | match (token.value.parent()) { |
27 | ast::NameRef(name_ref) => { | 29 | ast::NameRef(name_ref) => { |
28 | let navs = reference_definition(db, token.with_value(&name_ref)).to_vec(); | 30 | reference_definition(db, token.with_value(&name_ref)).to_vec() |
29 | RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec()) | ||
30 | }, | 31 | }, |
31 | ast::Name(name) => { | 32 | ast::Name(name) => { |
32 | let navs = name_definition(db, token.with_value(&name))?; | 33 | name_definition(db, token.with_value(&name))? |
33 | RangeInfo::new(name.syntax().text_range(), navs) | ||
34 | |||
35 | }, | 34 | }, |
36 | _ => return None, | 35 | _ => return None, |
37 | } | 36 | } |
38 | }; | 37 | }; |
39 | 38 | ||
40 | Some(res) | 39 | Some(RangeInfo::new(original_token.text_range(), nav_targets)) |
40 | } | ||
41 | |||
42 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | ||
43 | return tokens.max_by_key(priority); | ||
44 | fn priority(n: &SyntaxToken) -> usize { | ||
45 | match n.kind() { | ||
46 | IDENT | INT_NUMBER => 2, | ||
47 | kind if kind.is_trivia() => 0, | ||
48 | _ => 1, | ||
49 | } | ||
50 | } | ||
41 | } | 51 | } |
42 | 52 | ||
43 | #[derive(Debug)] | 53 | #[derive(Debug)] |
@@ -58,15 +68,17 @@ impl ReferenceResult { | |||
58 | 68 | ||
59 | pub(crate) fn reference_definition( | 69 | pub(crate) fn reference_definition( |
60 | db: &RootDatabase, | 70 | db: &RootDatabase, |
61 | name_ref: Source<&ast::NameRef>, | 71 | name_ref: InFile<&ast::NameRef>, |
62 | ) -> ReferenceResult { | 72 | ) -> ReferenceResult { |
63 | use self::ReferenceResult::*; | 73 | use self::ReferenceResult::*; |
64 | 74 | ||
65 | let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); | 75 | let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); |
66 | match name_kind { | 76 | match name_kind { |
67 | Some(Macro(mac)) => return Exact(mac.to_nav(db)), | 77 | Some(Macro(it)) => return Exact(it.to_nav(db)), |
68 | Some(Field(field)) => return Exact(field.to_nav(db)), | 78 | Some(Field(it)) => return Exact(it.to_nav(db)), |
69 | Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), | 79 | Some(TypeParam(it)) => return Exact(it.to_nav(db)), |
80 | Some(AssocItem(it)) => return Exact(it.to_nav(db)), | ||
81 | Some(Local(it)) => return Exact(it.to_nav(db)), | ||
70 | Some(Def(def)) => match NavigationTarget::from_def(db, def) { | 82 | Some(Def(def)) => match NavigationTarget::from_def(db, def) { |
71 | Some(nav) => return Exact(nav), | 83 | Some(nav) => return Exact(nav), |
72 | None => return Approximate(vec![]), | 84 | None => return Approximate(vec![]), |
@@ -77,10 +89,6 @@ pub(crate) fn reference_definition( | |||
77 | // us to the actual type | 89 | // us to the actual type |
78 | return Exact(imp.to_nav(db)); | 90 | return Exact(imp.to_nav(db)); |
79 | } | 91 | } |
80 | Some(Local(local)) => return Exact(local.to_nav(db)), | ||
81 | Some(GenericParam(_)) => { | ||
82 | // FIXME: go to the generic param def | ||
83 | } | ||
84 | None => {} | 92 | None => {} |
85 | }; | 93 | }; |
86 | 94 | ||
@@ -94,7 +102,7 @@ pub(crate) fn reference_definition( | |||
94 | 102 | ||
95 | pub(crate) fn name_definition( | 103 | pub(crate) fn name_definition( |
96 | db: &RootDatabase, | 104 | db: &RootDatabase, |
97 | name: Source<&ast::Name>, | 105 | name: InFile<&ast::Name>, |
98 | ) -> Option<Vec<NavigationTarget>> { | 106 | ) -> Option<Vec<NavigationTarget>> { |
99 | let parent = name.value.syntax().parent()?; | 107 | let parent = name.value.syntax().parent()?; |
100 | 108 | ||
@@ -115,7 +123,7 @@ pub(crate) fn name_definition( | |||
115 | None | 123 | None |
116 | } | 124 | } |
117 | 125 | ||
118 | fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<NavigationTarget> { | 126 | fn named_target(db: &RootDatabase, node: InFile<&SyntaxNode>) -> Option<NavigationTarget> { |
119 | match_ast! { | 127 | match_ast! { |
120 | match (node.value) { | 128 | match (node.value) { |
121 | ast::StructDef(it) => { | 129 | ast::StructDef(it) => { |
@@ -213,21 +221,44 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati | |||
213 | 221 | ||
214 | #[cfg(test)] | 222 | #[cfg(test)] |
215 | mod tests { | 223 | mod tests { |
216 | use test_utils::covers; | 224 | use test_utils::{assert_eq_text, covers}; |
217 | 225 | ||
218 | use crate::mock_analysis::analysis_and_position; | 226 | use crate::mock_analysis::analysis_and_position; |
219 | 227 | ||
220 | fn check_goto(fixture: &str, expected: &str) { | 228 | fn check_goto(fixture: &str, expected: &str, expected_range: &str) { |
221 | let (analysis, pos) = analysis_and_position(fixture); | 229 | let (analysis, pos) = analysis_and_position(fixture); |
222 | 230 | ||
223 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | 231 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; |
224 | assert_eq!(navs.len(), 1); | 232 | assert_eq!(navs.len(), 1); |
233 | |||
225 | let nav = navs.pop().unwrap(); | 234 | let nav = navs.pop().unwrap(); |
235 | let file_text = analysis.file_text(nav.file_id()).unwrap(); | ||
236 | |||
237 | let mut actual = file_text[nav.full_range()].to_string(); | ||
238 | if let Some(focus) = nav.focus_range() { | ||
239 | actual += "|"; | ||
240 | actual += &file_text[focus]; | ||
241 | } | ||
242 | |||
243 | if !expected_range.contains("...") { | ||
244 | test_utils::assert_eq_text!(&actual, expected_range); | ||
245 | } else { | ||
246 | let mut parts = expected_range.split("..."); | ||
247 | let prefix = parts.next().unwrap(); | ||
248 | let suffix = parts.next().unwrap(); | ||
249 | assert!( | ||
250 | actual.starts_with(prefix) && actual.ends_with(suffix), | ||
251 | "\nExpected: {}\n Actual: {}\n", | ||
252 | expected_range, | ||
253 | actual | ||
254 | ); | ||
255 | } | ||
256 | |||
226 | nav.assert_match(expected); | 257 | nav.assert_match(expected); |
227 | } | 258 | } |
228 | 259 | ||
229 | #[test] | 260 | #[test] |
230 | fn goto_definition_works_in_items() { | 261 | fn goto_def_in_items() { |
231 | check_goto( | 262 | check_goto( |
232 | " | 263 | " |
233 | //- /lib.rs | 264 | //- /lib.rs |
@@ -235,6 +266,20 @@ mod tests { | |||
235 | enum E { X(Foo<|>) } | 266 | enum E { X(Foo<|>) } |
236 | ", | 267 | ", |
237 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | 268 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", |
269 | "struct Foo;|Foo", | ||
270 | ); | ||
271 | } | ||
272 | |||
273 | #[test] | ||
274 | fn goto_def_at_start_of_item() { | ||
275 | check_goto( | ||
276 | " | ||
277 | //- /lib.rs | ||
278 | struct Foo; | ||
279 | enum E { X(<|>Foo) } | ||
280 | ", | ||
281 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
282 | "struct Foo;|Foo", | ||
238 | ); | 283 | ); |
239 | } | 284 | } |
240 | 285 | ||
@@ -247,61 +292,65 @@ mod tests { | |||
247 | mod a; | 292 | mod a; |
248 | mod b; | 293 | mod b; |
249 | enum E { X(Foo<|>) } | 294 | enum E { X(Foo<|>) } |
295 | |||
250 | //- /a.rs | 296 | //- /a.rs |
251 | struct Foo; | 297 | struct Foo; |
298 | |||
252 | //- /b.rs | 299 | //- /b.rs |
253 | struct Foo; | 300 | struct Foo; |
254 | ", | 301 | ", |
255 | "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", | 302 | "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", |
303 | "struct Foo;|Foo", | ||
256 | ); | 304 | ); |
257 | } | 305 | } |
258 | 306 | ||
259 | #[test] | 307 | #[test] |
260 | fn goto_definition_works_for_module_declaration() { | 308 | fn goto_def_for_module_declaration() { |
261 | check_goto( | 309 | check_goto( |
262 | " | 310 | " |
263 | //- /lib.rs | 311 | //- /lib.rs |
264 | mod <|>foo; | 312 | mod <|>foo; |
313 | |||
265 | //- /foo.rs | 314 | //- /foo.rs |
266 | // empty | 315 | // empty |
267 | ", | 316 | ", |
268 | "foo SOURCE_FILE FileId(2) [0; 10)", | 317 | "foo SOURCE_FILE FileId(2) [0; 10)", |
318 | "// empty\n\n", | ||
269 | ); | 319 | ); |
270 | 320 | ||
271 | check_goto( | 321 | check_goto( |
272 | " | 322 | " |
273 | //- /lib.rs | 323 | //- /lib.rs |
274 | mod <|>foo; | 324 | mod <|>foo; |
325 | |||
275 | //- /foo/mod.rs | 326 | //- /foo/mod.rs |
276 | // empty | 327 | // empty |
277 | ", | 328 | ", |
278 | "foo SOURCE_FILE FileId(2) [0; 10)", | 329 | "foo SOURCE_FILE FileId(2) [0; 10)", |
330 | "// empty\n\n", | ||
279 | ); | 331 | ); |
280 | } | 332 | } |
281 | 333 | ||
282 | #[test] | 334 | #[test] |
283 | fn goto_definition_works_for_macros() { | 335 | fn goto_def_for_macros() { |
284 | covers!(goto_definition_works_for_macros); | 336 | covers!(goto_def_for_macros); |
285 | check_goto( | 337 | check_goto( |
286 | " | 338 | " |
287 | //- /lib.rs | 339 | //- /lib.rs |
288 | macro_rules! foo { | 340 | macro_rules! foo { () => { () } } |
289 | () => { | ||
290 | {} | ||
291 | }; | ||
292 | } | ||
293 | 341 | ||
294 | fn bar() { | 342 | fn bar() { |
295 | <|>foo!(); | 343 | <|>foo!(); |
296 | } | 344 | } |
297 | ", | 345 | ", |
298 | "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", | 346 | "foo MACRO_CALL FileId(1) [0; 33) [13; 16)", |
347 | "macro_rules! foo { () => { () } }|foo", | ||
299 | ); | 348 | ); |
300 | } | 349 | } |
301 | 350 | ||
302 | #[test] | 351 | #[test] |
303 | fn goto_definition_works_for_macros_from_other_crates() { | 352 | fn goto_def_for_macros_from_other_crates() { |
304 | covers!(goto_definition_works_for_macros); | 353 | covers!(goto_def_for_macros); |
305 | check_goto( | 354 | check_goto( |
306 | " | 355 | " |
307 | //- /lib.rs | 356 | //- /lib.rs |
@@ -312,18 +361,15 @@ mod tests { | |||
312 | 361 | ||
313 | //- /foo/lib.rs | 362 | //- /foo/lib.rs |
314 | #[macro_export] | 363 | #[macro_export] |
315 | macro_rules! foo { | 364 | macro_rules! foo { () => { () } } |
316 | () => { | ||
317 | {} | ||
318 | }; | ||
319 | } | ||
320 | ", | 365 | ", |
321 | "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", | 366 | "foo MACRO_CALL FileId(2) [0; 49) [29; 32)", |
367 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
322 | ); | 368 | ); |
323 | } | 369 | } |
324 | 370 | ||
325 | #[test] | 371 | #[test] |
326 | fn goto_definition_works_for_macros_in_use_tree() { | 372 | fn goto_def_for_macros_in_use_tree() { |
327 | check_goto( | 373 | check_goto( |
328 | " | 374 | " |
329 | //- /lib.rs | 375 | //- /lib.rs |
@@ -331,18 +377,15 @@ mod tests { | |||
331 | 377 | ||
332 | //- /foo/lib.rs | 378 | //- /foo/lib.rs |
333 | #[macro_export] | 379 | #[macro_export] |
334 | macro_rules! foo { | 380 | macro_rules! foo { () => { () } } |
335 | () => { | ||
336 | {} | ||
337 | }; | ||
338 | } | ||
339 | ", | 381 | ", |
340 | "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", | 382 | "foo MACRO_CALL FileId(2) [0; 49) [29; 32)", |
383 | "#[macro_export]\nmacro_rules! foo { () => { () } }|foo", | ||
341 | ); | 384 | ); |
342 | } | 385 | } |
343 | 386 | ||
344 | #[test] | 387 | #[test] |
345 | fn goto_definition_works_for_macro_defined_fn_with_arg() { | 388 | fn goto_def_for_macro_defined_fn_with_arg() { |
346 | check_goto( | 389 | check_goto( |
347 | " | 390 | " |
348 | //- /lib.rs | 391 | //- /lib.rs |
@@ -350,20 +393,19 @@ mod tests { | |||
350 | ($name:ident) => (fn $name() {}) | 393 | ($name:ident) => (fn $name() {}) |
351 | } | 394 | } |
352 | 395 | ||
353 | define_fn!( | 396 | define_fn!(foo); |
354 | foo | ||
355 | ) | ||
356 | 397 | ||
357 | fn bar() { | 398 | fn bar() { |
358 | <|>foo(); | 399 | <|>foo(); |
359 | } | 400 | } |
360 | ", | 401 | ", |
361 | "foo FN_DEF FileId(1) [80; 83) [80; 83)", | 402 | "foo FN_DEF FileId(1) [64; 80) [75; 78)", |
403 | "define_fn!(foo);|foo", | ||
362 | ); | 404 | ); |
363 | } | 405 | } |
364 | 406 | ||
365 | #[test] | 407 | #[test] |
366 | fn goto_definition_works_for_macro_defined_fn_no_arg() { | 408 | fn goto_def_for_macro_defined_fn_no_arg() { |
367 | check_goto( | 409 | check_goto( |
368 | " | 410 | " |
369 | //- /lib.rs | 411 | //- /lib.rs |
@@ -377,32 +419,70 @@ mod tests { | |||
377 | <|>foo(); | 419 | <|>foo(); |
378 | } | 420 | } |
379 | ", | 421 | ", |
380 | "foo FN_DEF FileId(1) [39; 42) [39; 42)", | 422 | "foo FN_DEF FileId(1) [51; 64) [51; 64)", |
423 | "define_fn!();|define_fn!();", | ||
381 | ); | 424 | ); |
382 | } | 425 | } |
383 | 426 | ||
384 | #[test] | 427 | #[test] |
385 | fn goto_definition_works_for_methods() { | 428 | fn goto_definition_works_for_macro_inside_pattern() { |
386 | covers!(goto_definition_works_for_methods); | 429 | check_goto( |
430 | " | ||
431 | //- /lib.rs | ||
432 | macro_rules! foo {() => {0}} | ||
433 | |||
434 | fn bar() { | ||
435 | match (0,1) { | ||
436 | (<|>foo!(), _) => {} | ||
437 | } | ||
438 | } | ||
439 | ", | ||
440 | "foo MACRO_CALL FileId(1) [0; 28) [13; 16)", | ||
441 | "macro_rules! foo {() => {0}}|foo", | ||
442 | ); | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn goto_definition_works_for_macro_inside_match_arm_lhs() { | ||
447 | check_goto( | ||
448 | " | ||
449 | //- /lib.rs | ||
450 | macro_rules! foo {() => {0}} | ||
451 | |||
452 | fn bar() { | ||
453 | match 0 { | ||
454 | <|>foo!() => {} | ||
455 | } | ||
456 | } | ||
457 | ", | ||
458 | "foo MACRO_CALL FileId(1) [0; 28) [13; 16)", | ||
459 | "macro_rules! foo {() => {0}}|foo", | ||
460 | ); | ||
461 | } | ||
462 | |||
463 | #[test] | ||
464 | fn goto_def_for_methods() { | ||
465 | covers!(goto_def_for_methods); | ||
387 | check_goto( | 466 | check_goto( |
388 | " | 467 | " |
389 | //- /lib.rs | 468 | //- /lib.rs |
390 | struct Foo; | 469 | struct Foo; |
391 | impl Foo { | 470 | impl Foo { |
392 | fn frobnicate(&self) { } | 471 | fn frobnicate(&self) { } |
393 | } | 472 | } |
394 | 473 | ||
395 | fn bar(foo: &Foo) { | 474 | fn bar(foo: &Foo) { |
396 | foo.frobnicate<|>(); | 475 | foo.frobnicate<|>(); |
397 | } | 476 | } |
398 | ", | 477 | ", |
399 | "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", | 478 | "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)", |
479 | "fn frobnicate(&self) { }|frobnicate", | ||
400 | ); | 480 | ); |
401 | } | 481 | } |
402 | 482 | ||
403 | #[test] | 483 | #[test] |
404 | fn goto_definition_works_for_fields() { | 484 | fn goto_def_for_fields() { |
405 | covers!(goto_definition_works_for_fields); | 485 | covers!(goto_def_for_fields); |
406 | check_goto( | 486 | check_goto( |
407 | " | 487 | " |
408 | //- /lib.rs | 488 | //- /lib.rs |
@@ -415,12 +495,13 @@ mod tests { | |||
415 | } | 495 | } |
416 | ", | 496 | ", |
417 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", | 497 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", |
498 | "spam: u32|spam", | ||
418 | ); | 499 | ); |
419 | } | 500 | } |
420 | 501 | ||
421 | #[test] | 502 | #[test] |
422 | fn goto_definition_works_for_record_fields() { | 503 | fn goto_def_for_record_fields() { |
423 | covers!(goto_definition_works_for_record_fields); | 504 | covers!(goto_def_for_record_fields); |
424 | check_goto( | 505 | check_goto( |
425 | " | 506 | " |
426 | //- /lib.rs | 507 | //- /lib.rs |
@@ -435,29 +516,48 @@ mod tests { | |||
435 | } | 516 | } |
436 | ", | 517 | ", |
437 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", | 518 | "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", |
519 | "spam: u32|spam", | ||
520 | ); | ||
521 | } | ||
522 | |||
523 | #[test] | ||
524 | fn goto_for_tuple_fields() { | ||
525 | check_goto( | ||
526 | " | ||
527 | //- /lib.rs | ||
528 | struct Foo(u32); | ||
529 | |||
530 | fn bar() { | ||
531 | let foo = Foo(0); | ||
532 | foo.<|>0; | ||
533 | } | ||
534 | ", | ||
535 | "TUPLE_FIELD_DEF FileId(1) [11; 14)", | ||
536 | "u32", | ||
438 | ); | 537 | ); |
439 | } | 538 | } |
440 | 539 | ||
441 | #[test] | 540 | #[test] |
442 | fn goto_definition_works_for_ufcs_inherent_methods() { | 541 | fn goto_def_for_ufcs_inherent_methods() { |
443 | check_goto( | 542 | check_goto( |
444 | " | 543 | " |
445 | //- /lib.rs | 544 | //- /lib.rs |
446 | struct Foo; | 545 | struct Foo; |
447 | impl Foo { | 546 | impl Foo { |
448 | fn frobnicate() { } | 547 | fn frobnicate() { } |
449 | } | 548 | } |
450 | 549 | ||
451 | fn bar(foo: &Foo) { | 550 | fn bar(foo: &Foo) { |
452 | Foo::frobnicate<|>(); | 551 | Foo::frobnicate<|>(); |
453 | } | 552 | } |
454 | ", | 553 | ", |
455 | "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", | 554 | "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)", |
555 | "fn frobnicate() { }|frobnicate", | ||
456 | ); | 556 | ); |
457 | } | 557 | } |
458 | 558 | ||
459 | #[test] | 559 | #[test] |
460 | fn goto_definition_works_for_ufcs_trait_methods_through_traits() { | 560 | fn goto_def_for_ufcs_trait_methods_through_traits() { |
461 | check_goto( | 561 | check_goto( |
462 | " | 562 | " |
463 | //- /lib.rs | 563 | //- /lib.rs |
@@ -470,11 +570,12 @@ mod tests { | |||
470 | } | 570 | } |
471 | ", | 571 | ", |
472 | "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", | 572 | "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", |
573 | "fn frobnicate();|frobnicate", | ||
473 | ); | 574 | ); |
474 | } | 575 | } |
475 | 576 | ||
476 | #[test] | 577 | #[test] |
477 | fn goto_definition_works_for_ufcs_trait_methods_through_self() { | 578 | fn goto_def_for_ufcs_trait_methods_through_self() { |
478 | check_goto( | 579 | check_goto( |
479 | " | 580 | " |
480 | //- /lib.rs | 581 | //- /lib.rs |
@@ -489,6 +590,7 @@ mod tests { | |||
489 | } | 590 | } |
490 | ", | 591 | ", |
491 | "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", | 592 | "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", |
593 | "fn frobnicate();|frobnicate", | ||
492 | ); | 594 | ); |
493 | } | 595 | } |
494 | 596 | ||
@@ -505,6 +607,7 @@ mod tests { | |||
505 | } | 607 | } |
506 | ", | 608 | ", |
507 | "impl IMPL_BLOCK FileId(1) [12; 73)", | 609 | "impl IMPL_BLOCK FileId(1) [12; 73)", |
610 | "impl Foo {...}", | ||
508 | ); | 611 | ); |
509 | 612 | ||
510 | check_goto( | 613 | check_goto( |
@@ -518,6 +621,7 @@ mod tests { | |||
518 | } | 621 | } |
519 | ", | 622 | ", |
520 | "impl IMPL_BLOCK FileId(1) [12; 73)", | 623 | "impl IMPL_BLOCK FileId(1) [12; 73)", |
624 | "impl Foo {...}", | ||
521 | ); | 625 | ); |
522 | 626 | ||
523 | check_goto( | 627 | check_goto( |
@@ -531,6 +635,7 @@ mod tests { | |||
531 | } | 635 | } |
532 | ", | 636 | ", |
533 | "impl IMPL_BLOCK FileId(1) [15; 75)", | 637 | "impl IMPL_BLOCK FileId(1) [15; 75)", |
638 | "impl Foo {...}", | ||
534 | ); | 639 | ); |
535 | 640 | ||
536 | check_goto( | 641 | check_goto( |
@@ -543,6 +648,7 @@ mod tests { | |||
543 | } | 648 | } |
544 | ", | 649 | ", |
545 | "impl IMPL_BLOCK FileId(1) [15; 62)", | 650 | "impl IMPL_BLOCK FileId(1) [15; 62)", |
651 | "impl Foo {...}", | ||
546 | ); | 652 | ); |
547 | } | 653 | } |
548 | 654 | ||
@@ -562,6 +668,7 @@ mod tests { | |||
562 | } | 668 | } |
563 | ", | 669 | ", |
564 | "impl IMPL_BLOCK FileId(1) [49; 115)", | 670 | "impl IMPL_BLOCK FileId(1) [49; 115)", |
671 | "impl Make for Foo {...}", | ||
565 | ); | 672 | ); |
566 | 673 | ||
567 | check_goto( | 674 | check_goto( |
@@ -578,17 +685,19 @@ mod tests { | |||
578 | } | 685 | } |
579 | ", | 686 | ", |
580 | "impl IMPL_BLOCK FileId(1) [49; 115)", | 687 | "impl IMPL_BLOCK FileId(1) [49; 115)", |
688 | "impl Make for Foo {...}", | ||
581 | ); | 689 | ); |
582 | } | 690 | } |
583 | 691 | ||
584 | #[test] | 692 | #[test] |
585 | fn goto_definition_works_when_used_on_definition_name_itself() { | 693 | fn goto_def_when_used_on_definition_name_itself() { |
586 | check_goto( | 694 | check_goto( |
587 | " | 695 | " |
588 | //- /lib.rs | 696 | //- /lib.rs |
589 | struct Foo<|> { value: u32 } | 697 | struct Foo<|> { value: u32 } |
590 | ", | 698 | ", |
591 | "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", | 699 | "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", |
700 | "struct Foo { value: u32 }|Foo", | ||
592 | ); | 701 | ); |
593 | 702 | ||
594 | check_goto( | 703 | check_goto( |
@@ -599,15 +708,16 @@ mod tests { | |||
599 | } | 708 | } |
600 | "#, | 709 | "#, |
601 | "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", | 710 | "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", |
711 | "field: string|field", | ||
602 | ); | 712 | ); |
603 | 713 | ||
604 | check_goto( | 714 | check_goto( |
605 | " | 715 | " |
606 | //- /lib.rs | 716 | //- /lib.rs |
607 | fn foo_test<|>() { | 717 | fn foo_test<|>() { } |
608 | } | ||
609 | ", | 718 | ", |
610 | "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", | 719 | "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", |
720 | "fn foo_test() { }|foo_test", | ||
611 | ); | 721 | ); |
612 | 722 | ||
613 | check_goto( | 723 | check_goto( |
@@ -618,6 +728,7 @@ mod tests { | |||
618 | } | 728 | } |
619 | ", | 729 | ", |
620 | "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", | 730 | "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", |
731 | "enum Foo {...}|Foo", | ||
621 | ); | 732 | ); |
622 | 733 | ||
623 | check_goto( | 734 | check_goto( |
@@ -630,22 +741,25 @@ mod tests { | |||
630 | } | 741 | } |
631 | ", | 742 | ", |
632 | "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", | 743 | "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", |
744 | "Variant2|Variant2", | ||
633 | ); | 745 | ); |
634 | 746 | ||
635 | check_goto( | 747 | check_goto( |
636 | r#" | 748 | r#" |
637 | //- /lib.rs | 749 | //- /lib.rs |
638 | static inner<|>: &str = ""; | 750 | static INNER<|>: &str = ""; |
639 | "#, | 751 | "#, |
640 | "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", | 752 | "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)", |
753 | "static INNER: &str = \"\";|INNER", | ||
641 | ); | 754 | ); |
642 | 755 | ||
643 | check_goto( | 756 | check_goto( |
644 | r#" | 757 | r#" |
645 | //- /lib.rs | 758 | //- /lib.rs |
646 | const inner<|>: &str = ""; | 759 | const INNER<|>: &str = ""; |
647 | "#, | 760 | "#, |
648 | "inner CONST_DEF FileId(1) [0; 23) [6; 11)", | 761 | "INNER CONST_DEF FileId(1) [0; 23) [6; 11)", |
762 | "const INNER: &str = \"\";|INNER", | ||
649 | ); | 763 | ); |
650 | 764 | ||
651 | check_goto( | 765 | check_goto( |
@@ -654,24 +768,25 @@ mod tests { | |||
654 | type Thing<|> = Option<()>; | 768 | type Thing<|> = Option<()>; |
655 | "#, | 769 | "#, |
656 | "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", | 770 | "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", |
771 | "type Thing = Option<()>;|Thing", | ||
657 | ); | 772 | ); |
658 | 773 | ||
659 | check_goto( | 774 | check_goto( |
660 | r#" | 775 | r#" |
661 | //- /lib.rs | 776 | //- /lib.rs |
662 | trait Foo<|> { | 777 | trait Foo<|> { } |
663 | } | ||
664 | "#, | 778 | "#, |
665 | "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", | 779 | "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", |
780 | "trait Foo { }|Foo", | ||
666 | ); | 781 | ); |
667 | 782 | ||
668 | check_goto( | 783 | check_goto( |
669 | r#" | 784 | r#" |
670 | //- /lib.rs | 785 | //- /lib.rs |
671 | mod bar<|> { | 786 | mod bar<|> { } |
672 | } | ||
673 | "#, | 787 | "#, |
674 | "bar MODULE FileId(1) [0; 11) [4; 7)", | 788 | "bar MODULE FileId(1) [0; 11) [4; 7)", |
789 | "mod bar { }|bar", | ||
675 | ); | 790 | ); |
676 | } | 791 | } |
677 | 792 | ||
@@ -689,8 +804,128 @@ mod tests { | |||
689 | fo<|>o(); | 804 | fo<|>o(); |
690 | } | 805 | } |
691 | } | 806 | } |
807 | mod confuse_index { fn foo(); } | ||
692 | ", | 808 | ", |
693 | "foo FN_DEF FileId(1) [52; 63) [55; 58)", | 809 | "foo FN_DEF FileId(1) [52; 63) [55; 58)", |
810 | "fn foo() {}|foo", | ||
694 | ); | 811 | ); |
695 | } | 812 | } |
813 | |||
814 | #[test] | ||
815 | fn goto_through_format() { | ||
816 | check_goto( | ||
817 | " | ||
818 | //- /lib.rs | ||
819 | #[macro_export] | ||
820 | macro_rules! format { | ||
821 | ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) | ||
822 | } | ||
823 | #[rustc_builtin_macro] | ||
824 | #[macro_export] | ||
825 | macro_rules! format_args { | ||
826 | ($fmt:expr) => ({ /* compiler built-in */ }); | ||
827 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | ||
828 | } | ||
829 | pub mod __export { | ||
830 | pub use crate::format_args; | ||
831 | fn foo() {} // for index confusion | ||
832 | } | ||
833 | fn foo() -> i8 {} | ||
834 | fn test() { | ||
835 | format!(\"{}\", fo<|>o()) | ||
836 | } | ||
837 | ", | ||
838 | "foo FN_DEF FileId(1) [398; 415) [401; 404)", | ||
839 | "fn foo() -> i8 {}|foo", | ||
840 | ); | ||
841 | } | ||
842 | |||
843 | #[test] | ||
844 | fn goto_for_type_param() { | ||
845 | check_goto( | ||
846 | " | ||
847 | //- /lib.rs | ||
848 | struct Foo<T> { | ||
849 | t: <|>T, | ||
850 | } | ||
851 | ", | ||
852 | "T TYPE_PARAM FileId(1) [11; 12)", | ||
853 | "T", | ||
854 | ); | ||
855 | } | ||
856 | |||
857 | #[test] | ||
858 | fn goto_within_macro() { | ||
859 | check_goto( | ||
860 | " | ||
861 | //- /lib.rs | ||
862 | macro_rules! id { | ||
863 | ($($tt:tt)*) => ($($tt)*) | ||
864 | } | ||
865 | |||
866 | fn foo() { | ||
867 | let x = 1; | ||
868 | id!({ | ||
869 | let y = <|>x; | ||
870 | let z = y; | ||
871 | }); | ||
872 | } | ||
873 | ", | ||
874 | "x BIND_PAT FileId(1) [69; 70)", | ||
875 | "x", | ||
876 | ); | ||
877 | |||
878 | check_goto( | ||
879 | " | ||
880 | //- /lib.rs | ||
881 | macro_rules! id { | ||
882 | ($($tt:tt)*) => ($($tt)*) | ||
883 | } | ||
884 | |||
885 | fn foo() { | ||
886 | let x = 1; | ||
887 | id!({ | ||
888 | let y = x; | ||
889 | let z = <|>y; | ||
890 | }); | ||
891 | } | ||
892 | ", | ||
893 | "y BIND_PAT FileId(1) [98; 99)", | ||
894 | "y", | ||
895 | ); | ||
896 | } | ||
897 | |||
898 | #[test] | ||
899 | fn goto_def_in_local_fn() { | ||
900 | check_goto( | ||
901 | " | ||
902 | //- /lib.rs | ||
903 | fn main() { | ||
904 | fn foo() { | ||
905 | let x = 92; | ||
906 | <|>x; | ||
907 | } | ||
908 | } | ||
909 | ", | ||
910 | "x BIND_PAT FileId(1) [39; 40)", | ||
911 | "x", | ||
912 | ); | ||
913 | } | ||
914 | |||
915 | #[test] | ||
916 | fn goto_def_for_field_init_shorthand() { | ||
917 | covers!(goto_def_for_field_init_shorthand); | ||
918 | check_goto( | ||
919 | " | ||
920 | //- /lib.rs | ||
921 | struct Foo { x: i32 } | ||
922 | fn main() { | ||
923 | let x = 92; | ||
924 | Foo { x<|> }; | ||
925 | } | ||
926 | ", | ||
927 | "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)", | ||
928 | "x: i32|x", | ||
929 | ) | ||
930 | } | ||
696 | } | 931 | } |