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.rs243
1 files changed, 173 insertions, 70 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index bee8e9df2..9b5744789 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -225,35 +225,40 @@ mod tests {
225 225
226 use crate::mock_analysis::analysis_and_position; 226 use crate::mock_analysis::analysis_and_position;
227 227
228 fn check_goto(fixture: &str, expected: &str) { 228 fn check_goto(fixture: &str, expected: &str, expected_range: &str) {
229 let (analysis, pos) = analysis_and_position(fixture); 229 let (analysis, pos) = analysis_and_position(fixture);
230 230
231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
232 assert_eq!(navs.len(), 1); 232 assert_eq!(navs.len(), 1);
233 let nav = navs.pop().unwrap();
234 nav.assert_match(expected);
235 }
236
237 fn check_goto_with_range_content(fixture: &str, expected: &str, expected_range: &str) {
238 let (analysis, pos) = analysis_and_position(fixture);
239 233
240 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
241 assert_eq!(navs.len(), 1);
242 let nav = navs.pop().unwrap(); 234 let nav = navs.pop().unwrap();
243 let file_text = analysis.file_text(pos.file_id).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 }
244 242
245 let actual_full_range = &file_text[nav.full_range()]; 243 if !expected_range.contains("...") {
246 let actual_range = &file_text[nav.range()]; 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 }
247 256
248 test_utils::assert_eq_text!(
249 &format!("{}|{}", actual_full_range, actual_range),
250 expected_range
251 );
252 nav.assert_match(expected); 257 nav.assert_match(expected);
253 } 258 }
254 259
255 #[test] 260 #[test]
256 fn goto_definition_works_in_items() { 261 fn goto_def_in_items() {
257 check_goto( 262 check_goto(
258 " 263 "
259 //- /lib.rs 264 //- /lib.rs
@@ -261,11 +266,12 @@ mod tests {
261 enum E { X(Foo<|>) } 266 enum E { X(Foo<|>) }
262 ", 267 ",
263 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 268 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
269 "struct Foo;|Foo",
264 ); 270 );
265 } 271 }
266 272
267 #[test] 273 #[test]
268 fn goto_definition_works_at_start_of_item() { 274 fn goto_def_at_start_of_item() {
269 check_goto( 275 check_goto(
270 " 276 "
271 //- /lib.rs 277 //- /lib.rs
@@ -273,6 +279,7 @@ mod tests {
273 enum E { X(<|>Foo) } 279 enum E { X(<|>Foo) }
274 ", 280 ",
275 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 281 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
282 "struct Foo;|Foo",
276 ); 283 );
277 } 284 }
278 285
@@ -285,61 +292,65 @@ mod tests {
285 mod a; 292 mod a;
286 mod b; 293 mod b;
287 enum E { X(Foo<|>) } 294 enum E { X(Foo<|>) }
295
288 //- /a.rs 296 //- /a.rs
289 struct Foo; 297 struct Foo;
298
290 //- /b.rs 299 //- /b.rs
291 struct Foo; 300 struct Foo;
292 ", 301 ",
293 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", 302 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)",
303 "struct Foo;|Foo",
294 ); 304 );
295 } 305 }
296 306
297 #[test] 307 #[test]
298 fn goto_definition_works_for_module_declaration() { 308 fn goto_def_for_module_declaration() {
299 check_goto( 309 check_goto(
300 " 310 "
301 //- /lib.rs 311 //- /lib.rs
302 mod <|>foo; 312 mod <|>foo;
313
303 //- /foo.rs 314 //- /foo.rs
304 // empty 315 // empty
305 ", 316 ",
306 "foo SOURCE_FILE FileId(2) [0; 10)", 317 "foo SOURCE_FILE FileId(2) [0; 10)",
318 "// empty\n\n",
307 ); 319 );
308 320
309 check_goto( 321 check_goto(
310 " 322 "
311 //- /lib.rs 323 //- /lib.rs
312 mod <|>foo; 324 mod <|>foo;
325
313 //- /foo/mod.rs 326 //- /foo/mod.rs
314 // empty 327 // empty
315 ", 328 ",
316 "foo SOURCE_FILE FileId(2) [0; 10)", 329 "foo SOURCE_FILE FileId(2) [0; 10)",
330 "// empty\n\n",
317 ); 331 );
318 } 332 }
319 333
320 #[test] 334 #[test]
321 fn goto_definition_works_for_macros() { 335 fn goto_def_for_macros() {
322 covers!(goto_definition_works_for_macros); 336 covers!(goto_def_for_macros);
323 check_goto( 337 check_goto(
324 " 338 "
325 //- /lib.rs 339 //- /lib.rs
326 macro_rules! foo { 340 macro_rules! foo { () => { () } }
327 () => {
328 {}
329 };
330 }
331 341
332 fn bar() { 342 fn bar() {
333 <|>foo!(); 343 <|>foo!();
334 } 344 }
335 ", 345 ",
336 "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", 346 "foo MACRO_CALL FileId(1) [0; 33) [13; 16)",
347 "macro_rules! foo { () => { () } }|foo",
337 ); 348 );
338 } 349 }
339 350
340 #[test] 351 #[test]
341 fn goto_definition_works_for_macros_from_other_crates() { 352 fn goto_def_for_macros_from_other_crates() {
342 covers!(goto_definition_works_for_macros); 353 covers!(goto_def_for_macros);
343 check_goto( 354 check_goto(
344 " 355 "
345 //- /lib.rs 356 //- /lib.rs
@@ -350,18 +361,15 @@ mod tests {
350 361
351 //- /foo/lib.rs 362 //- /foo/lib.rs
352 #[macro_export] 363 #[macro_export]
353 macro_rules! foo { 364 macro_rules! foo { () => { () } }
354 () => {
355 {}
356 };
357 }
358 ", 365 ",
359 "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",
360 ); 368 );
361 } 369 }
362 370
363 #[test] 371 #[test]
364 fn goto_definition_works_for_macros_in_use_tree() { 372 fn goto_def_for_macros_in_use_tree() {
365 check_goto( 373 check_goto(
366 " 374 "
367 //- /lib.rs 375 //- /lib.rs
@@ -369,19 +377,16 @@ mod tests {
369 377
370 //- /foo/lib.rs 378 //- /foo/lib.rs
371 #[macro_export] 379 #[macro_export]
372 macro_rules! foo { 380 macro_rules! foo { () => { () } }
373 () => {
374 {}
375 };
376 }
377 ", 381 ",
378 "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",
379 ); 384 );
380 } 385 }
381 386
382 #[test] 387 #[test]
383 fn goto_definition_works_for_macro_defined_fn_with_arg() { 388 fn goto_def_for_macro_defined_fn_with_arg() {
384 check_goto_with_range_content( 389 check_goto(
385 " 390 "
386 //- /lib.rs 391 //- /lib.rs
387 macro_rules! define_fn { 392 macro_rules! define_fn {
@@ -400,8 +405,8 @@ mod tests {
400 } 405 }
401 406
402 #[test] 407 #[test]
403 fn goto_definition_works_for_macro_defined_fn_no_arg() { 408 fn goto_def_for_macro_defined_fn_no_arg() {
404 check_goto_with_range_content( 409 check_goto(
405 " 410 "
406 //- /lib.rs 411 //- /lib.rs
407 macro_rules! define_fn { 412 macro_rules! define_fn {
@@ -420,27 +425,28 @@ mod tests {
420 } 425 }
421 426
422 #[test] 427 #[test]
423 fn goto_definition_works_for_methods() { 428 fn goto_def_for_methods() {
424 covers!(goto_definition_works_for_methods); 429 covers!(goto_def_for_methods);
425 check_goto( 430 check_goto(
426 " 431 "
427 //- /lib.rs 432 //- /lib.rs
428 struct Foo; 433 struct Foo;
429 impl Foo { 434 impl Foo {
430 fn frobnicate(&self) { } 435 fn frobnicate(&self) { }
431 } 436 }
432 437
433 fn bar(foo: &Foo) { 438 fn bar(foo: &Foo) {
434 foo.frobnicate<|>(); 439 foo.frobnicate<|>();
435 } 440 }
436 ", 441 ",
437 "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", 442 "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)",
443 "fn frobnicate(&self) { }|frobnicate",
438 ); 444 );
439 } 445 }
440 446
441 #[test] 447 #[test]
442 fn goto_definition_works_for_fields() { 448 fn goto_def_for_fields() {
443 covers!(goto_definition_works_for_fields); 449 covers!(goto_def_for_fields);
444 check_goto( 450 check_goto(
445 " 451 "
446 //- /lib.rs 452 //- /lib.rs
@@ -453,12 +459,13 @@ mod tests {
453 } 459 }
454 ", 460 ",
455 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 461 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
462 "spam: u32|spam",
456 ); 463 );
457 } 464 }
458 465
459 #[test] 466 #[test]
460 fn goto_definition_works_for_record_fields() { 467 fn goto_def_for_record_fields() {
461 covers!(goto_definition_works_for_record_fields); 468 covers!(goto_def_for_record_fields);
462 check_goto( 469 check_goto(
463 " 470 "
464 //- /lib.rs 471 //- /lib.rs
@@ -473,6 +480,7 @@ mod tests {
473 } 480 }
474 ", 481 ",
475 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 482 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
483 "spam: u32|spam",
476 ); 484 );
477 } 485 }
478 486
@@ -489,29 +497,31 @@ mod tests {
489 } 497 }
490 ", 498 ",
491 "TUPLE_FIELD_DEF FileId(1) [11; 14)", 499 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
500 "u32",
492 ); 501 );
493 } 502 }
494 503
495 #[test] 504 #[test]
496 fn goto_definition_works_for_ufcs_inherent_methods() { 505 fn goto_def_for_ufcs_inherent_methods() {
497 check_goto( 506 check_goto(
498 " 507 "
499 //- /lib.rs 508 //- /lib.rs
500 struct Foo; 509 struct Foo;
501 impl Foo { 510 impl Foo {
502 fn frobnicate() { } 511 fn frobnicate() { }
503 } 512 }
504 513
505 fn bar(foo: &Foo) { 514 fn bar(foo: &Foo) {
506 Foo::frobnicate<|>(); 515 Foo::frobnicate<|>();
507 } 516 }
508 ", 517 ",
509 "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", 518 "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)",
519 "fn frobnicate() { }|frobnicate",
510 ); 520 );
511 } 521 }
512 522
513 #[test] 523 #[test]
514 fn goto_definition_works_for_ufcs_trait_methods_through_traits() { 524 fn goto_def_for_ufcs_trait_methods_through_traits() {
515 check_goto( 525 check_goto(
516 " 526 "
517 //- /lib.rs 527 //- /lib.rs
@@ -524,11 +534,12 @@ mod tests {
524 } 534 }
525 ", 535 ",
526 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", 536 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
537 "fn frobnicate();|frobnicate",
527 ); 538 );
528 } 539 }
529 540
530 #[test] 541 #[test]
531 fn goto_definition_works_for_ufcs_trait_methods_through_self() { 542 fn goto_def_for_ufcs_trait_methods_through_self() {
532 check_goto( 543 check_goto(
533 " 544 "
534 //- /lib.rs 545 //- /lib.rs
@@ -543,6 +554,7 @@ mod tests {
543 } 554 }
544 ", 555 ",
545 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", 556 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
557 "fn frobnicate();|frobnicate",
546 ); 558 );
547 } 559 }
548 560
@@ -559,6 +571,7 @@ mod tests {
559 } 571 }
560 ", 572 ",
561 "impl IMPL_BLOCK FileId(1) [12; 73)", 573 "impl IMPL_BLOCK FileId(1) [12; 73)",
574 "impl Foo {...}",
562 ); 575 );
563 576
564 check_goto( 577 check_goto(
@@ -572,6 +585,7 @@ mod tests {
572 } 585 }
573 ", 586 ",
574 "impl IMPL_BLOCK FileId(1) [12; 73)", 587 "impl IMPL_BLOCK FileId(1) [12; 73)",
588 "impl Foo {...}",
575 ); 589 );
576 590
577 check_goto( 591 check_goto(
@@ -585,6 +599,7 @@ mod tests {
585 } 599 }
586 ", 600 ",
587 "impl IMPL_BLOCK FileId(1) [15; 75)", 601 "impl IMPL_BLOCK FileId(1) [15; 75)",
602 "impl Foo {...}",
588 ); 603 );
589 604
590 check_goto( 605 check_goto(
@@ -597,6 +612,7 @@ mod tests {
597 } 612 }
598 ", 613 ",
599 "impl IMPL_BLOCK FileId(1) [15; 62)", 614 "impl IMPL_BLOCK FileId(1) [15; 62)",
615 "impl Foo {...}",
600 ); 616 );
601 } 617 }
602 618
@@ -616,6 +632,7 @@ mod tests {
616 } 632 }
617 ", 633 ",
618 "impl IMPL_BLOCK FileId(1) [49; 115)", 634 "impl IMPL_BLOCK FileId(1) [49; 115)",
635 "impl Make for Foo {...}",
619 ); 636 );
620 637
621 check_goto( 638 check_goto(
@@ -632,17 +649,19 @@ mod tests {
632 } 649 }
633 ", 650 ",
634 "impl IMPL_BLOCK FileId(1) [49; 115)", 651 "impl IMPL_BLOCK FileId(1) [49; 115)",
652 "impl Make for Foo {...}",
635 ); 653 );
636 } 654 }
637 655
638 #[test] 656 #[test]
639 fn goto_definition_works_when_used_on_definition_name_itself() { 657 fn goto_def_when_used_on_definition_name_itself() {
640 check_goto( 658 check_goto(
641 " 659 "
642 //- /lib.rs 660 //- /lib.rs
643 struct Foo<|> { value: u32 } 661 struct Foo<|> { value: u32 }
644 ", 662 ",
645 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", 663 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)",
664 "struct Foo { value: u32 }|Foo",
646 ); 665 );
647 666
648 check_goto( 667 check_goto(
@@ -653,15 +672,16 @@ mod tests {
653 } 672 }
654 "#, 673 "#,
655 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", 674 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)",
675 "field: string|field",
656 ); 676 );
657 677
658 check_goto( 678 check_goto(
659 " 679 "
660 //- /lib.rs 680 //- /lib.rs
661 fn foo_test<|>() { 681 fn foo_test<|>() { }
662 }
663 ", 682 ",
664 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", 683 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)",
684 "fn foo_test() { }|foo_test",
665 ); 685 );
666 686
667 check_goto( 687 check_goto(
@@ -672,6 +692,7 @@ mod tests {
672 } 692 }
673 ", 693 ",
674 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", 694 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)",
695 "enum Foo {...}|Foo",
675 ); 696 );
676 697
677 check_goto( 698 check_goto(
@@ -684,22 +705,25 @@ mod tests {
684 } 705 }
685 ", 706 ",
686 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", 707 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)",
708 "Variant2|Variant2",
687 ); 709 );
688 710
689 check_goto( 711 check_goto(
690 r#" 712 r#"
691 //- /lib.rs 713 //- /lib.rs
692 static inner<|>: &str = ""; 714 static INNER<|>: &str = "";
693 "#, 715 "#,
694 "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", 716 "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)",
717 "static INNER: &str = \"\";|INNER",
695 ); 718 );
696 719
697 check_goto( 720 check_goto(
698 r#" 721 r#"
699 //- /lib.rs 722 //- /lib.rs
700 const inner<|>: &str = ""; 723 const INNER<|>: &str = "";
701 "#, 724 "#,
702 "inner CONST_DEF FileId(1) [0; 23) [6; 11)", 725 "INNER CONST_DEF FileId(1) [0; 23) [6; 11)",
726 "const INNER: &str = \"\";|INNER",
703 ); 727 );
704 728
705 check_goto( 729 check_goto(
@@ -708,24 +732,25 @@ mod tests {
708 type Thing<|> = Option<()>; 732 type Thing<|> = Option<()>;
709 "#, 733 "#,
710 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", 734 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)",
735 "type Thing = Option<()>;|Thing",
711 ); 736 );
712 737
713 check_goto( 738 check_goto(
714 r#" 739 r#"
715 //- /lib.rs 740 //- /lib.rs
716 trait Foo<|> { 741 trait Foo<|> { }
717 }
718 "#, 742 "#,
719 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", 743 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)",
744 "trait Foo { }|Foo",
720 ); 745 );
721 746
722 check_goto( 747 check_goto(
723 r#" 748 r#"
724 //- /lib.rs 749 //- /lib.rs
725 mod bar<|> { 750 mod bar<|> { }
726 }
727 "#, 751 "#,
728 "bar MODULE FileId(1) [0; 11) [4; 7)", 752 "bar MODULE FileId(1) [0; 11) [4; 7)",
753 "mod bar { }|bar",
729 ); 754 );
730 } 755 }
731 756
@@ -746,6 +771,7 @@ mod tests {
746 mod confuse_index { fn foo(); } 771 mod confuse_index { fn foo(); }
747 ", 772 ",
748 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 773 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
774 "fn foo() {}|foo",
749 ); 775 );
750 } 776 }
751 777
@@ -774,6 +800,7 @@ mod tests {
774 } 800 }
775 ", 801 ",
776 "foo FN_DEF FileId(1) [398; 415) [401; 404)", 802 "foo FN_DEF FileId(1) [398; 415) [401; 404)",
803 "fn foo() -> i8 {}|foo",
777 ); 804 );
778 } 805 }
779 806
@@ -787,6 +814,82 @@ mod tests {
787 } 814 }
788 ", 815 ",
789 "T TYPE_PARAM FileId(1) [11; 12)", 816 "T TYPE_PARAM FileId(1) [11; 12)",
817 "T",
790 ); 818 );
791 } 819 }
820
821 #[test]
822 fn goto_within_macro() {
823 check_goto(
824 "
825 //- /lib.rs
826 macro_rules! id {
827 ($($tt:tt)*) => ($($tt)*)
828 }
829
830 fn foo() {
831 let x = 1;
832 id!({
833 let y = <|>x;
834 let z = y;
835 });
836 }
837 ",
838 "x BIND_PAT FileId(1) [69; 70)",
839 "x",
840 );
841
842 check_goto(
843 "
844 //- /lib.rs
845 macro_rules! id {
846 ($($tt:tt)*) => ($($tt)*)
847 }
848
849 fn foo() {
850 let x = 1;
851 id!({
852 let y = x;
853 let z = <|>y;
854 });
855 }
856 ",
857 "y BIND_PAT FileId(1) [98; 99)",
858 "y",
859 );
860 }
861
862 #[test]
863 fn goto_def_in_local_fn() {
864 check_goto(
865 "
866 //- /lib.rs
867 fn main() {
868 fn foo() {
869 let x = 92;
870 <|>x;
871 }
872 }
873 ",
874 "x BIND_PAT FileId(1) [39; 40)",
875 "x",
876 );
877 }
878
879 #[test]
880 fn goto_def_for_field_init_shorthand() {
881 covers!(goto_def_for_field_init_shorthand);
882 check_goto(
883 "
884 //- /lib.rs
885 struct Foo { x: i32 }
886 fn main() {
887 let x = 92;
888 Foo { x<|> };
889 }
890 ",
891 "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
892 "x: i32|x",
893 )
894 }
792} 895}