5 defs::{NameClass, NameRefClass},
6 symbol_index, RootDatabase,
8 use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
11 display::{ToNav, TryToNav},
12 FilePosition, NavigationTarget, RangeInfo,
15 // Feature: Go to Definition
17 // Navigates to the definition of an identifier.
20 // | Editor | Shortcut
22 // | VS Code | kbd:[F12]
24 pub(crate) fn goto_definition(
26 position: FilePosition,
27 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
28 let sema = Semantics::new(db);
29 let file = sema.parse(position.file_id).syntax().clone();
30 let original_token = pick_best(file.token_at_offset(position.offset))?;
31 let token = sema.descend_into_macros(original_token.clone());
32 let parent = token.parent();
34 let nav_targets = match_ast! {
36 ast::NameRef(name_ref) => {
37 reference_definition(&sema, Either::Right(&name_ref)).to_vec()
40 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
41 let nav = def.try_to_nav(sema.db)?;
44 ast::SelfParam(self_param) => {
45 vec![self_to_nav_target(self_param, position.file_id)?]
47 ast::PathSegment(segment) => {
48 segment.self_token()?;
49 let path = segment.parent_path();
50 if path.qualifier().is_some() && !ast::PathExpr::can_cast(path.syntax().parent()?.kind()) {
53 let func = segment.syntax().ancestors().find_map(ast::Fn::cast)?;
54 let self_param = func.param_list()?.self_param()?;
55 vec![self_to_nav_target(self_param, position.file_id)?]
57 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, <) {
58 let def = name_class.referenced_or_defined(sema.db);
59 let nav = def.try_to_nav(sema.db)?;
62 reference_definition(&sema, Either::Left(<)).to_vec()
68 Some(RangeInfo::new(original_token.text_range(), nav_targets))
71 fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
72 return tokens.max_by_key(priority);
73 fn priority(n: &SyntaxToken) -> usize {
75 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] => 2,
76 kind if kind.is_trivia() => 0,
82 fn self_to_nav_target(self_param: ast::SelfParam, file_id: FileId) -> Option<NavigationTarget> {
83 let self_token = self_param.self_token()?;
84 Some(NavigationTarget {
86 full_range: self_param.syntax().text_range(),
87 focus_range: Some(self_token.text_range()),
88 name: self_token.text().clone(),
89 kind: self_token.kind(),
97 pub(crate) enum ReferenceResult {
98 Exact(NavigationTarget),
99 Approximate(Vec<NavigationTarget>),
102 impl ReferenceResult {
103 fn to_vec(self) -> Vec<NavigationTarget> {
105 ReferenceResult::Exact(target) => vec![target],
106 ReferenceResult::Approximate(vec) => vec,
111 pub(crate) fn reference_definition(
112 sema: &Semantics<RootDatabase>,
113 name_ref: Either<&ast::Lifetime, &ast::NameRef>,
114 ) -> ReferenceResult {
115 let name_kind = name_ref.either(
116 |lifetime| NameRefClass::classify_lifetime(sema, lifetime),
117 |name_ref| NameRefClass::classify(sema, name_ref),
119 if let Some(def) = name_kind {
120 let def = def.referenced(sema.db);
121 return match def.try_to_nav(sema.db) {
122 Some(nav) => ReferenceResult::Exact(nav),
123 None => ReferenceResult::Approximate(Vec::new()),
127 // Fallback index based approach:
128 let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text);
130 symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect();
131 ReferenceResult::Approximate(navs)
136 use ide_db::base_db::FileRange;
137 use syntax::{TextRange, TextSize};
141 fn check(ra_fixture: &str) {
142 let (analysis, position, mut annotations) = fixture::annotations(ra_fixture);
143 let (mut expected, data) = annotations.pop().unwrap();
144 match data.as_str() {
148 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
150 data => panic!("bad data: {}", data),
154 analysis.goto_definition(position).unwrap().expect("no definition found").info;
156 panic!("unresolved reference")
158 assert_eq!(navs.len(), 1);
160 let nav = navs.pop().unwrap();
161 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
165 fn goto_def_for_extern_crate() {
168 //- /main.rs crate:main deps:std
170 //- /std/lib.rs crate:std
178 fn goto_def_for_renamed_extern_crate() {
181 //- /main.rs crate:main deps:std
182 extern crate std as abc<|>;
183 //- /std/lib.rs crate:std
191 fn goto_def_in_items() {
202 fn goto_def_at_start_of_item() {
213 fn goto_definition_resolves_correct_name() {
232 fn goto_def_for_module_declaration() {
257 fn goto_def_for_macros() {
260 macro_rules! foo { () => { () } }
270 fn goto_def_for_macros_from_other_crates() {
281 macro_rules! foo { () => { () } }
288 fn goto_def_for_macros_in_use_tree() {
296 macro_rules! foo { () => { () } }
303 fn goto_def_for_macro_defined_fn_with_arg() {
307 macro_rules! define_fn {
308 ($name:ident) => (fn $name() {})
322 fn goto_def_for_macro_defined_fn_no_arg() {
326 macro_rules! define_fn {
341 fn goto_definition_works_for_macro_inside_pattern() {
345 macro_rules! foo {() => {0}}
358 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
362 macro_rules! foo {() => {0}}
374 fn goto_def_for_use_alias() {
377 //- /lib.rs crate:main deps:foo
380 //- /foo/lib.rs crate:foo
388 fn goto_def_for_use_alias_foo_macro() {
391 //- /lib.rs crate:main deps:foo
392 use foo::foo as bar<|>;
394 //- /foo/lib.rs crate:foo
396 macro_rules! foo { () => { () } }
403 fn goto_def_for_methods() {
408 fn frobnicate(&self) { }
420 fn goto_def_for_fields() {
435 fn goto_def_for_record_fields() {
453 fn goto_def_for_record_pat_fields() {
461 fn bar(foo: Foo) -> Foo {
462 let Foo { spam<|>: _, } = foo
469 fn goto_def_for_record_fields_macros() {
472 macro_rules! m { () => { 92 };}
473 struct Foo { spam: u32 }
477 Foo { spam<|>: m!() }
484 fn goto_for_tuple_fields() {
499 fn goto_def_for_ufcs_inherent_methods() {
508 Foo::frobnicate<|>();
515 fn goto_def_for_ufcs_trait_methods_through_traits() {
523 Foo::frobnicate<|>();
530 fn goto_def_for_ufcs_trait_methods_through_self() {
537 impl Trait for Foo {}
540 Foo::frobnicate<|>();
547 fn goto_definition_on_self() {
553 pub fn new() -> Self {
564 pub fn new() -> Self<|> {
576 pub fn new() -> Self<|> {
588 pub fn thing(a: &Self<|>) {
596 fn goto_definition_on_self_in_trait_impl() {
620 fn new() -> Self<|> {
629 fn goto_def_when_used_on_definition_name_itself() {
632 struct Foo<|> { value: u32 }
654 enum Foo<|> { Variant }
672 static INNER<|>: &str = "";
679 const INNER<|>: &str = "";
686 type Thing<|> = Option<()>;
707 fn goto_from_macro() {
711 ($($tt:tt)*) => { $($tt)* }
720 mod confuse_index { fn foo(); }
726 fn goto_through_format() {
730 macro_rules! format {
731 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
733 #[rustc_builtin_macro]
735 macro_rules! format_args {
736 ($fmt:expr) => ({ /* compiler built-in */ });
737 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
740 pub use crate::format_args;
741 fn foo() {} // for index confusion
746 format!("{}", fo<|>o())
753 fn goto_for_type_param() {
756 struct Foo<T: Clone> { t: <|>T }
763 fn goto_within_macro() {
767 ($($tt:tt)*) => ($($tt)*)
784 ($($tt:tt)*) => ($($tt)*)
800 fn goto_def_in_local_fn() {
815 fn goto_def_in_local_macro() {
819 macro_rules! foo { () => { () } }
828 fn goto_def_for_field_init_shorthand() {
831 struct Foo { x: i32 }
842 fn goto_def_for_enum_variant_field() {
850 Foo::Bar { x<|> } => x
858 fn goto_def_for_enum_variant_self_pattern_const() {
865 match self { Self::Bar<|> => {} }
873 fn goto_def_for_enum_variant_self_pattern_record() {
876 enum Foo { Bar { val: i32 } }
879 fn baz(self) -> i32 {
880 match self { Self::Bar<|> { val } => {} }
888 fn goto_def_for_enum_variant_self_expr_const() {
894 fn baz(self) { Self::Bar<|>; }
901 fn goto_def_for_enum_variant_self_expr_record() {
904 enum Foo { Bar { val: i32 } }
907 fn baz(self) { Self::Bar<|> {val: 4}; }
914 fn goto_def_for_type_alias_generic_parameter() {
917 type Alias<T> = T<|>;
924 fn goto_def_for_macro_container() {
928 foo::module<|>::mac!();
934 macro_rules! _mac { () => { () } }
935 pub use crate::_mac as mac;
942 fn goto_def_for_assoc_ty_in_path() {
950 fn f() -> impl Iterator<Item<|> = u8> {}
956 fn goto_def_for_assoc_ty_in_path_multiple() {
965 fn f() -> impl Iterator<A<|> = u8, B = ()> {}
976 fn f() -> impl Iterator<A = u8, B<|> = ()> {}
982 fn goto_def_for_assoc_ty_ufcs() {
990 fn g() -> <() as Iterator<Item<|> = ()>>::Item {}
996 fn goto_def_for_assoc_ty_ufcs_multiple() {
1005 fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {}
1016 fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {}
1022 fn goto_self_param_ty_specified() {
1028 fn bar(self: &Foo) {
1037 fn goto_self_param_on_decl() {
1051 fn goto_lifetime_param_on_decl() {
1054 fn foo<'foobar<|>>(_: &'foobar ()) {
1061 fn goto_lifetime_param_decl() {
1064 fn foo<'foobar>(_: &'foobar<|> ()) {
1071 fn goto_lifetime_param_decl_nested() {
1074 fn foo<'foobar>(_: &'foobar ()) {
1075 fn foo<'foobar>(_: &'foobar<|> ()) {}