1 use std::{convert::TryInto, 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 kind if kind.is_trivia() => 0,
46 if let Some(doc_comment) = token_as_doc_comment(&original_token) {
47 return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
48 let nav = def.try_to_nav(db)?;
49 Some(RangeInfo::new(original_token.text_range(), vec![nav]))
53 .descend_into_macros(original_token.clone())
56 let parent = token.parent()?;
57 if let Some(tt) = ast::TokenTree::cast(parent) {
58 if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), position.file_id)
64 IdentClass::classify_token(sema, &token)?
68 try_filter_trait_item_definition(sema, &def)
69 .unwrap_or_else(|| def_to_nav(sema.db, def))
76 .collect::<Vec<NavigationTarget>>();
78 Some(RangeInfo::new(original_token.text_range(), navs))
81 fn try_lookup_include_path(
82 sema: &Semantics<'_, RootDatabase>,
86 ) -> Option<NavigationTarget> {
87 let token = ast::String::cast(token)?;
88 let path = token.value()?.into_owned();
89 let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
90 let name = macro_call.path()?.segment()?.name_ref()?;
91 if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
94 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
95 let size = sema.db.file_text(file_id).len().try_into().ok()?;
96 Some(NavigationTarget {
98 full_range: TextRange::new(0.into(), size),
102 container_name: None,
107 /// finds the trait definition of an impl'd item, except function
110 /// trait A { type a; }
112 /// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait
114 fn try_filter_trait_item_definition(
115 sema: &Semantics<'_, RootDatabase>,
117 ) -> Option<Vec<NavigationTarget>> {
119 let assoc = def.as_assoc_item(db)?;
121 AssocItem::Function(..) => None,
122 AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
123 let imp = match assoc.container(db) {
124 hir::AssocItemContainer::Impl(imp) => imp,
127 let trait_ = imp.trait_(db)?;
128 let name = def.name(db)?;
129 let discri_value = discriminant(&assoc);
133 .filter(|itm| discriminant(*itm) == discri_value)
134 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
140 fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
141 def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
146 use ide_db::base_db::FileRange;
147 use itertools::Itertools;
152 fn check(ra_fixture: &str) {
153 let (analysis, position, expected) = fixture::annotations(ra_fixture);
154 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
156 panic!("unresolved reference")
159 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
162 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
164 .collect::<Vec<_>>();
165 let expected = expected
167 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
169 .collect::<Vec<_>>();
170 assert_eq!(expected, navs);
173 fn check_unresolved(ra_fixture: &str) {
174 let (analysis, position) = fixture::position(ra_fixture);
175 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
177 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
181 fn goto_def_if_items_same_name() {
198 fn goto_def_in_mac_call_in_attr_invoc() {
201 //- proc_macros: identity
207 macro_rules! identity {
208 ($($tt:tt)*) => {$($tt)*};
211 #[proc_macros::identity]
213 identity!(Struct$0 { field: 0 });
221 fn goto_def_for_extern_crate() {
224 //- /main.rs crate:main deps:std
226 //- /std/lib.rs crate:std
234 fn goto_def_for_renamed_extern_crate() {
237 //- /main.rs crate:main deps:std
238 extern crate std as abc$0;
239 //- /std/lib.rs crate:std
247 fn goto_def_in_items() {
258 fn goto_def_at_start_of_item() {
269 fn goto_definition_resolves_correct_name() {
288 fn goto_def_for_module_declaration() {
313 fn goto_def_for_macros() {
316 macro_rules! foo { () => { () } }
326 fn goto_def_for_macros_from_other_crates() {
329 //- /lib.rs crate:main deps:foo
335 //- /foo/lib.rs crate:foo
337 macro_rules! foo { () => { () } }
344 fn goto_def_for_macros_in_use_tree() {
347 //- /lib.rs crate:main deps:foo
350 //- /foo/lib.rs crate:foo
352 macro_rules! foo { () => { () } }
359 fn goto_def_for_macro_defined_fn_with_arg() {
363 macro_rules! define_fn {
364 ($name:ident) => (fn $name() {})
378 fn goto_def_for_macro_defined_fn_no_arg() {
382 macro_rules! define_fn {
397 fn goto_definition_works_for_macro_inside_pattern() {
401 macro_rules! foo {() => {0}}
414 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
418 macro_rules! foo {() => {0}}
430 fn goto_def_for_use_alias() {
433 //- /lib.rs crate:main deps:foo
436 //- /foo/lib.rs crate:foo
444 fn goto_def_for_use_alias_foo_macro() {
447 //- /lib.rs crate:main deps:foo
448 use foo::foo as bar$0;
450 //- /foo/lib.rs crate:foo
452 macro_rules! foo { () => { () } }
459 fn goto_def_for_methods() {
464 fn frobnicate(&self) { }
476 fn goto_def_for_fields() {
491 fn goto_def_for_record_fields() {
509 fn goto_def_for_record_pat_fields() {
517 fn bar(foo: Foo) -> Foo {
518 let Foo { spam$0: _, } = foo
525 fn goto_def_for_record_fields_macros() {
528 macro_rules! m { () => { 92 };}
529 struct Foo { spam: u32 }
540 fn goto_for_tuple_fields() {
555 fn goto_def_for_ufcs_inherent_methods() {
571 fn goto_def_for_ufcs_trait_methods_through_traits() {
586 fn goto_def_for_ufcs_trait_methods_through_self() {
593 impl Trait for Foo {}
603 fn goto_definition_on_self() {
609 pub fn new() -> Self {
620 pub fn new() -> Self$0 {
632 pub fn new() -> Self$0 {
644 pub fn thing(a: &Self$0) {
652 fn goto_definition_on_self_in_trait_impl() {
685 fn goto_def_when_used_on_definition_name_itself() {
688 struct Foo$0 { value: u32 }
710 enum Foo$0 { Variant }
728 static INNER$0: &str = "";
735 const INNER$0: &str = "";
742 type Thing$0 = Option<()>;
763 fn goto_from_macro() {
767 ($($tt:tt)*) => { $($tt)* }
776 mod confuse_index { fn foo(); }
782 fn goto_through_format() {
786 macro_rules! format {
787 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
789 #[rustc_builtin_macro]
791 macro_rules! format_args {
792 ($fmt:expr) => ({ /* compiler built-in */ });
793 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
796 pub use crate::format_args;
797 fn foo() {} // for index confusion
802 format!("{}", fo$0o())
809 fn goto_through_included_file() {
813 #[rustc_builtin_macro]
814 macro_rules! include {}
817 //^^^^^^^^^^^^^^^^^^^
834 fn goto_for_type_param() {
837 struct Foo<T: Clone> { t: $0T }
844 fn goto_within_macro() {
848 ($($tt:tt)*) => ($($tt)*)
865 ($($tt:tt)*) => ($($tt)*)
881 fn goto_def_in_local_fn() {
896 fn goto_def_in_local_macro() {
900 macro_rules! foo { () => { () } }
909 fn goto_def_for_field_init_shorthand() {
912 struct Foo { x: i32 }
924 fn goto_def_for_enum_variant_field() {
933 Foo::Bar { x$0 } => x
942 fn goto_def_for_enum_variant_self_pattern_const() {
949 match self { Self::Bar$0 => {} }
957 fn goto_def_for_enum_variant_self_pattern_record() {
960 enum Foo { Bar { val: i32 } }
963 fn baz(self) -> i32 {
964 match self { Self::Bar$0 { val } => {} }
972 fn goto_def_for_enum_variant_self_expr_const() {
978 fn baz(self) { Self::Bar$0; }
985 fn goto_def_for_enum_variant_self_expr_record() {
988 enum Foo { Bar { val: i32 } }
991 fn baz(self) { Self::Bar$0 {val: 4}; }
998 fn goto_def_for_type_alias_generic_parameter() {
1001 type Alias<T> = T$0;
1008 fn goto_def_for_macro_container() {
1011 //- /lib.rs crate:main deps:foo
1012 foo::module$0::mac!();
1014 //- /foo/lib.rs crate:foo
1018 macro_rules! _mac { () => { () } }
1019 pub use crate::_mac as mac;
1026 fn goto_def_for_assoc_ty_in_path() {
1034 fn f() -> impl Iterator<Item$0 = u8> {}
1040 fn goto_def_for_super_assoc_ty_in_path() {
1050 fn f() -> impl Sub<Item$0 = u8> {}
1056 fn unknown_assoc_ty() {
1059 trait Iterator { type Item; }
1060 fn f() -> impl Iterator<Invalid$0 = u8> {}
1066 fn goto_def_for_assoc_ty_in_path_multiple() {
1075 fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1086 fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1092 fn goto_def_for_assoc_ty_ufcs() {
1100 fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1106 fn goto_def_for_assoc_ty_ufcs_multiple() {
1115 fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1126 fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1132 fn goto_self_param_ty_specified() {
1138 fn bar(self: &Foo) {
1147 fn goto_self_param_on_decl() {
1161 fn goto_lifetime_param_on_decl() {
1164 fn foo<'foobar$0>(_: &'foobar ()) {
1171 fn goto_lifetime_param_decl() {
1174 fn foo<'foobar>(_: &'foobar$0 ()) {
1181 fn goto_lifetime_param_decl_nested() {
1184 fn foo<'foobar>(_: &'foobar ()) {
1185 fn foo<'foobar>(_: &'foobar$0 ()) {}
1192 fn goto_lifetime_hrtb() {
1193 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1197 fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1204 fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1211 fn goto_lifetime_hrtb_for_type() {
1212 // FIXME: requires ForTypes to be implemented
1215 fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1225 fn foo<'foo>(_: &'foo ()) {
1237 fn goto_def_for_intra_doc_link_same_file() {
1240 /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
1243 /// You might want to see [`std::fs::read()`] too.
1252 fn goto_def_for_intra_doc_link_inner() {
1267 fn goto_incomplete_field() {
1272 fn foo() { A { a$0: }; }
1278 fn goto_proc_macro() {
1281 //- /main.rs crate:main deps:mac
1286 //- /mac.rs crate:mac
1287 #![crate_type="proc-macro"]
1296 fn goto_intra_doc_links() {
1301 /// This is the item. Cool!
1306 /// Gives you a [`TheItem$0`].
1308 /// [`TheItem`]: theitem::TheItem
1309 pub fn gimme() -> theitem::TheItem {
1317 fn goto_ident_from_pat_macro() {
1321 ($name:ident) => { Enum::Variant1($name) }
1335 Enum::Variant2 => {}
1348 let str = include_str!("foo.txt$0");
1357 mod goto_impl_of_trait_fn {
1360 fn cursor_on_impl() {
1369 impl Twait for Stwuct {
1386 impl Twait for Stwuct {
1407 impl Twait for Stwuct {
1419 fn where_clause_can_work() {
1428 impl <T:EA> G for Gen<T> {
1432 impl <T> G for Gen<T>
1442 let gen = Gen::<A>(A);
1449 fn wc_case_is_ok() {
1456 trait Bound: BParent{}
1458 impl <T> G for Gen<T>
1468 let gen = Gen::<A>(A);
1476 fn method_call_defaulted() {
1486 impl Twait for Stwuct {
1497 fn method_call_on_generic() {
1505 fn f<T: Twait>(s: T) {
1514 fn goto_def_of_trait_impl_const() {
1524 impl Twait for Stwuct {
1525 const NOMS$0: bool = true;
1532 fn goto_def_of_trait_impl_type_alias() {
1542 impl Twait for Stwuct {
1550 fn goto_def_derive_input() {
1554 #[rustc_builtin_macro]
1564 #[rustc_builtin_macro]
1567 #[cfg_attr(feature = "false", derive)]
1576 #[rustc_builtin_macro]
1580 #[derive(foo::Copy$0)]
1589 #[rustc_builtin_macro]
1592 #[derive(foo$0::Copy)]
1599 fn goto_def_in_macro_multi() {
1608 fn $ident(Foo { $ident }: Foo) {}
1625 let _: $ident = $ident;