1 use std
::mem
::discriminant
;
3 use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}
;
4 use hir
::{AsAssocItem, AssocItem, Semantics}
;
6 base_db
::{AnchoredPath, FileId, FileLoader}
,
7 defs
::{Definition, IdentClass}
,
8 helpers
::pick_best_token
,
11 use itertools
::Itertools
;
12 use syntax
::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T}
;
14 // Feature: Go to Definition
16 // Navigates to the definition of an identifier.
18 // For outline modules, this will navigate to the source file of the module.
21 // | Editor | Shortcut
23 // | VS Code | kbd:[F12]
26 // image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
27 pub(crate) fn goto_definition(
29 position
: FilePosition
,
30 ) -> Option
<RangeInfo
<Vec
<NavigationTarget
>>> {
31 let sema
= &Semantics
::new(db
);
32 let file
= sema
.parse(position
.file_id
).syntax().clone();
34 pick_best_token(file
.token_at_offset(position
.offset
), |kind
| match kind
{
43 // index and prefix ops
44 T
!['
['
] | T
!['
]'
] | T
![?
] | T
![*] | T
![-] | T
![!] => 3,
45 kind
if kind
.is_keyword() => 2,
46 T
!['
('
] | T
!['
)'
] => 2,
47 kind
if kind
.is_trivia() => 0,
50 if let Some(doc_comment
) = token_as_doc_comment(&original_token
) {
51 return doc_comment
.get_definition_with_descend_at(sema
, position
.offset
, |def
, _
, _
| {
52 let nav
= def
.try_to_nav(db
)?
;
53 Some(RangeInfo
::new(original_token
.text_range(), vec
![nav
]))
57 .descend_into_macros(original_token
.clone())
60 let parent
= token
.parent()?
;
61 if let Some(tt
) = ast
::TokenTree
::cast(parent
) {
62 if let Some(x
) = try_lookup_include_path(sema
, tt
, token
.clone(), position
.file_id
)
68 IdentClass
::classify_token(sema
, &token
)?
72 try_filter_trait_item_definition(sema
, &def
)
73 .unwrap_or_else(|| def_to_nav(sema
.db
, def
))
80 .collect
::<Vec
<NavigationTarget
>>();
82 Some(RangeInfo
::new(original_token
.text_range(), navs
))
85 fn try_lookup_include_path(
86 sema
: &Semantics
<'_
, RootDatabase
>,
90 ) -> Option
<NavigationTarget
> {
91 let token
= ast
::String
::cast(token
)?
;
92 let path
= token
.value()?
.into_owned();
93 let macro_call
= tt
.syntax().parent().and_then(ast
::MacroCall
::cast
)?
;
94 let name
= macro_call
.path()?
.segment()?
.name_ref()?
;
95 if !matches
!(&*name
.text(), "include" | "include_str" | "include_bytes") {
98 let file_id
= sema
.db
.resolve_path(AnchoredPath { anchor: file_id, path: &path }
)?
;
99 let size
= sema
.db
.file_text(file_id
).len().try_into().ok()?
;
100 Some(NavigationTarget
{
102 full_range
: TextRange
::new(0.into
(), size
),
106 container_name
: None
,
111 /// finds the trait definition of an impl'd item, except function
114 /// trait A { type a; }
116 /// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait
118 fn try_filter_trait_item_definition(
119 sema
: &Semantics
<'_
, RootDatabase
>,
121 ) -> Option
<Vec
<NavigationTarget
>> {
123 let assoc
= def
.as_assoc_item(db
)?
;
125 AssocItem
::Function(..) => None
,
126 AssocItem
::Const(..) | AssocItem
::TypeAlias(..) => {
127 let imp
= match assoc
.container(db
) {
128 hir
::AssocItemContainer
::Impl(imp
) => imp
,
131 let trait_
= imp
.trait_(db
)?
;
132 let name
= def
.name(db
)?
;
133 let discri_value
= discriminant(&assoc
);
137 .filter(|itm
| discriminant(*itm
) == discri_value
)
138 .find_map(|itm
| (itm
.name(db
)?
== name
).then(|| itm
.try_to_nav(db
)).flatten())
144 fn def_to_nav(db
: &RootDatabase
, def
: Definition
) -> Vec
<NavigationTarget
> {
145 def
.try_to_nav(db
).map(|it
| vec
![it
]).unwrap_or_default()
150 use ide_db
::base_db
::FileRange
;
151 use itertools
::Itertools
;
156 fn check(ra_fixture
: &str) {
157 let (analysis
, position
, expected
) = fixture
::annotations(ra_fixture
);
158 let navs
= analysis
.goto_definition(position
).unwrap().expect("no definition found").info
;
160 panic
!("unresolved reference")
163 let cmp
= |&FileRange { file_id, range }
: &_
| (file_id
, range
.start());
166 .map(|nav
| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }
)
168 .collect
::<Vec
<_
>>();
169 let expected
= expected
171 .map(|(FileRange { file_id, range }
, _
)| FileRange { file_id, range }
)
173 .collect
::<Vec
<_
>>();
174 assert_eq
!(expected
, navs
);
177 fn check_unresolved(ra_fixture
: &str) {
178 let (analysis
, position
) = fixture
::position(ra_fixture
);
179 let navs
= analysis
.goto_definition(position
).unwrap().expect("no definition found").info
;
181 assert
!(navs
.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs
)
185 fn goto_def_if_items_same_name() {
202 fn goto_def_in_mac_call_in_attr_invoc() {
205 //- proc_macros: identity
211 macro_rules! identity {
212 ($($tt:tt)*) => {$($tt)*};
215 #[proc_macros::identity]
217 identity!(Struct$0 { field: 0 });
225 fn goto_def_for_extern_crate() {
228 //- /main.rs crate:main deps:std
230 //- /std/lib.rs crate:std
238 fn goto_def_for_renamed_extern_crate() {
241 //- /main.rs crate:main deps:std
242 extern crate std as abc$0;
243 //- /std/lib.rs crate:std
251 fn goto_def_in_items() {
262 fn goto_def_at_start_of_item() {
273 fn goto_definition_resolves_correct_name() {
292 fn goto_def_for_module_declaration() {
317 fn goto_def_for_macros() {
320 macro_rules! foo { () => { () } }
330 fn goto_def_for_macros_from_other_crates() {
333 //- /lib.rs crate:main deps:foo
339 //- /foo/lib.rs crate:foo
341 macro_rules! foo { () => { () } }
348 fn goto_def_for_macros_in_use_tree() {
351 //- /lib.rs crate:main deps:foo
354 //- /foo/lib.rs crate:foo
356 macro_rules! foo { () => { () } }
363 fn goto_def_for_macro_defined_fn_with_arg() {
367 macro_rules! define_fn {
368 ($name:ident) => (fn $name() {})
382 fn goto_def_for_macro_defined_fn_no_arg() {
386 macro_rules! define_fn {
401 fn goto_definition_works_for_macro_inside_pattern() {
405 macro_rules! foo {() => {0}}
418 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
422 macro_rules! foo {() => {0}}
434 fn goto_def_for_use_alias() {
437 //- /lib.rs crate:main deps:foo
440 //- /foo/lib.rs crate:foo
448 fn goto_def_for_use_alias_foo_macro() {
451 //- /lib.rs crate:main deps:foo
452 use foo::foo as bar$0;
454 //- /foo/lib.rs crate:foo
456 macro_rules! foo { () => { () } }
463 fn goto_def_for_methods() {
468 fn frobnicate(&self) { }
480 fn goto_def_for_fields() {
495 fn goto_def_for_record_fields() {
513 fn goto_def_for_record_pat_fields() {
521 fn bar(foo: Foo) -> Foo {
522 let Foo { spam$0: _, } = foo
529 fn goto_def_for_record_fields_macros() {
532 macro_rules! m { () => { 92 };}
533 struct Foo { spam: u32 }
544 fn goto_for_tuple_fields() {
559 fn goto_def_for_ufcs_inherent_methods() {
575 fn goto_def_for_ufcs_trait_methods_through_traits() {
590 fn goto_def_for_ufcs_trait_methods_through_self() {
597 impl Trait for Foo {}
607 fn goto_definition_on_self() {
613 pub fn new() -> Self {
624 pub fn new() -> Self$0 {
636 pub fn new() -> Self$0 {
648 pub fn thing(a: &Self$0) {
656 fn goto_definition_on_self_in_trait_impl() {
689 fn goto_def_when_used_on_definition_name_itself() {
692 struct Foo$0 { value: u32 }
714 enum Foo$0 { Variant }
732 static INNER$0: &str = "";
739 const INNER$0: &str = "";
746 type Thing$0 = Option<()>;
767 fn goto_from_macro() {
771 ($($tt:tt)*) => { $($tt)* }
780 mod confuse_index { fn foo(); }
786 fn goto_through_format() {
790 macro_rules! format {
791 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
793 #[rustc_builtin_macro]
795 macro_rules! format_args {
796 ($fmt:expr) => ({ /* compiler built-in */ });
797 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
800 pub use crate::format_args;
801 fn foo() {} // for index confusion
806 format!("{}", fo$0o())
813 fn goto_through_included_file() {
817 #[rustc_builtin_macro]
818 macro_rules! include {}
821 //^^^^^^^^^^^^^^^^^^^
838 fn goto_for_type_param() {
841 struct Foo<T: Clone> { t: $0T }
848 fn goto_within_macro() {
852 ($($tt:tt)*) => ($($tt)*)
869 ($($tt:tt)*) => ($($tt)*)
885 fn goto_def_in_local_fn() {
900 fn goto_def_in_local_macro() {
904 macro_rules! foo { () => { () } }
913 fn goto_def_for_field_init_shorthand() {
916 struct Foo { x: i32 }
928 fn goto_def_for_enum_variant_field() {
937 Foo::Bar { x$0 } => x
946 fn goto_def_for_enum_variant_self_pattern_const() {
953 match self { Self::Bar$0 => {} }
961 fn goto_def_for_enum_variant_self_pattern_record() {
964 enum Foo { Bar { val: i32 } }
967 fn baz(self) -> i32 {
968 match self { Self::Bar$0 { val } => {} }
976 fn goto_def_for_enum_variant_self_expr_const() {
982 fn baz(self) { Self::Bar$0; }
989 fn goto_def_for_enum_variant_self_expr_record() {
992 enum Foo { Bar { val: i32 } }
995 fn baz(self) { Self::Bar$0 {val: 4}; }
1002 fn goto_def_for_type_alias_generic_parameter() {
1005 type Alias<T> = T$0;
1012 fn goto_def_for_macro_container() {
1015 //- /lib.rs crate:main deps:foo
1016 foo::module$0::mac!();
1018 //- /foo/lib.rs crate:foo
1022 macro_rules! _mac { () => { () } }
1023 pub use crate::_mac as mac;
1030 fn goto_def_for_assoc_ty_in_path() {
1038 fn f() -> impl Iterator<Item$0 = u8> {}
1044 fn goto_def_for_super_assoc_ty_in_path() {
1054 fn f() -> impl Sub<Item$0 = u8> {}
1060 fn unknown_assoc_ty() {
1063 trait Iterator { type Item; }
1064 fn f() -> impl Iterator<Invalid$0 = u8> {}
1070 fn goto_def_for_assoc_ty_in_path_multiple() {
1079 fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1090 fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1096 fn goto_def_for_assoc_ty_ufcs() {
1104 fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1110 fn goto_def_for_assoc_ty_ufcs_multiple() {
1119 fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1130 fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1136 fn goto_self_param_ty_specified() {
1142 fn bar(self: &Foo) {
1151 fn goto_self_param_on_decl() {
1165 fn goto_lifetime_param_on_decl() {
1168 fn foo<'foobar$0>(_: &'foobar ()) {
1175 fn goto_lifetime_param_decl() {
1178 fn foo<'foobar>(_: &'foobar$0 ()) {
1185 fn goto_lifetime_param_decl_nested() {
1188 fn foo<'foobar>(_: &'foobar ()) {
1189 fn foo<'foobar>(_: &'foobar$0 ()) {}
1196 fn goto_lifetime_hrtb() {
1197 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1201 fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1208 fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1215 fn goto_lifetime_hrtb_for_type() {
1216 // FIXME: requires ForTypes to be implemented
1219 fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1229 fn foo<'foo>(_: &'foo ()) {
1241 fn goto_def_for_intra_doc_link_same_file() {
1244 /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1247 /// You might want to see [`std::fs::read()`] too.
1256 fn goto_def_for_intra_doc_link_inner() {
1271 fn goto_incomplete_field() {
1276 fn foo() { A { a$0: }; }
1282 fn goto_proc_macro() {
1285 //- /main.rs crate:main deps:mac
1290 //- /mac.rs crate:mac
1291 #![crate_type="proc-macro"]
1300 fn goto_intra_doc_links() {
1305 /// This is the item. Cool!
1310 /// Gives you a [`TheItem$0`].
1312 /// [`TheItem`]: theitem::TheItem
1313 pub fn gimme() -> theitem::TheItem {
1321 fn goto_ident_from_pat_macro() {
1325 ($name:ident) => { Enum::Variant1($name) }
1339 Enum::Variant2 => {}
1352 let str = include_str!("foo.txt$0");
1361 mod goto_impl_of_trait_fn
{
1364 fn cursor_on_impl() {
1373 impl Twait for Stwuct {
1390 impl Twait for Stwuct {
1411 impl Twait for Stwuct {
1423 fn where_clause_can_work() {
1432 impl <T:EA> G for Gen<T> {
1436 impl <T> G for Gen<T>
1446 let gen = Gen::<A>(A);
1453 fn wc_case_is_ok() {
1460 trait Bound: BParent{}
1462 impl <T> G for Gen<T>
1472 let gen = Gen::<A>(A);
1480 fn method_call_defaulted() {
1490 impl Twait for Stwuct {
1501 fn method_call_on_generic() {
1509 fn f<T: Twait>(s: T) {
1518 fn goto_def_of_trait_impl_const() {
1528 impl Twait for Stwuct {
1529 const NOMS$0: bool = true;
1536 fn goto_def_of_trait_impl_type_alias() {
1546 impl Twait for Stwuct {
1554 fn goto_def_derive_input() {
1558 #[rustc_builtin_macro]
1568 #[rustc_builtin_macro]
1571 #[cfg_attr(feature = "false", derive)]
1580 #[rustc_builtin_macro]
1584 #[derive(foo::Copy$0)]
1593 #[rustc_builtin_macro]
1596 #[derive(foo$0::Copy)]
1603 fn goto_def_in_macro_multi() {
1612 fn $ident(Foo { $ident }: Foo) {}
1629 let _: $ident = $ident;
1640 fn goto_await_poll() {
1643 //- minicore: future
1647 impl core::future::Future for MyFut {
1652 self: std::pin::Pin<&mut Self>,
1653 cx: &mut std::task::Context<'_>
1654 ) -> std::task::Poll<Self::Output>
1668 fn goto_await_into_future_poll() {
1671 //- minicore: future
1675 impl core::future::IntoFuture for Futurable {
1676 type IntoFuture = MyFut;
1681 impl core::future::Future for MyFut {
1686 self: std::pin::Pin<&mut Self>,
1687 cx: &mut std::task::Context<'_>
1688 ) -> std::task::Poll<Self::Output>
1709 impl core::ops::Try for Struct {
1724 fn goto_index_op() {
1731 impl core::ops::Index<usize> for Struct {
1746 fn goto_prefix_op() {
1753 impl core::ops::Deref for Struct {
1775 impl core::ops::Add for Struct {