3 defs::{Definition, NameClass, NameRefClass},
6 use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T};
8 use crate::{FilePosition, NavigationTarget, RangeInfo};
10 // Feature: Go to Declaration
12 // Navigates to the declaration of an identifier.
14 // This is currently the same as `Go to Definition` with the exception of outline modules where it
15 // will navigate to the `mod name;` item declaration.
16 pub(crate) fn goto_declaration(
18 position: FilePosition,
19 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
20 let sema = Semantics::new(db);
21 let file = sema.parse(position.file_id).syntax().clone();
22 let original_token = file
23 .token_at_offset(position.offset)
24 .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
25 let range = original_token.text_range();
26 let info: Vec<NavigationTarget> = sema
27 .descend_into_macros(original_token)
30 let parent = token.parent()?;
31 let def = match_ast! {
33 ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
34 NameRefClass::Definition(it) => Some(it),
37 ast::Name(name) => match NameClass::classify(&sema, &name)? {
38 NameClass::Definition(it) => Some(it),
45 Definition::Module(module) => {
46 Some(NavigationTarget::from_module_to_decl(db, module))
53 Some(RangeInfo::new(range, info))
58 use ide_db::base_db::FileRange;
59 use itertools::Itertools;
63 fn check(ra_fixture: &str) {
64 let (analysis, position, expected) = fixture::annotations(ra_fixture);
66 .goto_declaration(position)
68 .expect("no declaration or definition found")
71 panic!("unresolved reference")
74 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
77 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
80 let expected = expected
82 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
85 assert_eq!(expected, navs);
89 fn goto_decl_module_outline() {
102 fn goto_decl_module_inline() {