1 use std::convert::TryInto;
3 use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav};
4 use hir::{AsAssocItem, 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.
19 // | Editor | Shortcut
21 // | VS Code | kbd:[F12]
24 // image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
25 pub(crate) fn goto_definition(
27 position: FilePosition,
28 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
29 let sema = &Semantics::new(db);
30 let file = sema.parse(position.file_id).syntax().clone();
32 pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
41 kind if kind.is_trivia() => 0,
44 if let Some(doc_comment) = token_as_doc_comment(&original_token) {
45 return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
46 let nav = def.try_to_nav(db)?;
47 Some(RangeInfo::new(original_token.text_range(), vec![nav]))
51 .descend_into_macros(original_token.clone())
54 let parent = token.parent()?;
55 if let Some(tt) = ast::TokenTree::cast(parent) {
56 if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), position.file_id)
62 IdentClass::classify_token(sema, &token)?
66 try_find_trait_item_definition(sema.db, &def)
67 .unwrap_or_else(|| def_to_nav(sema.db, def))
74 .collect::<Vec<NavigationTarget>>();
76 Some(RangeInfo::new(original_token.text_range(), navs))
79 fn try_lookup_include_path(
80 sema: &Semantics<RootDatabase>,
84 ) -> Option<NavigationTarget> {
85 let token = ast::String::cast(token)?;
86 let path = token.value()?.into_owned();
87 let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
88 let name = macro_call.path()?.segment()?.name_ref()?;
89 if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
92 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
93 let size = sema.db.file_text(file_id).len().try_into().ok()?;
94 Some(NavigationTarget {
96 full_range: TextRange::new(0.into(), size),
100 container_name: None,
106 /// finds the trait definition of an impl'd item
109 /// trait A { fn a(); }
111 /// impl A for S { fn a(); } // <-- on this function, will get the location of a() in the trait
113 fn try_find_trait_item_definition(
116 ) -> Option<Vec<NavigationTarget>> {
117 let name = def.name(db)?;
118 let assoc = def.as_assoc_item(db)?;
120 let imp = match assoc.container(db) {
121 hir::AssocItemContainer::Impl(imp) => imp,
125 let trait_ = imp.trait_(db)?;
129 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
133 fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
134 def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
139 use ide_db::base_db::FileRange;
140 use itertools::Itertools;
145 fn check(ra_fixture: &str) {
146 let (analysis, position, expected) = fixture::annotations(ra_fixture);
147 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
149 panic!("unresolved reference")
152 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
155 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
157 .collect::<Vec<_>>();
158 let expected = expected
160 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
162 .collect::<Vec<_>>();
163 assert_eq!(expected, navs);
166 fn check_unresolved(ra_fixture: &str) {
167 let (analysis, position) = fixture::position(ra_fixture);
168 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
170 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
174 fn goto_def_in_mac_call_in_attr_invoc() {
177 //- proc_macros: identity
183 macro_rules! identity {
184 ($($tt:tt)*) => {$($tt)*};
187 #[proc_macros::identity]
189 identity!(Struct$0 { field: 0 });
197 fn goto_def_for_extern_crate() {
200 //- /main.rs crate:main deps:std
202 //- /std/lib.rs crate:std
210 fn goto_def_for_renamed_extern_crate() {
213 //- /main.rs crate:main deps:std
214 extern crate std as abc$0;
215 //- /std/lib.rs crate:std
223 fn goto_def_in_items() {
234 fn goto_def_at_start_of_item() {
245 fn goto_definition_resolves_correct_name() {
264 fn goto_def_for_module_declaration() {
289 fn goto_def_for_macros() {
292 macro_rules! foo { () => { () } }
302 fn goto_def_for_macros_from_other_crates() {
305 //- /lib.rs crate:main deps:foo
311 //- /foo/lib.rs crate:foo
313 macro_rules! foo { () => { () } }
320 fn goto_def_for_macros_in_use_tree() {
323 //- /lib.rs crate:main deps:foo
326 //- /foo/lib.rs crate:foo
328 macro_rules! foo { () => { () } }
335 fn goto_def_for_macro_defined_fn_with_arg() {
339 macro_rules! define_fn {
340 ($name:ident) => (fn $name() {})
354 fn goto_def_for_macro_defined_fn_no_arg() {
358 macro_rules! define_fn {
373 fn goto_definition_works_for_macro_inside_pattern() {
377 macro_rules! foo {() => {0}}
390 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
394 macro_rules! foo {() => {0}}
406 fn goto_def_for_use_alias() {
409 //- /lib.rs crate:main deps:foo
412 //- /foo/lib.rs crate:foo
420 fn goto_def_for_use_alias_foo_macro() {
423 //- /lib.rs crate:main deps:foo
424 use foo::foo as bar$0;
426 //- /foo/lib.rs crate:foo
428 macro_rules! foo { () => { () } }
435 fn goto_def_for_methods() {
440 fn frobnicate(&self) { }
452 fn goto_def_for_fields() {
467 fn goto_def_for_record_fields() {
485 fn goto_def_for_record_pat_fields() {
493 fn bar(foo: Foo) -> Foo {
494 let Foo { spam$0: _, } = foo
501 fn goto_def_for_record_fields_macros() {
504 macro_rules! m { () => { 92 };}
505 struct Foo { spam: u32 }
516 fn goto_for_tuple_fields() {
531 fn goto_def_for_ufcs_inherent_methods() {
547 fn goto_def_for_ufcs_trait_methods_through_traits() {
562 fn goto_def_for_ufcs_trait_methods_through_self() {
569 impl Trait for Foo {}
579 fn goto_definition_on_self() {
585 pub fn new() -> Self {
596 pub fn new() -> Self$0 {
608 pub fn new() -> Self$0 {
620 pub fn thing(a: &Self$0) {
628 fn goto_definition_on_self_in_trait_impl() {
661 fn goto_def_when_used_on_definition_name_itself() {
664 struct Foo$0 { value: u32 }
686 enum Foo$0 { Variant }
704 static INNER$0: &str = "";
711 const INNER$0: &str = "";
718 type Thing$0 = Option<()>;
739 fn goto_from_macro() {
743 ($($tt:tt)*) => { $($tt)* }
752 mod confuse_index { fn foo(); }
758 fn goto_through_format() {
762 macro_rules! format {
763 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
765 #[rustc_builtin_macro]
767 macro_rules! format_args {
768 ($fmt:expr) => ({ /* compiler built-in */ });
769 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
772 pub use crate::format_args;
773 fn foo() {} // for index confusion
778 format!("{}", fo$0o())
785 fn goto_through_included_file() {
789 #[rustc_builtin_macro]
790 macro_rules! include {}
793 //^^^^^^^^^^^^^^^^^^^
810 fn goto_for_type_param() {
813 struct Foo<T: Clone> { t: $0T }
820 fn goto_within_macro() {
824 ($($tt:tt)*) => ($($tt)*)
841 ($($tt:tt)*) => ($($tt)*)
857 fn goto_def_in_local_fn() {
872 fn goto_def_in_local_macro() {
876 macro_rules! foo { () => { () } }
885 fn goto_def_for_field_init_shorthand() {
888 struct Foo { x: i32 }
900 fn goto_def_for_enum_variant_field() {
909 Foo::Bar { x$0 } => x
918 fn goto_def_for_enum_variant_self_pattern_const() {
925 match self { Self::Bar$0 => {} }
933 fn goto_def_for_enum_variant_self_pattern_record() {
936 enum Foo { Bar { val: i32 } }
939 fn baz(self) -> i32 {
940 match self { Self::Bar$0 { val } => {} }
948 fn goto_def_for_enum_variant_self_expr_const() {
954 fn baz(self) { Self::Bar$0; }
961 fn goto_def_for_enum_variant_self_expr_record() {
964 enum Foo { Bar { val: i32 } }
967 fn baz(self) { Self::Bar$0 {val: 4}; }
974 fn goto_def_for_type_alias_generic_parameter() {
984 fn goto_def_for_macro_container() {
987 //- /lib.rs crate:main deps:foo
988 foo::module$0::mac!();
990 //- /foo/lib.rs crate:foo
994 macro_rules! _mac { () => { () } }
995 pub use crate::_mac as mac;
1002 fn goto_def_for_assoc_ty_in_path() {
1010 fn f() -> impl Iterator<Item$0 = u8> {}
1016 fn goto_def_for_super_assoc_ty_in_path() {
1026 fn f() -> impl Sub<Item$0 = u8> {}
1032 fn unknown_assoc_ty() {
1035 trait Iterator { type Item; }
1036 fn f() -> impl Iterator<Invalid$0 = u8> {}
1042 fn goto_def_for_assoc_ty_in_path_multiple() {
1051 fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1062 fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1068 fn goto_def_for_assoc_ty_ufcs() {
1076 fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1082 fn goto_def_for_assoc_ty_ufcs_multiple() {
1091 fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1102 fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1108 fn goto_self_param_ty_specified() {
1114 fn bar(self: &Foo) {
1123 fn goto_self_param_on_decl() {
1137 fn goto_lifetime_param_on_decl() {
1140 fn foo<'foobar$0>(_: &'foobar ()) {
1147 fn goto_lifetime_param_decl() {
1150 fn foo<'foobar>(_: &'foobar$0 ()) {
1157 fn goto_lifetime_param_decl_nested() {
1160 fn foo<'foobar>(_: &'foobar ()) {
1161 fn foo<'foobar>(_: &'foobar$0 ()) {}
1168 fn goto_lifetime_hrtb() {
1169 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1173 fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1180 fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1187 fn goto_lifetime_hrtb_for_type() {
1188 // FIXME: requires ForTypes to be implemented
1191 fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1201 fn foo<'foo>(_: &'foo ()) {
1213 fn goto_def_for_intra_doc_link_same_file() {
1216 /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1219 /// You might want to see [`std::fs::read()`] too.
1228 fn goto_def_for_intra_doc_link_inner() {
1243 fn goto_incomplete_field() {
1248 fn foo() { A { a$0: }; }
1254 fn goto_proc_macro() {
1257 //- /main.rs crate:main deps:mac
1262 //- /mac.rs crate:mac
1263 #![crate_type="proc-macro"]
1272 fn goto_intra_doc_links() {
1277 /// This is the item. Cool!
1282 /// Gives you a [`TheItem$0`].
1284 /// [`TheItem`]: theitem::TheItem
1285 pub fn gimme() -> theitem::TheItem {
1293 fn goto_ident_from_pat_macro() {
1297 ($name:ident) => { Enum::Variant1($name) }
1311 Enum::Variant2 => {}
1324 let str = include_str!("foo.txt$0");
1334 fn goto_def_of_trait_impl_fn() {
1344 impl Twait for Stwuct {
1352 fn goto_def_of_trait_impl_const() {
1362 impl Twait for Stwuct {
1363 const NOMS$0: bool = true;
1370 fn goto_def_of_trait_impl_type_alias() {
1380 impl Twait for Stwuct {
1388 fn goto_def_derive_input() {
1392 #[rustc_builtin_macro]
1402 #[rustc_builtin_macro]
1405 #[cfg_attr(feature = "false", derive)]
1414 #[rustc_builtin_macro]
1418 #[derive(foo::Copy$0)]
1427 #[rustc_builtin_macro]
1430 #[derive(foo$0::Copy)]
1437 fn goto_def_in_macro_multi() {
1446 fn $ident(Foo { $ident }: Foo) {}
1463 let _: $ident = $ident;