diff options
Diffstat (limited to 'crates/ra_ide_api/src/goto_definition.rs')
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 87 |
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 @@ | |||
1 | use ra_db::{FileId, Cancelable, SyntaxDatabase}; | 1 | use ra_db::{FileId, Cancelable, SyntaxDatabase}; |
2 | use ra_syntax::{ | 2 | use 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 | ||
7 | use crate::{FilePosition, NavigationTarget, db::RootDatabase}; | 7 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; |
8 | 8 | ||
9 | pub(crate) fn goto_definition( | 9 | pub(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)] |
102 | mod tests { | 87 | mod 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 | } |