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.rs66
-rw-r--r--crates/ra_ide_api/src/lib.rs8
2 files changed, 74 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..de2b9d3c3
--- /dev/null
+++ b/crates/ra_ide_api/src/goto_type_definition.rs
@@ -0,0 +1,66 @@
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 let (adt_def, _) = ty.as_adt()?;
34 let nav = NavigationTarget::from_adt_def(db, adt_def);
35
36 Some(RangeInfo::new(node.range(), vec![nav]))
37}
38
39#[cfg(test)]
40mod tests {
41 use crate::mock_analysis::analysis_and_position;
42
43 fn check_goto(fixture: &str, expected: &str) {
44 let (analysis, pos) = analysis_and_position(fixture);
45
46 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info;
47 assert_eq!(navs.len(), 1);
48 let nav = navs.pop().unwrap();
49 nav.assert_match(expected);
50 }
51
52 #[test]
53 fn goto_type_definition_works_simple() {
54 check_goto(
55 "
56 //- /lib.rs
57 struct Foo;
58 fn foo() {
59 let f: Foo;
60 f<|>
61 }
62 ",
63 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
64 );
65 }
66}
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,