aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/goto_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/goto_definition.rs')
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs87
1 files changed, 28 insertions, 59 deletions
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index eaddd5083..8d2ff561a 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -1,22 +1,24 @@
1use ra_db::{FileId, Cancelable, SyntaxDatabase}; 1use ra_db::{FileId, Cancelable, SyntaxDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 TextRange, AstNode, ast, SyntaxKind::{NAME, MODULE}, 3 AstNode, ast,
4 algo::find_node_at_offset, 4 algo::find_node_at_offset,
5}; 5};
6 6
7use crate::{FilePosition, NavigationTarget, db::RootDatabase}; 7use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
8 8
9pub(crate) fn goto_definition( 9pub(crate) fn goto_definition(
10 db: &RootDatabase, 10 db: &RootDatabase,
11 position: FilePosition, 11 position: FilePosition,
12) -> Cancelable<Option<Vec<NavigationTarget>>> { 12) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
13 let file = db.source_file(position.file_id); 13 let file = db.source_file(position.file_id);
14 let syntax = file.syntax(); 14 let syntax = file.syntax();
15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
16 return Ok(Some(reference_definition(db, position.file_id, name_ref)?)); 16 let navs = reference_definition(db, position.file_id, name_ref)?;
17 return Ok(Some(RangeInfo::new(name_ref.syntax().range(), navs)));
17 } 18 }
18 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 19 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
19 return name_definition(db, position.file_id, name); 20 let navs = ctry!(name_definition(db, position.file_id, name)?);
21 return Ok(Some(RangeInfo::new(name.syntax().range(), navs)));
20 } 22 }
21 Ok(None) 23 Ok(None)
22} 24}
@@ -32,13 +34,7 @@ pub(crate) fn reference_definition(
32 let scope = fn_descr.scopes(db)?; 34 let scope = fn_descr.scopes(db)?;
33 // First try to resolve the symbol locally 35 // First try to resolve the symbol locally
34 if let Some(entry) = scope.resolve_local_name(name_ref) { 36 if let Some(entry) = scope.resolve_local_name(name_ref) {
35 let nav = NavigationTarget { 37 let nav = NavigationTarget::from_scope_entry(file_id, &entry);
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]); 38 return Ok(vec![nav]);
43 }; 39 };
44 } 40 }
@@ -79,18 +75,7 @@ fn name_definition(
79 if let Some(child_module) = 75 if let Some(child_module) =
80 hir::source_binder::module_from_declaration(db, file_id, module)? 76 hir::source_binder::module_from_declaration(db, file_id, module)?
81 { 77 {
82 let (file_id, _) = child_module.definition_source(db)?; 78 let nav = NavigationTarget::from_module(db, child_module)?;
83 let name = match child_module.name(db)? {
84 Some(name) => name.to_string().into(),
85 None => "".into(),
86 };
87 let nav = NavigationTarget {
88 file_id,
89 name,
90 range: TextRange::offset_len(0.into(), 0.into()),
91 kind: MODULE,
92 ptr: None,
93 };
94 return Ok(Some(vec![nav])); 79 return Ok(Some(vec![nav]));
95 } 80 }
96 } 81 }
@@ -100,31 +85,32 @@ fn name_definition(
100 85
101#[cfg(test)] 86#[cfg(test)]
102mod tests { 87mod tests {
103 use test_utils::assert_eq_dbg;
104 use crate::mock_analysis::analysis_and_position; 88 use crate::mock_analysis::analysis_and_position;
105 89
90 fn check_goto(fixuture: &str, expected: &str) {
91 let (analysis, pos) = analysis_and_position(fixuture);
92
93 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
94 assert_eq!(navs.len(), 1);
95 let nav = navs.pop().unwrap();
96 nav.assert_match(expected);
97 }
98
106 #[test] 99 #[test]
107 fn goto_definition_works_in_items() { 100 fn goto_definition_works_in_items() {
108 let (analysis, pos) = analysis_and_position( 101 check_goto(
109 " 102 "
110 //- /lib.rs 103 //- /lib.rs
111 struct Foo; 104 struct Foo;
112 enum E { X(Foo<|>) } 105 enum E { X(Foo<|>) }
113 ", 106 ",
114 ); 107 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
115
116 let symbols = analysis.goto_definition(pos).unwrap().unwrap();
117 assert_eq_dbg(
118 r#"[NavigationTarget { file_id: FileId(1), name: "Foo",
119 kind: STRUCT_DEF, range: [0; 11),
120 ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }]"#,
121 &symbols,
122 ); 108 );
123 } 109 }
124 110
125 #[test] 111 #[test]
126 fn goto_definition_resolves_correct_name() { 112 fn goto_definition_resolves_correct_name() {
127 let (analysis, pos) = analysis_and_position( 113 check_goto(
128 " 114 "
129 //- /lib.rs 115 //- /lib.rs
130 use a::Foo; 116 use a::Foo;
@@ -136,47 +122,30 @@ mod tests {
136 //- /b.rs 122 //- /b.rs
137 struct Foo; 123 struct Foo;
138 ", 124 ",
139 ); 125 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)",
140
141 let symbols = analysis.goto_definition(pos).unwrap().unwrap();
142 assert_eq_dbg(
143 r#"[NavigationTarget { file_id: FileId(2), name: "Foo",
144 kind: STRUCT_DEF, range: [0; 11),
145 ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }]"#,
146 &symbols,
147 ); 126 );
148 } 127 }
149 128
150 #[test] 129 #[test]
151 fn goto_definition_works_for_module_declaration() { 130 fn goto_definition_works_for_module_declaration() {
152 let (analysis, pos) = analysis_and_position( 131 check_goto(
153 " 132 "
154 //- /lib.rs 133 //- /lib.rs
155 mod <|>foo; 134 mod <|>foo;
156 //- /foo.rs 135 //- /foo.rs
157 // empty 136 // empty
158 ", 137 ",
159 ); 138 "foo SOURCE_FILE FileId(2) [0; 10)",
160
161 let symbols = analysis.goto_definition(pos).unwrap().unwrap();
162 assert_eq_dbg(
163 r#"[NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }]"#,
164 &symbols,
165 ); 139 );
166 140
167 let (analysis, pos) = analysis_and_position( 141 check_goto(
168 " 142 "
169 //- /lib.rs 143 //- /lib.rs
170 mod <|>foo; 144 mod <|>foo;
171 //- /foo/mod.rs 145 //- /foo/mod.rs
172 // empty 146 // empty
173 ", 147 ",
174 ); 148 "foo SOURCE_FILE FileId(2) [0; 10)",
175
176 let symbols = analysis.goto_definition(pos).unwrap().unwrap();
177 assert_eq_dbg(
178 r#"[NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }]"#,
179 &symbols,
180 ); 149 );
181 } 150 }
182} 151}