aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs68
-rw-r--r--crates/ra_ide_api/src/lib.rs8
2 files changed, 76 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs
new file mode 100644
index 000000000..b6a3c1c3a
--- /dev/null
+++ b/crates/ra_ide_api/src/goto_type_definition.rs
@@ -0,0 +1,68 @@
1use ra_db::SourceDatabase;
2use ra_syntax::{
3 AstNode, ast,
4 algo::find_token_at_offset
5};
6
7use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
8
9pub(crate) fn goto_type_definition(
10 db: &RootDatabase,
11 position: FilePosition,
12) -> Option<RangeInfo<Vec<NavigationTarget>>> {
13 let file = db.parse(position.file_id);
14
15 let node = find_token_at_offset(file.syntax(), position.offset).find_map(|token| {
16 token
17 .parent()
18 .ancestors()
19 .find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
20 })?;
21
22 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, node, None);
23
24 let ty: hir::Ty = if let Some(ty) = ast::Expr::cast(node).and_then(|e| analyzer.type_of(db, e))
25 {
26 ty
27 } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, p)) {
28 ty
29 } else {
30 return None;
31 };
32
33 if let Some((adt_def, _)) = ty.as_adt() {
34 let nav = NavigationTarget::from_adt_def(db, adt_def);
35 return Some(RangeInfo::new(node.range(), vec![nav]));
36 };
37
38 None
39}
40
41#[cfg(test)]
42mod tests {
43 use crate::mock_analysis::analysis_and_position;
44
45 fn check_goto(fixture: &str, expected: &str) {
46 let (analysis, pos) = analysis_and_position(fixture);
47
48 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info;
49 assert_eq!(navs.len(), 1);
50 let nav = navs.pop().unwrap();
51 nav.assert_match(expected);
52 }
53
54 #[test]
55 fn goto_type_definition_works_simple() {
56 check_goto(
57 "
58 //- /lib.rs
59 struct Foo;
60 fn foo() {
61 let f: Foo;
62 f<|>
63 }
64 ",
65 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
66 );
67 }
68}
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index d25795adc..d4be8bd6c 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -19,6 +19,7 @@ mod status;
19mod completion; 19mod completion;
20mod runnables; 20mod runnables;
21mod goto_definition; 21mod goto_definition;
22mod goto_type_definition;
22mod extend_selection; 23mod extend_selection;
23mod hover; 24mod hover;
24mod call_info; 25mod call_info;
@@ -416,6 +417,13 @@ impl Analysis {
416 self.with_db(|db| impls::goto_implementation(db, position)) 417 self.with_db(|db| impls::goto_implementation(db, position))
417 } 418 }
418 419
420 pub fn goto_type_definition(
421 &self,
422 position: FilePosition,
423 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
424 self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
425 }
426
419 /// Finds all usages of the reference at point. 427 /// Finds all usages of the reference at point.
420 pub fn find_all_refs( 428 pub fn find_all_refs(
421 &self, 429 &self,