aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/goto_type_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/goto_type_definition.rs')
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs68
1 files changed, 68 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}