aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/goto_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/goto_definition.rs')
-rw-r--r--crates/ra_ide/src/goto_definition.rs393
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
3use hir::{db::AstDatabase, Source}; 3use hir::{db::AstDatabase, InFile};
4use ra_syntax::{ 4use 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
9use crate::{ 11use 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
42fn 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
59pub(crate) fn reference_definition( 69pub(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
95pub(crate) fn name_definition( 103pub(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
118fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<NavigationTarget> { 126fn 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)]
215mod tests { 223mod 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}