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.rs967
1 files changed, 0 insertions, 967 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
deleted file mode 100644
index 4e3f428fa..000000000
--- a/crates/ra_ide/src/goto_definition.rs
+++ /dev/null
@@ -1,967 +0,0 @@
1use hir::Semantics;
2use ra_ide_db::{
3 defs::{classify_name, classify_name_ref, NameClass},
4 symbol_index, RootDatabase,
5};
6use ra_syntax::{
7 ast::{self},
8 match_ast, AstNode,
9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset, T,
11};
12
13use crate::{
14 display::{ToNav, TryToNav},
15 FilePosition, NavigationTarget, RangeInfo,
16};
17
18// Feature: Go to Definition
19//
20// Navigates to the definition of an identifier.
21//
22// |===
23// | Editor | Shortcut
24//
25// | VS Code | kbd:[F12]
26// |===
27pub(crate) fn goto_definition(
28 db: &RootDatabase,
29 position: FilePosition,
30) -> Option<RangeInfo<Vec<NavigationTarget>>> {
31 let sema = Semantics::new(db);
32 let file = sema.parse(position.file_id).syntax().clone();
33 let original_token = pick_best(file.token_at_offset(position.offset))?;
34 let token = sema.descend_into_macros(original_token.clone());
35 let parent = token.parent();
36
37 let nav_targets = match_ast! {
38 match parent {
39 ast::NameRef(name_ref) => {
40 reference_definition(&sema, &name_ref).to_vec()
41 },
42 ast::Name(name) => {
43 let def = match classify_name(&sema, &name)? {
44 NameClass::Definition(def) | NameClass::ConstReference(def) => def,
45 NameClass::FieldShorthand { local: _, field } => field,
46 };
47 let nav = def.try_to_nav(sema.db)?;
48 vec![nav]
49 },
50 _ => return None,
51 }
52 };
53
54 Some(RangeInfo::new(original_token.text_range(), nav_targets))
55}
56
57fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
58 return tokens.max_by_key(priority);
59 fn priority(n: &SyntaxToken) -> usize {
60 match n.kind() {
61 IDENT | INT_NUMBER | T![self] => 2,
62 kind if kind.is_trivia() => 0,
63 _ => 1,
64 }
65 }
66}
67
68#[derive(Debug)]
69pub(crate) enum ReferenceResult {
70 Exact(NavigationTarget),
71 Approximate(Vec<NavigationTarget>),
72}
73
74impl ReferenceResult {
75 fn to_vec(self) -> Vec<NavigationTarget> {
76 match self {
77 ReferenceResult::Exact(target) => vec![target],
78 ReferenceResult::Approximate(vec) => vec,
79 }
80 }
81}
82
83pub(crate) fn reference_definition(
84 sema: &Semantics<RootDatabase>,
85 name_ref: &ast::NameRef,
86) -> ReferenceResult {
87 let name_kind = classify_name_ref(sema, name_ref);
88 if let Some(def) = name_kind {
89 let def = def.definition();
90
91 return match def.try_to_nav(sema.db) {
92 Some(nav) => ReferenceResult::Exact(nav),
93 None => ReferenceResult::Approximate(Vec::new()),
94 };
95 }
96
97 // Fallback index based approach:
98 let navs = symbol_index::index_resolve(sema.db, name_ref)
99 .into_iter()
100 .map(|s| s.to_nav(sema.db))
101 .collect();
102 ReferenceResult::Approximate(navs)
103}
104
105#[cfg(test)]
106mod tests {
107 use ra_db::FileRange;
108 use ra_syntax::{TextRange, TextSize};
109
110 use crate::mock_analysis::MockAnalysis;
111
112 fn check(ra_fixture: &str) {
113 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
114 let (mut expected, data) = mock.annotation();
115 let analysis = mock.analysis();
116 match data.as_str() {
117 "" => (),
118 "file" => {
119 expected.range =
120 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
121 }
122 data => panic!("bad data: {}", data),
123 }
124
125 let mut navs =
126 analysis.goto_definition(position).unwrap().expect("no definition found").info;
127 if navs.len() == 0 {
128 panic!("unresolved reference")
129 }
130 assert_eq!(navs.len(), 1);
131
132 let nav = navs.pop().unwrap();
133 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
134 }
135
136 #[test]
137 fn goto_def_in_items() {
138 check(
139 r#"
140struct Foo;
141 //^^^
142enum E { X(Foo<|>) }
143"#,
144 );
145 }
146
147 #[test]
148 fn goto_def_at_start_of_item() {
149 check(
150 r#"
151struct Foo;
152 //^^^
153enum E { X(<|>Foo) }
154"#,
155 );
156 }
157
158 #[test]
159 fn goto_definition_resolves_correct_name() {
160 check(
161 r#"
162//- /lib.rs
163use a::Foo;
164mod a;
165mod b;
166enum E { X(Foo<|>) }
167
168//- /a.rs
169struct Foo;
170 //^^^
171//- /b.rs
172struct Foo;
173"#,
174 );
175 }
176
177 #[test]
178 fn goto_def_for_module_declaration() {
179 check(
180 r#"
181//- /lib.rs
182mod <|>foo;
183
184//- /foo.rs
185// empty
186//^ file
187"#,
188 );
189
190 check(
191 r#"
192//- /lib.rs
193mod <|>foo;
194
195//- /foo/mod.rs
196// empty
197//^ file
198"#,
199 );
200 }
201
202 #[test]
203 fn goto_def_for_macros() {
204 check(
205 r#"
206macro_rules! foo { () => { () } }
207 //^^^
208fn bar() {
209 <|>foo!();
210}
211"#,
212 );
213 }
214
215 #[test]
216 fn goto_def_for_macros_from_other_crates() {
217 check(
218 r#"
219//- /lib.rs
220use foo::foo;
221fn bar() {
222 <|>foo!();
223}
224
225//- /foo/lib.rs
226#[macro_export]
227macro_rules! foo { () => { () } }
228 //^^^
229"#,
230 );
231 }
232
233 #[test]
234 fn goto_def_for_macros_in_use_tree() {
235 check(
236 r#"
237//- /lib.rs
238use foo::foo<|>;
239
240//- /foo/lib.rs
241#[macro_export]
242macro_rules! foo { () => { () } }
243 //^^^
244"#,
245 );
246 }
247
248 #[test]
249 fn goto_def_for_macro_defined_fn_with_arg() {
250 check(
251 r#"
252//- /lib.rs
253macro_rules! define_fn {
254 ($name:ident) => (fn $name() {})
255}
256
257define_fn!(foo);
258 //^^^
259
260fn bar() {
261 <|>foo();
262}
263"#,
264 );
265 }
266
267 #[test]
268 fn goto_def_for_macro_defined_fn_no_arg() {
269 check(
270 r#"
271//- /lib.rs
272macro_rules! define_fn {
273 () => (fn foo() {})
274}
275
276 define_fn!();
277//^^^^^^^^^^^^^
278
279fn bar() {
280 <|>foo();
281}
282"#,
283 );
284 }
285
286 #[test]
287 fn goto_definition_works_for_macro_inside_pattern() {
288 check(
289 r#"
290//- /lib.rs
291macro_rules! foo {() => {0}}
292 //^^^
293
294fn bar() {
295 match (0,1) {
296 (<|>foo!(), _) => {}
297 }
298}
299"#,
300 );
301 }
302
303 #[test]
304 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
305 check(
306 r#"
307//- /lib.rs
308macro_rules! foo {() => {0}}
309 //^^^
310fn bar() {
311 match 0 {
312 <|>foo!() => {}
313 }
314}
315"#,
316 );
317 }
318
319 #[test]
320 fn goto_def_for_use_alias() {
321 check(
322 r#"
323//- /lib.rs
324use foo as bar<|>;
325
326//- /foo/lib.rs
327// empty
328//^ file
329"#,
330 );
331 }
332
333 #[test]
334 fn goto_def_for_use_alias_foo_macro() {
335 check(
336 r#"
337//- /lib.rs
338use foo::foo as bar<|>;
339
340//- /foo/lib.rs
341#[macro_export]
342macro_rules! foo { () => { () } }
343 //^^^
344"#,
345 );
346 }
347
348 #[test]
349 fn goto_def_for_methods() {
350 check(
351 r#"
352//- /lib.rs
353struct Foo;
354impl Foo {
355 fn frobnicate(&self) { }
356 //^^^^^^^^^^
357}
358
359fn bar(foo: &Foo) {
360 foo.frobnicate<|>();
361}
362"#,
363 );
364 }
365
366 #[test]
367 fn goto_def_for_fields() {
368 check(
369 r#"
370struct Foo {
371 spam: u32,
372} //^^^^
373
374fn bar(foo: &Foo) {
375 foo.spam<|>;
376}
377"#,
378 );
379 }
380
381 #[test]
382 fn goto_def_for_record_fields() {
383 check(
384 r#"
385//- /lib.rs
386struct Foo {
387 spam: u32,
388} //^^^^
389
390fn bar() -> Foo {
391 Foo {
392 spam<|>: 0,
393 }
394}
395"#,
396 );
397 }
398
399 #[test]
400 fn goto_def_for_record_pat_fields() {
401 check(
402 r#"
403//- /lib.rs
404struct Foo {
405 spam: u32,
406} //^^^^
407
408fn bar(foo: Foo) -> Foo {
409 let Foo { spam<|>: _, } = foo
410}
411"#,
412 );
413 }
414
415 #[test]
416 fn goto_def_for_record_fields_macros() {
417 check(
418 r"
419macro_rules! m { () => { 92 };}
420struct Foo { spam: u32 }
421 //^^^^
422
423fn bar() -> Foo {
424 Foo { spam<|>: m!() }
425}
426",
427 );
428 }
429
430 #[test]
431 fn goto_for_tuple_fields() {
432 check(
433 r#"
434struct Foo(u32);
435 //^^^
436
437fn bar() {
438 let foo = Foo(0);
439 foo.<|>0;
440}
441"#,
442 );
443 }
444
445 #[test]
446 fn goto_def_for_ufcs_inherent_methods() {
447 check(
448 r#"
449struct Foo;
450impl Foo {
451 fn frobnicate() { }
452} //^^^^^^^^^^
453
454fn bar(foo: &Foo) {
455 Foo::frobnicate<|>();
456}
457"#,
458 );
459 }
460
461 #[test]
462 fn goto_def_for_ufcs_trait_methods_through_traits() {
463 check(
464 r#"
465trait Foo {
466 fn frobnicate();
467} //^^^^^^^^^^
468
469fn bar() {
470 Foo::frobnicate<|>();
471}
472"#,
473 );
474 }
475
476 #[test]
477 fn goto_def_for_ufcs_trait_methods_through_self() {
478 check(
479 r#"
480struct Foo;
481trait Trait {
482 fn frobnicate();
483} //^^^^^^^^^^
484impl Trait for Foo {}
485
486fn bar() {
487 Foo::frobnicate<|>();
488}
489"#,
490 );
491 }
492
493 #[test]
494 fn goto_definition_on_self() {
495 check(
496 r#"
497struct Foo;
498impl Foo {
499 //^^^
500 pub fn new() -> Self {
501 Self<|> {}
502 }
503}
504"#,
505 );
506 check(
507 r#"
508struct Foo;
509impl Foo {
510 //^^^
511 pub fn new() -> Self<|> {
512 Self {}
513 }
514}
515"#,
516 );
517
518 check(
519 r#"
520enum Foo { A }
521impl Foo {
522 //^^^
523 pub fn new() -> Self<|> {
524 Foo::A
525 }
526}
527"#,
528 );
529
530 check(
531 r#"
532enum Foo { A }
533impl Foo {
534 //^^^
535 pub fn thing(a: &Self<|>) {
536 }
537}
538"#,
539 );
540 }
541
542 #[test]
543 fn goto_definition_on_self_in_trait_impl() {
544 check(
545 r#"
546struct Foo;
547trait Make {
548 fn new() -> Self;
549}
550impl Make for Foo {
551 //^^^
552 fn new() -> Self {
553 Self<|> {}
554 }
555}
556"#,
557 );
558
559 check(
560 r#"
561struct Foo;
562trait Make {
563 fn new() -> Self;
564}
565impl Make for Foo {
566 //^^^
567 fn new() -> Self<|> {
568 Self {}
569 }
570}
571"#,
572 );
573 }
574
575 #[test]
576 fn goto_def_when_used_on_definition_name_itself() {
577 check(
578 r#"
579struct Foo<|> { value: u32 }
580 //^^^
581 "#,
582 );
583
584 check(
585 r#"
586struct Foo {
587 field<|>: string,
588} //^^^^^
589"#,
590 );
591
592 check(
593 r#"
594fn foo_test<|>() { }
595 //^^^^^^^^
596"#,
597 );
598
599 check(
600 r#"
601enum Foo<|> { Variant }
602 //^^^
603"#,
604 );
605
606 check(
607 r#"
608enum Foo {
609 Variant1,
610 Variant2<|>,
611 //^^^^^^^^
612 Variant3,
613}
614"#,
615 );
616
617 check(
618 r#"
619static INNER<|>: &str = "";
620 //^^^^^
621"#,
622 );
623
624 check(
625 r#"
626const INNER<|>: &str = "";
627 //^^^^^
628"#,
629 );
630
631 check(
632 r#"
633type Thing<|> = Option<()>;
634 //^^^^^
635"#,
636 );
637
638 check(
639 r#"
640trait Foo<|> { }
641 //^^^
642"#,
643 );
644
645 check(
646 r#"
647mod bar<|> { }
648 //^^^
649"#,
650 );
651 }
652
653 #[test]
654 fn goto_from_macro() {
655 check(
656 r#"
657macro_rules! id {
658 ($($tt:tt)*) => { $($tt)* }
659}
660fn foo() {}
661 //^^^
662id! {
663 fn bar() {
664 fo<|>o();
665 }
666}
667mod confuse_index { fn foo(); }
668"#,
669 );
670 }
671
672 #[test]
673 fn goto_through_format() {
674 check(
675 r#"
676#[macro_export]
677macro_rules! format {
678 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
679}
680#[rustc_builtin_macro]
681#[macro_export]
682macro_rules! format_args {
683 ($fmt:expr) => ({ /* compiler built-in */ });
684 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
685}
686pub mod __export {
687 pub use crate::format_args;
688 fn foo() {} // for index confusion
689}
690fn foo() -> i8 {}
691 //^^^
692fn test() {
693 format!("{}", fo<|>o())
694}
695"#,
696 );
697 }
698
699 #[test]
700 fn goto_for_type_param() {
701 check(
702 r#"
703struct Foo<T: Clone> { t: <|>T }
704 //^
705"#,
706 );
707 }
708
709 #[test]
710 fn goto_within_macro() {
711 check(
712 r#"
713macro_rules! id {
714 ($($tt:tt)*) => ($($tt)*)
715}
716
717fn foo() {
718 let x = 1;
719 //^
720 id!({
721 let y = <|>x;
722 let z = y;
723 });
724}
725"#,
726 );
727
728 check(
729 r#"
730macro_rules! id {
731 ($($tt:tt)*) => ($($tt)*)
732}
733
734fn foo() {
735 let x = 1;
736 id!({
737 let y = x;
738 //^
739 let z = <|>y;
740 });
741}
742"#,
743 );
744 }
745
746 #[test]
747 fn goto_def_in_local_fn() {
748 check(
749 r#"
750fn main() {
751 fn foo() {
752 let x = 92;
753 //^
754 <|>x;
755 }
756}
757"#,
758 );
759 }
760
761 #[test]
762 fn goto_def_in_local_macro() {
763 check(
764 r#"
765fn bar() {
766 macro_rules! foo { () => { () } }
767 //^^^
768 <|>foo!();
769}
770"#,
771 );
772 }
773
774 #[test]
775 fn goto_def_for_field_init_shorthand() {
776 check(
777 r#"
778struct Foo { x: i32 }
779fn main() {
780 let x = 92;
781 //^
782 Foo { x<|> };
783}
784"#,
785 )
786 }
787
788 #[test]
789 fn goto_def_for_enum_variant_field() {
790 check(
791 r#"
792enum Foo {
793 Bar { x: i32 }
794} //^
795fn baz(foo: Foo) {
796 match foo {
797 Foo::Bar { x<|> } => x
798 };
799}
800"#,
801 );
802 }
803
804 #[test]
805 fn goto_def_for_enum_variant_self_pattern_const() {
806 check(
807 r#"
808enum Foo { Bar }
809 //^^^
810impl Foo {
811 fn baz(self) {
812 match self { Self::Bar<|> => {} }
813 }
814}
815"#,
816 );
817 }
818
819 #[test]
820 fn goto_def_for_enum_variant_self_pattern_record() {
821 check(
822 r#"
823enum Foo { Bar { val: i32 } }
824 //^^^
825impl Foo {
826 fn baz(self) -> i32 {
827 match self { Self::Bar<|> { val } => {} }
828 }
829}
830"#,
831 );
832 }
833
834 #[test]
835 fn goto_def_for_enum_variant_self_expr_const() {
836 check(
837 r#"
838enum Foo { Bar }
839 //^^^
840impl Foo {
841 fn baz(self) { Self::Bar<|>; }
842}
843"#,
844 );
845 }
846
847 #[test]
848 fn goto_def_for_enum_variant_self_expr_record() {
849 check(
850 r#"
851enum Foo { Bar { val: i32 } }
852 //^^^
853impl Foo {
854 fn baz(self) { Self::Bar<|> {val: 4}; }
855}
856"#,
857 );
858 }
859
860 #[test]
861 fn goto_def_for_type_alias_generic_parameter() {
862 check(
863 r#"
864type Alias<T> = T<|>;
865 //^
866"#,
867 )
868 }
869
870 #[test]
871 fn goto_def_for_macro_container() {
872 check(
873 r#"
874//- /lib.rs
875foo::module<|>::mac!();
876
877//- /foo/lib.rs
878pub mod module {
879 //^^^^^^
880 #[macro_export]
881 macro_rules! _mac { () => { () } }
882 pub use crate::_mac as mac;
883}
884"#,
885 );
886 }
887
888 #[test]
889 fn goto_def_for_assoc_ty_in_path() {
890 check(
891 r#"
892trait Iterator {
893 type Item;
894 //^^^^
895}
896
897fn f() -> impl Iterator<Item<|> = u8> {}
898"#,
899 );
900 }
901
902 #[test]
903 fn goto_def_for_assoc_ty_in_path_multiple() {
904 check(
905 r#"
906trait Iterator {
907 type A;
908 //^
909 type B;
910}
911
912fn f() -> impl Iterator<A<|> = u8, B = ()> {}
913"#,
914 );
915 check(
916 r#"
917trait Iterator {
918 type A;
919 type B;
920 //^
921}
922
923fn f() -> impl Iterator<A = u8, B<|> = ()> {}
924"#,
925 );
926 }
927
928 #[test]
929 fn goto_def_for_assoc_ty_ufcs() {
930 check(
931 r#"
932trait Iterator {
933 type Item;
934 //^^^^
935}
936
937fn g() -> <() as Iterator<Item<|> = ()>>::Item {}
938"#,
939 );
940 }
941
942 #[test]
943 fn goto_def_for_assoc_ty_ufcs_multiple() {
944 check(
945 r#"
946trait Iterator {
947 type A;
948 //^
949 type B;
950}
951
952fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {}
953"#,
954 );
955 check(
956 r#"
957trait Iterator {
958 type A;
959 type B;
960 //^
961}
962
963fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {}
964"#,
965 );
966 }
967}