aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/goto_defenition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/goto_defenition.rs')
-rw-r--r--crates/ra_ide_api/src/goto_defenition.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/goto_defenition.rs b/crates/ra_ide_api/src/goto_defenition.rs
new file mode 100644
index 000000000..fcd8d315e
--- /dev/null
+++ b/crates/ra_ide_api/src/goto_defenition.rs
@@ -0,0 +1,139 @@
1use ra_db::{FileId, Cancelable, SyntaxDatabase};
2use ra_syntax::{
3 TextRange, AstNode, ast, SyntaxKind::{NAME, MODULE},
4 algo::find_node_at_offset,
5};
6
7use crate::{FilePosition, NavigationTarget, db::RootDatabase};
8
9pub(crate) fn goto_defenition(
10 db: &RootDatabase,
11 position: FilePosition,
12) -> Cancelable<Option<Vec<NavigationTarget>>> {
13 let file = db.source_file(position.file_id);
14 let syntax = file.syntax();
15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
16 return Ok(Some(reference_defenition(db, position.file_id, name_ref)?));
17 }
18 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
19 return name_defenition(db, position.file_id, name);
20 }
21 Ok(None)
22}
23
24pub(crate) fn reference_defenition(
25 db: &RootDatabase,
26 file_id: FileId,
27 name_ref: &ast::NameRef,
28) -> Cancelable<Vec<NavigationTarget>> {
29 if let Some(fn_descr) =
30 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
31 {
32 let scope = fn_descr.scopes(db)?;
33 // First try to resolve the symbol locally
34 if let Some(entry) = scope.resolve_local_name(name_ref) {
35 let nav = NavigationTarget {
36 file_id,
37 name: entry.name().to_string().into(),
38 range: entry.ptr().range(),
39 kind: NAME,
40 ptr: None,
41 };
42 return Ok(vec![nav]);
43 };
44 }
45 // If that fails try the index based approach.
46 let navs = db
47 .index_resolve(name_ref)?
48 .into_iter()
49 .map(NavigationTarget::from_symbol)
50 .collect();
51 Ok(navs)
52}
53
54fn name_defenition(
55 db: &RootDatabase,
56 file_id: FileId,
57 name: &ast::Name,
58) -> Cancelable<Option<Vec<NavigationTarget>>> {
59 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
60 if module.has_semi() {
61 if let Some(child_module) =
62 hir::source_binder::module_from_declaration(db, file_id, module)?
63 {
64 let (file_id, _) = child_module.defenition_source(db)?;
65 let name = match child_module.name(db)? {
66 Some(name) => name.to_string().into(),
67 None => "".into(),
68 };
69 let nav = NavigationTarget {
70 file_id,
71 name,
72 range: TextRange::offset_len(0.into(), 0.into()),
73 kind: MODULE,
74 ptr: None,
75 };
76 return Ok(Some(vec![nav]));
77 }
78 }
79 }
80 Ok(None)
81}
82
83#[cfg(test)]
84mod tests {
85 use test_utils::assert_eq_dbg;
86 use crate::mock_analysis::analysis_and_position;
87
88 #[test]
89 fn goto_defenition_works_in_items() {
90 let (analysis, pos) = analysis_and_position(
91 "
92 //- /lib.rs
93 struct Foo;
94 enum E { X(Foo<|>) }
95 ",
96 );
97
98 let symbols = analysis.goto_defenition(pos).unwrap().unwrap();
99 assert_eq_dbg(
100 r#"[NavigationTarget { file_id: FileId(1), name: "Foo",
101 kind: STRUCT_DEF, range: [0; 11),
102 ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }]"#,
103 &symbols,
104 );
105 }
106
107 #[test]
108 fn goto_defenition_works_for_module_declaration() {
109 let (analysis, pos) = analysis_and_position(
110 "
111 //- /lib.rs
112 mod <|>foo;
113 //- /foo.rs
114 // empty
115 ",
116 );
117
118 let symbols = analysis.goto_defenition(pos).unwrap().unwrap();
119 assert_eq_dbg(
120 r#"[NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }]"#,
121 &symbols,
122 );
123
124 let (analysis, pos) = analysis_and_position(
125 "
126 //- /lib.rs
127 mod <|>foo;
128 //- /foo/mod.rs
129 // empty
130 ",
131 );
132
133 let symbols = analysis.goto_defenition(pos).unwrap().unwrap();
134 assert_eq_dbg(
135 r#"[NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }]"#,
136 &symbols,
137 );
138 }
139}