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(
54 |def
, _
, link_range
| {
55 let nav
= def
.try_to_nav(db
)?
;
56 Some(RangeInfo
::new(link_range
, vec
![nav
]))
61 .descend_into_macros(original_token
.clone())
64 let parent
= token
.parent()?
;
65 if let Some(tt
) = ast
::TokenTree
::cast(parent
) {
66 if let Some(x
) = try_lookup_include_path(sema
, tt
, token
.clone(), position
.file_id
)
72 IdentClass
::classify_token(sema
, &token
)?
76 try_filter_trait_item_definition(sema
, &def
)
77 .unwrap_or_else(|| def_to_nav(sema
.db
, def
))
84 .collect
::<Vec
<NavigationTarget
>>();
86 Some(RangeInfo
::new(original_token
.text_range(), navs
))
89 fn try_lookup_include_path(
90 sema
: &Semantics
<'_
, RootDatabase
>,
94 ) -> Option
<NavigationTarget
> {
95 let token
= ast
::String
::cast(token
)?
;
96 let path
= token
.value()?
.into_owned();
97 let macro_call
= tt
.syntax().parent().and_then(ast
::MacroCall
::cast
)?
;
98 let name
= macro_call
.path()?
.segment()?
.name_ref()?
;
99 if !matches
!(&*name
.text(), "include" | "include_str" | "include_bytes") {
103 // Ignore non-built-in macros to account for shadowing
104 if let Some(it
) = sema
.resolve_macro_call(¯o_call
) {
105 if !matches
!(it
.kind(sema
.db
), hir
::MacroKind
::BuiltIn
) {
110 let file_id
= sema
.db
.resolve_path(AnchoredPath { anchor: file_id, path: &path }
)?
;
111 let size
= sema
.db
.file_text(file_id
).len().try_into().ok()?
;
112 Some(NavigationTarget
{
114 full_range
: TextRange
::new(0.into
(), size
),
118 container_name
: None
,
123 /// finds the trait definition of an impl'd item, except function
126 /// trait A { type a; }
128 /// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait
130 fn try_filter_trait_item_definition(
131 sema
: &Semantics
<'_
, RootDatabase
>,
133 ) -> Option
<Vec
<NavigationTarget
>> {
135 let assoc
= def
.as_assoc_item(db
)?
;
137 AssocItem
::Function(..) => None
,
138 AssocItem
::Const(..) | AssocItem
::TypeAlias(..) => {
139 let imp
= match assoc
.container(db
) {
140 hir
::AssocItemContainer
::Impl(imp
) => imp
,
143 let trait_
= imp
.trait_(db
)?
;
144 let name
= def
.name(db
)?
;
145 let discri_value
= discriminant(&assoc
);
149 .filter(|itm
| discriminant(*itm
) == discri_value
)
150 .find_map(|itm
| (itm
.name(db
)?
== name
).then(|| itm
.try_to_nav(db
)).flatten())
156 fn def_to_nav(db
: &RootDatabase
, def
: Definition
) -> Vec
<NavigationTarget
> {
157 def
.try_to_nav(db
).map(|it
| vec
![it
]).unwrap_or_default()
162 use ide_db
::base_db
::FileRange
;
163 use itertools
::Itertools
;
168 fn check(ra_fixture
: &str) {
169 let (analysis
, position
, expected
) = fixture
::annotations(ra_fixture
);
170 let navs
= analysis
.goto_definition(position
).unwrap().expect("no definition found").info
;
172 let cmp
= |&FileRange { file_id, range }
: &_
| (file_id
, range
.start());
175 .map(|nav
| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }
)
177 .collect
::<Vec
<_
>>();
178 let expected
= expected
180 .map(|(FileRange { file_id, range }
, _
)| FileRange { file_id, range }
)
182 .collect
::<Vec
<_
>>();
183 assert_eq
!(expected
, navs
);
186 fn check_unresolved(ra_fixture
: &str) {
187 let (analysis
, position
) = fixture
::position(ra_fixture
);
188 let navs
= analysis
.goto_definition(position
).unwrap().expect("no definition found").info
;
190 assert
!(navs
.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
194 fn goto_def_if_items_same_name() {
211 fn goto_def_in_mac_call_in_attr_invoc() {
214 //- proc_macros: identity
220 macro_rules! identity {
221 ($($tt:tt)*) => {$($tt)*};
224 #[proc_macros::identity]
226 identity!(Struct$0 { field: 0 });
234 fn goto_def_for_extern_crate() {
237 //- /main.rs crate:main deps:std
239 //- /std/lib.rs crate:std
247 fn goto_def_for_renamed_extern_crate() {
250 //- /main.rs crate:main deps:std
251 extern crate std as abc$0;
252 //- /std/lib.rs crate:std
260 fn goto_def_in_items() {
271 fn goto_def_at_start_of_item() {
282 fn goto_definition_resolves_correct_name() {
301 fn goto_def_for_module_declaration() {
326 fn goto_def_for_macros() {
329 macro_rules! foo { () => { () } }
339 fn goto_def_for_macros_from_other_crates() {
342 //- /lib.rs crate:main deps:foo
348 //- /foo/lib.rs crate:foo
350 macro_rules! foo { () => { () } }
357 fn goto_def_for_macros_in_use_tree() {
360 //- /lib.rs crate:main deps:foo
363 //- /foo/lib.rs crate:foo
365 macro_rules! foo { () => { () } }
372 fn goto_def_for_macro_defined_fn_with_arg() {
376 macro_rules! define_fn {
377 ($name:ident) => (fn $name() {})
391 fn goto_def_for_macro_defined_fn_no_arg() {
395 macro_rules! define_fn {
410 fn goto_definition_works_for_macro_inside_pattern() {
414 macro_rules! foo {() => {0}}
427 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
431 macro_rules! foo {() => {0}}
443 fn goto_def_for_use_alias() {
446 //- /lib.rs crate:main deps:foo
449 //- /foo/lib.rs crate:foo
457 fn goto_def_for_use_alias_foo_macro() {
460 //- /lib.rs crate:main deps:foo
461 use foo::foo as bar$0;
463 //- /foo/lib.rs crate:foo
465 macro_rules! foo { () => { () } }
472 fn goto_def_for_methods() {
477 fn frobnicate(&self) { }
489 fn goto_def_for_fields() {
504 fn goto_def_for_record_fields() {
522 fn goto_def_for_record_pat_fields() {
530 fn bar(foo: Foo) -> Foo {
531 let Foo { spam$0: _, } = foo
538 fn goto_def_for_record_fields_macros() {
541 macro_rules! m { () => { 92 };}
542 struct Foo { spam: u32 }
553 fn goto_for_tuple_fields() {
568 fn goto_def_for_ufcs_inherent_methods() {
584 fn goto_def_for_ufcs_trait_methods_through_traits() {
599 fn goto_def_for_ufcs_trait_methods_through_self() {
606 impl Trait for Foo {}
616 fn goto_definition_on_self() {
622 pub fn new() -> Self {
633 pub fn new() -> Self$0 {
645 pub fn new() -> Self$0 {
657 pub fn thing(a: &Self$0) {
665 fn goto_definition_on_self_in_trait_impl() {
698 fn goto_def_when_used_on_definition_name_itself() {
701 struct Foo$0 { value: u32 }
723 enum Foo$0 { Variant }
741 static INNER$0: &str = "";
748 const INNER$0: &str = "";
755 type Thing$0 = Option<()>;
783 fn goto_from_macro() {
787 ($($tt:tt)*) => { $($tt)* }
796 mod confuse_index { fn foo(); }
802 fn goto_through_format() {
806 macro_rules! format {
807 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
809 #[rustc_builtin_macro]
811 macro_rules! format_args {
812 ($fmt:expr) => ({ /* compiler built-in */ });
813 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
816 pub use crate::format_args;
817 fn foo() {} // for index confusion
822 format!("{}", fo$0o())
829 fn goto_through_included_file() {
833 #[rustc_builtin_macro]
834 macro_rules! include {}
837 //^^^^^^^^^^^^^^^^^^^
854 fn goto_for_type_param() {
857 struct Foo<T: Clone> { t: $0T }
864 fn goto_within_macro() {
868 ($($tt:tt)*) => ($($tt)*)
885 ($($tt:tt)*) => ($($tt)*)
901 fn goto_def_in_local_fn() {
916 fn goto_def_in_local_macro() {
920 macro_rules! foo { () => { () } }
929 fn goto_def_for_field_init_shorthand() {
932 struct Foo { x: i32 }
944 fn goto_def_for_enum_variant_field() {
953 Foo::Bar { x$0 } => x
962 fn goto_def_for_enum_variant_self_pattern_const() {
969 match self { Self::Bar$0 => {} }
977 fn goto_def_for_enum_variant_self_pattern_record() {
980 enum Foo { Bar { val: i32 } }
983 fn baz(self) -> i32 {
984 match self { Self::Bar$0 { val } => {} }
992 fn goto_def_for_enum_variant_self_expr_const() {
998 fn baz(self) { Self::Bar$0; }
1005 fn goto_def_for_enum_variant_self_expr_record() {
1008 enum Foo { Bar { val: i32 } }
1011 fn baz(self) { Self::Bar$0 {val: 4}; }
1018 fn goto_def_for_type_alias_generic_parameter() {
1021 type Alias<T> = T$0;
1028 fn goto_def_for_macro_container() {
1031 //- /lib.rs crate:main deps:foo
1032 foo::module$0::mac!();
1034 //- /foo/lib.rs crate:foo
1038 macro_rules! _mac { () => { () } }
1039 pub use crate::_mac as mac;
1046 fn goto_def_for_assoc_ty_in_path() {
1054 fn f() -> impl Iterator<Item$0 = u8> {}
1060 fn goto_def_for_super_assoc_ty_in_path() {
1070 fn f() -> impl Sub<Item$0 = u8> {}
1076 fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {
1086 let _foo_enum: bar::Foo$0 = bar::Foo {};
1093 fn unknown_assoc_ty() {
1096 trait Iterator { type Item; }
1097 fn f() -> impl Iterator<Invalid$0 = u8> {}
1103 fn goto_def_for_assoc_ty_in_path_multiple() {
1112 fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1123 fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1129 fn goto_def_for_assoc_ty_ufcs() {
1137 fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1143 fn goto_def_for_assoc_ty_ufcs_multiple() {
1152 fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1163 fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1169 fn goto_self_param_ty_specified() {
1175 fn bar(self: &Foo) {
1184 fn goto_self_param_on_decl() {
1198 fn goto_lifetime_param_on_decl() {
1201 fn foo<'foobar$0>(_: &'foobar ()) {
1208 fn goto_lifetime_param_decl() {
1211 fn foo<'foobar>(_: &'foobar$0 ()) {
1218 fn goto_lifetime_param_decl_nested() {
1221 fn foo<'foobar>(_: &'foobar ()) {
1222 fn foo<'foobar>(_: &'foobar$0 ()) {}
1229 fn goto_lifetime_hrtb() {
1230 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1234 fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1241 fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1248 fn goto_lifetime_hrtb_for_type() {
1249 // FIXME: requires ForTypes to be implemented
1252 fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1262 fn foo<'foo>(_: &'foo ()) {
1274 fn goto_def_for_intra_doc_link_same_file() {
1277 /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1280 /// You might want to see [`std::fs::read()`] too.
1289 fn goto_def_for_intra_doc_link_inner() {
1304 fn goto_incomplete_field() {
1309 fn foo() { A { a$0: }; }
1315 fn goto_proc_macro() {
1318 //- /main.rs crate:main deps:mac
1323 //- /mac.rs crate:mac
1324 #![crate_type="proc-macro"]
1333 fn goto_intra_doc_links() {
1338 /// This is the item. Cool!
1343 /// Gives you a [`TheItem$0`].
1345 /// [`TheItem`]: theitem::TheItem
1346 pub fn gimme() -> theitem::TheItem {
1354 fn goto_ident_from_pat_macro() {
1358 ($name:ident) => { Enum::Variant1($name) }
1372 Enum::Variant2 => {}
1385 #[rustc_builtin_macro]
1386 macro_rules! include_str {}
1389 let str = include_str!("foo.txt$0");
1399 fn goto_doc_include_str() {
1403 #[rustc_builtin_macro]
1404 macro_rules! include_str {}
1406 #[doc = include_str!("docs.md$0")]
1417 fn goto_shadow_include() {
1421 macro_rules! include {
1422 ("included.rs") => {}
1425 include!("included.rs$0");
1433 mod goto_impl_of_trait_fn
{
1436 fn cursor_on_impl() {
1445 impl Twait for Stwuct {
1462 impl Twait for Stwuct {
1483 impl Twait for Stwuct {
1495 fn where_clause_can_work() {
1504 impl <T:EA> G for Gen<T> {
1508 impl <T> G for Gen<T>
1518 let gen = Gen::<A>(A);
1525 fn wc_case_is_ok() {
1532 trait Bound: BParent{}
1534 impl <T> G for Gen<T>
1544 let gen = Gen::<A>(A);
1552 fn method_call_defaulted() {
1562 impl Twait for Stwuct {
1573 fn method_call_on_generic() {
1581 fn f<T: Twait>(s: T) {
1590 fn goto_def_of_trait_impl_const() {
1600 impl Twait for Stwuct {
1601 const NOMS$0: bool = true;
1608 fn goto_def_of_trait_impl_type_alias() {
1618 impl Twait for Stwuct {
1626 fn goto_def_derive_input() {
1630 #[rustc_builtin_macro]
1640 #[rustc_builtin_macro]
1643 #[cfg_attr(feature = "false", derive)]
1652 #[rustc_builtin_macro]
1656 #[derive(foo::Copy$0)]
1665 #[rustc_builtin_macro]
1668 #[derive(foo$0::Copy)]
1675 fn goto_def_in_macro_multi() {
1684 fn $ident(Foo { $ident }: Foo) {}
1701 let _: $ident = $ident;
1712 fn goto_await_poll() {
1715 //- minicore: future
1719 impl core::future::Future for MyFut {
1724 self: std::pin::Pin<&mut Self>,
1725 cx: &mut std::task::Context<'_>
1726 ) -> std::task::Poll<Self::Output>
1740 fn goto_await_into_future_poll() {
1743 //- minicore: future
1747 impl core::future::IntoFuture for Futurable {
1748 type IntoFuture = MyFut;
1753 impl core::future::Future for MyFut {
1758 self: std::pin::Pin<&mut Self>,
1759 cx: &mut std::task::Context<'_>
1760 ) -> std::task::Poll<Self::Output>
1781 impl core::ops::Try for Struct {
1796 fn goto_index_op() {
1803 impl core::ops::Index<usize> for Struct {
1818 fn goto_prefix_op() {
1825 impl core::ops::Deref for Struct {
1847 impl core::ops::Add for Struct {
1862 fn goto_bin_op_multiple_impl() {
1867 impl core::ops::Add for S {
1872 impl core::ops::Add<usize> for S {
1887 impl core::ops::Add for S {
1891 impl core::ops::Add<usize> for S {
1905 fn path_call_multiple_trait_impl() {
1911 impl Trait<i32> for usize {
1915 impl Trait<i64> for usize {
1929 impl Trait<i32> for usize {
1932 impl Trait<i64> for usize {
1944 fn query_impls_in_nearest_block() {