1 use std::convert::TryInto;
4 display::TryToNav, doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo,
6 use hir::{AsAssocItem, Semantics};
8 base_db::{AnchoredPath, FileId, FileLoader},
10 helpers::pick_best_token,
13 use itertools::Itertools;
14 use syntax::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
16 // Feature: Go to Definition
18 // Navigates to the definition of an identifier.
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 {
35 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
36 kind if kind.is_trivia() => 0,
39 if let Some(doc_comment) = token_as_doc_comment(&original_token) {
40 return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
41 let nav = def.try_to_nav(db)?;
42 Some(RangeInfo::new(original_token.text_range(), vec![nav]))
46 .descend_into_macros(original_token.clone())
49 let parent = token.parent()?;
50 if let Some(tt) = ast::TokenTree::cast(parent) {
52 try_lookup_include_path(sema, tt, token.clone(), position.file_id)
58 Definition::from_token(sema, &token)
61 try_find_trait_item_definition(sema.db, &def)
62 .unwrap_or_else(|| def_to_nav(sema.db, def))
69 .collect::<Vec<NavigationTarget>>();
71 Some(RangeInfo::new(original_token.text_range(), navs))
74 fn try_lookup_include_path(
75 sema: &Semantics<RootDatabase>,
79 ) -> Option<Vec<NavigationTarget>> {
80 let token = ast::String::cast(token)?;
81 let path = token.value()?.into_owned();
82 let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
83 let name = macro_call.path()?.segment()?.name_ref()?;
84 if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
87 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
88 let size = sema.db.file_text(file_id).len().try_into().ok()?;
89 Some(vec![NavigationTarget {
91 full_range: TextRange::new(0.into(), size),
101 /// finds the trait definition of an impl'd item
104 /// trait A { fn a(); }
106 /// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait
108 fn try_find_trait_item_definition(
111 ) -> Option<Vec<NavigationTarget>> {
112 let name = def.name(db)?;
113 let assoc = def.as_assoc_item(db)?;
115 let imp = match assoc.container(db) {
116 hir::AssocItemContainer::Impl(imp) => imp,
120 let trait_ = imp.trait_(db)?;
124 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
128 fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
129 def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
134 use ide_db::base_db::FileRange;
135 use itertools::Itertools;
140 fn check(ra_fixture: &str) {
141 let (analysis, position, expected) = fixture::annotations(ra_fixture);
142 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
144 panic!("unresolved reference")
147 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
150 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
152 .collect::<Vec<_>>();
153 let expected = expected
155 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
157 .collect::<Vec<_>>();
158 assert_eq!(expected, navs);
161 fn check_unresolved(ra_fixture: &str) {
162 let (analysis, position) = fixture::position(ra_fixture);
163 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
165 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
169 fn goto_def_in_mac_call_in_attr_invoc() {
172 //- proc_macros: identity
178 macro_rules! identity {
179 ($($tt:tt)*) => {$($tt)*};
182 #[proc_macros::identity]
184 identity!(Struct$0 { field: 0 });
192 fn goto_def_for_extern_crate() {
195 //- /main.rs crate:main deps:std
197 //- /std/lib.rs crate:std
205 fn goto_def_for_renamed_extern_crate() {
208 //- /main.rs crate:main deps:std
209 extern crate std as abc$0;
210 //- /std/lib.rs crate:std
218 fn goto_def_in_items() {
229 fn goto_def_at_start_of_item() {
240 fn goto_definition_resolves_correct_name() {
259 fn goto_def_for_module_declaration() {
284 fn goto_def_for_macros() {
287 macro_rules! foo { () => { () } }
297 fn goto_def_for_macros_from_other_crates() {
300 //- /lib.rs crate:main deps:foo
306 //- /foo/lib.rs crate:foo
308 macro_rules! foo { () => { () } }
315 fn goto_def_for_macros_in_use_tree() {
318 //- /lib.rs crate:main deps:foo
321 //- /foo/lib.rs crate:foo
323 macro_rules! foo { () => { () } }
330 fn goto_def_for_macro_defined_fn_with_arg() {
334 macro_rules! define_fn {
335 ($name:ident) => (fn $name() {})
349 fn goto_def_for_macro_defined_fn_no_arg() {
353 macro_rules! define_fn {
368 fn goto_definition_works_for_macro_inside_pattern() {
372 macro_rules! foo {() => {0}}
385 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
389 macro_rules! foo {() => {0}}
401 fn goto_def_for_use_alias() {
404 //- /lib.rs crate:main deps:foo
407 //- /foo/lib.rs crate:foo
415 fn goto_def_for_use_alias_foo_macro() {
418 //- /lib.rs crate:main deps:foo
419 use foo::foo as bar$0;
421 //- /foo/lib.rs crate:foo
423 macro_rules! foo { () => { () } }
430 fn goto_def_for_methods() {
435 fn frobnicate(&self) { }
447 fn goto_def_for_fields() {
462 fn goto_def_for_record_fields() {
480 fn goto_def_for_record_pat_fields() {
488 fn bar(foo: Foo) -> Foo {
489 let Foo { spam$0: _, } = foo
496 fn goto_def_for_record_fields_macros() {
499 macro_rules! m { () => { 92 };}
500 struct Foo { spam: u32 }
511 fn goto_for_tuple_fields() {
526 fn goto_def_for_ufcs_inherent_methods() {
542 fn goto_def_for_ufcs_trait_methods_through_traits() {
557 fn goto_def_for_ufcs_trait_methods_through_self() {
564 impl Trait for Foo {}
574 fn goto_definition_on_self() {
580 pub fn new() -> Self {
591 pub fn new() -> Self$0 {
603 pub fn new() -> Self$0 {
615 pub fn thing(a: &Self$0) {
623 fn goto_definition_on_self_in_trait_impl() {
656 fn goto_def_when_used_on_definition_name_itself() {
659 struct Foo$0 { value: u32 }
681 enum Foo$0 { Variant }
699 static INNER$0: &str = "";
706 const INNER$0: &str = "";
713 type Thing$0 = Option<()>;
734 fn goto_from_macro() {
738 ($($tt:tt)*) => { $($tt)* }
747 mod confuse_index { fn foo(); }
753 fn goto_through_format() {
757 macro_rules! format {
758 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
760 #[rustc_builtin_macro]
762 macro_rules! format_args {
763 ($fmt:expr) => ({ /* compiler built-in */ });
764 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
767 pub use crate::format_args;
768 fn foo() {} // for index confusion
773 format!("{}", fo$0o())
780 fn goto_through_included_file() {
784 #[rustc_builtin_macro]
785 macro_rules! include {}
788 //^^^^^^^^^^^^^^^^^^^
805 fn goto_for_type_param() {
808 struct Foo<T: Clone> { t: $0T }
815 fn goto_within_macro() {
819 ($($tt:tt)*) => ($($tt)*)
836 ($($tt:tt)*) => ($($tt)*)
852 fn goto_def_in_local_fn() {
867 fn goto_def_in_local_macro() {
871 macro_rules! foo { () => { () } }
880 fn goto_def_for_field_init_shorthand() {
883 struct Foo { x: i32 }
895 fn goto_def_for_enum_variant_field() {
904 Foo::Bar { x$0 } => x
913 fn goto_def_for_enum_variant_self_pattern_const() {
920 match self { Self::Bar$0 => {} }
928 fn goto_def_for_enum_variant_self_pattern_record() {
931 enum Foo { Bar { val: i32 } }
934 fn baz(self) -> i32 {
935 match self { Self::Bar$0 { val } => {} }
943 fn goto_def_for_enum_variant_self_expr_const() {
949 fn baz(self) { Self::Bar$0; }
956 fn goto_def_for_enum_variant_self_expr_record() {
959 enum Foo { Bar { val: i32 } }
962 fn baz(self) { Self::Bar$0 {val: 4}; }
969 fn goto_def_for_type_alias_generic_parameter() {
979 fn goto_def_for_macro_container() {
982 //- /lib.rs crate:main deps:foo
983 foo::module$0::mac!();
985 //- /foo/lib.rs crate:foo
989 macro_rules! _mac { () => { () } }
990 pub use crate::_mac as mac;
997 fn goto_def_for_assoc_ty_in_path() {
1005 fn f() -> impl Iterator<Item$0 = u8> {}
1011 fn unknown_assoc_ty() {
1014 trait Iterator { type Item; }
1015 fn f() -> impl Iterator<Invalid$0 = u8> {}
1021 fn goto_def_for_assoc_ty_in_path_multiple() {
1030 fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1041 fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1047 fn goto_def_for_assoc_ty_ufcs() {
1055 fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1061 fn goto_def_for_assoc_ty_ufcs_multiple() {
1070 fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1081 fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1087 fn goto_self_param_ty_specified() {
1093 fn bar(self: &Foo) {
1102 fn goto_self_param_on_decl() {
1116 fn goto_lifetime_param_on_decl() {
1119 fn foo<'foobar$0>(_: &'foobar ()) {
1126 fn goto_lifetime_param_decl() {
1129 fn foo<'foobar>(_: &'foobar$0 ()) {
1136 fn goto_lifetime_param_decl_nested() {
1139 fn foo<'foobar>(_: &'foobar ()) {
1140 fn foo<'foobar>(_: &'foobar$0 ()) {}
1147 fn goto_lifetime_hrtb() {
1148 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1152 fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1159 fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1166 fn goto_lifetime_hrtb_for_type() {
1167 // FIXME: requires ForTypes to be implemented
1170 fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1180 fn foo<'foo>(_: &'foo ()) {
1192 fn goto_def_for_intra_doc_link_same_file() {
1195 /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1198 /// You might want to see [`std::fs::read()`] too.
1207 fn goto_def_for_intra_doc_link_inner() {
1222 fn goto_incomplete_field() {
1227 fn foo() { A { a$0: }; }
1233 fn goto_proc_macro() {
1236 //- /main.rs crate:main deps:mac
1241 //- /mac.rs crate:mac
1250 fn goto_intra_doc_links() {
1255 /// This is the item. Cool!
1260 /// Gives you a [`TheItem$0`].
1262 /// [`TheItem`]: theitem::TheItem
1263 pub fn gimme() -> theitem::TheItem {
1271 fn goto_ident_from_pat_macro() {
1275 ($name:ident) => { Enum::Variant1($name) }
1289 Enum::Variant2 => {}
1302 let str = include_str!("foo.txt$0");
1312 fn goto_def_of_trait_impl_fn() {
1322 impl Twait for Stwuct {
1330 fn goto_def_of_trait_impl_const() {
1340 impl Twait for Stwuct {
1341 const NOMS$0: bool = true;
1348 fn goto_def_of_trait_impl_type_alias() {
1358 impl Twait for Stwuct {
1366 fn goto_def_derive_input() {
1370 #[rustc_builtin_macro]
1381 #[rustc_builtin_macro]
1385 #[derive(foo::Copy$0)]
1392 fn goto_def_in_macro_multi() {
1401 fn $ident(Foo { $ident }: Foo) {}
1418 let _: $ident = $ident;