diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 120 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 77 | ||||
-rw-r--r-- | crates/ra_ide_api/src/status.rs | 4 |
3 files changed, 154 insertions, 47 deletions
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 5cb67fb95..1bf81e7d5 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs | |||
@@ -29,6 +29,21 @@ pub struct NavigationTarget { | |||
29 | docs: Option<String>, | 29 | docs: Option<String>, |
30 | } | 30 | } |
31 | 31 | ||
32 | fn find_range_from_node( | ||
33 | db: &RootDatabase, | ||
34 | src: hir::HirFileId, | ||
35 | node: &SyntaxNode, | ||
36 | ) -> (FileId, TextRange) { | ||
37 | let text_range = node.text_range(); | ||
38 | let (file_id, text_range) = src | ||
39 | .expansion_info(db) | ||
40 | .and_then(|expansion_info| expansion_info.find_range(text_range)) | ||
41 | .unwrap_or((src, text_range)); | ||
42 | |||
43 | // FIXME: handle recursive macro generated macro | ||
44 | (file_id.original_file(db), text_range) | ||
45 | } | ||
46 | |||
32 | impl NavigationTarget { | 47 | impl NavigationTarget { |
33 | /// When `focus_range` is specified, returns it. otherwise | 48 | /// When `focus_range` is specified, returns it. otherwise |
34 | /// returns `full_range` | 49 | /// returns `full_range` |
@@ -72,8 +87,12 @@ impl NavigationTarget { | |||
72 | self.focus_range | 87 | self.focus_range |
73 | } | 88 | } |
74 | 89 | ||
75 | pub(crate) fn from_bind_pat(file_id: FileId, pat: &ast::BindPat) -> NavigationTarget { | 90 | pub(crate) fn from_bind_pat( |
76 | NavigationTarget::from_named(file_id, pat, None, None) | 91 | db: &RootDatabase, |
92 | file_id: FileId, | ||
93 | pat: &ast::BindPat, | ||
94 | ) -> NavigationTarget { | ||
95 | NavigationTarget::from_named(db, file_id.into(), pat, None, None) | ||
77 | } | 96 | } |
78 | 97 | ||
79 | pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { | 98 | pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { |
@@ -96,7 +115,7 @@ impl NavigationTarget { | |||
96 | ) -> NavigationTarget { | 115 | ) -> NavigationTarget { |
97 | let parse = db.parse(file_id); | 116 | let parse = db.parse(file_id); |
98 | let pat = pat.to_node(parse.tree().syntax()); | 117 | let pat = pat.to_node(parse.tree().syntax()); |
99 | NavigationTarget::from_bind_pat(file_id, &pat) | 118 | NavigationTarget::from_bind_pat(db, file_id, &pat) |
100 | } | 119 | } |
101 | 120 | ||
102 | pub(crate) fn from_self_param( | 121 | pub(crate) fn from_self_param( |
@@ -119,31 +138,46 @@ impl NavigationTarget { | |||
119 | 138 | ||
120 | pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 139 | pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
121 | let src = module.definition_source(db); | 140 | let src = module.definition_source(db); |
122 | let file_id = src.file_id.original_file(db); | ||
123 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 141 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
124 | match src.ast { | 142 | match src.ast { |
125 | ModuleSource::SourceFile(node) => { | 143 | ModuleSource::SourceFile(node) => { |
126 | NavigationTarget::from_syntax(file_id, name, None, node.syntax(), None, None) | 144 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); |
145 | |||
146 | NavigationTarget::from_syntax( | ||
147 | file_id, | ||
148 | name, | ||
149 | None, | ||
150 | text_range, | ||
151 | node.syntax(), | ||
152 | None, | ||
153 | None, | ||
154 | ) | ||
155 | } | ||
156 | ModuleSource::Module(node) => { | ||
157 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | ||
158 | |||
159 | NavigationTarget::from_syntax( | ||
160 | file_id, | ||
161 | name, | ||
162 | None, | ||
163 | text_range, | ||
164 | node.syntax(), | ||
165 | node.doc_comment_text(), | ||
166 | node.short_label(), | ||
167 | ) | ||
127 | } | 168 | } |
128 | ModuleSource::Module(node) => NavigationTarget::from_syntax( | ||
129 | file_id, | ||
130 | name, | ||
131 | None, | ||
132 | node.syntax(), | ||
133 | node.doc_comment_text(), | ||
134 | node.short_label(), | ||
135 | ), | ||
136 | } | 169 | } |
137 | } | 170 | } |
138 | 171 | ||
139 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 172 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
140 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 173 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
141 | if let Some(src) = module.declaration_source(db) { | 174 | if let Some(src) = module.declaration_source(db) { |
142 | let file_id = src.file_id.original_file(db); | 175 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); |
143 | return NavigationTarget::from_syntax( | 176 | return NavigationTarget::from_syntax( |
144 | file_id, | 177 | file_id, |
145 | name, | 178 | name, |
146 | None, | 179 | None, |
180 | text_range, | ||
147 | src.ast.syntax(), | 181 | src.ast.syntax(), |
148 | src.ast.doc_comment_text(), | 182 | src.ast.doc_comment_text(), |
149 | src.ast.short_label(), | 183 | src.ast.short_label(), |
@@ -154,13 +188,25 @@ impl NavigationTarget { | |||
154 | 188 | ||
155 | pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { | 189 | pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { |
156 | let src = field.source(db); | 190 | let src = field.source(db); |
157 | let file_id = src.file_id.original_file(db); | ||
158 | match src.ast { | 191 | match src.ast { |
159 | FieldSource::Named(it) => { | 192 | FieldSource::Named(it) => NavigationTarget::from_named( |
160 | NavigationTarget::from_named(file_id, &it, it.doc_comment_text(), it.short_label()) | 193 | db, |
161 | } | 194 | src.file_id, |
195 | &it, | ||
196 | it.doc_comment_text(), | ||
197 | it.short_label(), | ||
198 | ), | ||
162 | FieldSource::Pos(it) => { | 199 | FieldSource::Pos(it) => { |
163 | NavigationTarget::from_syntax(file_id, "".into(), None, it.syntax(), None, None) | 200 | let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); |
201 | NavigationTarget::from_syntax( | ||
202 | file_id, | ||
203 | "".into(), | ||
204 | None, | ||
205 | text_range, | ||
206 | it.syntax(), | ||
207 | None, | ||
208 | None, | ||
209 | ) | ||
164 | } | 210 | } |
165 | } | 211 | } |
166 | } | 212 | } |
@@ -172,7 +218,8 @@ impl NavigationTarget { | |||
172 | { | 218 | { |
173 | let src = def.source(db); | 219 | let src = def.source(db); |
174 | NavigationTarget::from_named( | 220 | NavigationTarget::from_named( |
175 | src.file_id.original_file(db), | 221 | db, |
222 | src.file_id, | ||
176 | &src.ast, | 223 | &src.ast, |
177 | src.ast.doc_comment_text(), | 224 | src.ast.doc_comment_text(), |
178 | src.ast.short_label(), | 225 | src.ast.short_label(), |
@@ -212,10 +259,13 @@ impl NavigationTarget { | |||
212 | impl_block: hir::ImplBlock, | 259 | impl_block: hir::ImplBlock, |
213 | ) -> NavigationTarget { | 260 | ) -> NavigationTarget { |
214 | let src = impl_block.source(db); | 261 | let src = impl_block.source(db); |
262 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); | ||
263 | |||
215 | NavigationTarget::from_syntax( | 264 | NavigationTarget::from_syntax( |
216 | src.file_id.original_file(db), | 265 | file_id, |
217 | "impl".into(), | 266 | "impl".into(), |
218 | None, | 267 | None, |
268 | text_range, | ||
219 | src.ast.syntax(), | 269 | src.ast.syntax(), |
220 | None, | 270 | None, |
221 | None, | 271 | None, |
@@ -236,12 +286,7 @@ impl NavigationTarget { | |||
236 | pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { | 286 | pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { |
237 | let src = macro_call.source(db); | 287 | let src = macro_call.source(db); |
238 | log::debug!("nav target {:#?}", src.ast.syntax()); | 288 | log::debug!("nav target {:#?}", src.ast.syntax()); |
239 | NavigationTarget::from_named( | 289 | NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) |
240 | src.file_id.original_file(db), | ||
241 | &src.ast, | ||
242 | src.ast.doc_comment_text(), | ||
243 | None, | ||
244 | ) | ||
245 | } | 290 | } |
246 | 291 | ||
247 | #[cfg(test)] | 292 | #[cfg(test)] |
@@ -270,21 +315,33 @@ impl NavigationTarget { | |||
270 | 315 | ||
271 | /// Allows `NavigationTarget` to be created from a `NameOwner` | 316 | /// Allows `NavigationTarget` to be created from a `NameOwner` |
272 | pub(crate) fn from_named( | 317 | pub(crate) fn from_named( |
273 | file_id: FileId, | 318 | db: &RootDatabase, |
319 | file_id: hir::HirFileId, | ||
274 | node: &impl ast::NameOwner, | 320 | node: &impl ast::NameOwner, |
275 | docs: Option<String>, | 321 | docs: Option<String>, |
276 | description: Option<String>, | 322 | description: Option<String>, |
277 | ) -> NavigationTarget { | 323 | ) -> NavigationTarget { |
278 | //FIXME: use `_` instead of empty string | 324 | //FIXME: use `_` instead of empty string |
279 | let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); | 325 | let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); |
280 | let focus_range = node.name().map(|it| it.syntax().text_range()); | 326 | let focus_range = node.name().map(|it| find_range_from_node(db, file_id, it.syntax()).1); |
281 | NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax(), docs, description) | 327 | let (file_id, full_range) = find_range_from_node(db, file_id, node.syntax()); |
328 | |||
329 | NavigationTarget::from_syntax( | ||
330 | file_id, | ||
331 | name, | ||
332 | focus_range, | ||
333 | full_range, | ||
334 | node.syntax(), | ||
335 | docs, | ||
336 | description, | ||
337 | ) | ||
282 | } | 338 | } |
283 | 339 | ||
284 | fn from_syntax( | 340 | fn from_syntax( |
285 | file_id: FileId, | 341 | file_id: FileId, |
286 | name: SmolStr, | 342 | name: SmolStr, |
287 | focus_range: Option<TextRange>, | 343 | focus_range: Option<TextRange>, |
344 | full_range: TextRange, | ||
288 | node: &SyntaxNode, | 345 | node: &SyntaxNode, |
289 | docs: Option<String>, | 346 | docs: Option<String>, |
290 | description: Option<String>, | 347 | description: Option<String>, |
@@ -293,9 +350,8 @@ impl NavigationTarget { | |||
293 | file_id, | 350 | file_id, |
294 | name, | 351 | name, |
295 | kind: node.kind(), | 352 | kind: node.kind(), |
296 | full_range: node.text_range(), | 353 | full_range, |
297 | focus_range, | 354 | focus_range, |
298 | // ptr: Some(LocalSyntaxPtr::new(node)), | ||
299 | container_name: None, | 355 | container_name: None, |
300 | description, | 356 | description, |
301 | docs, | 357 | docs, |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index c1ce54bea..afa59cbe3 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -101,19 +101,20 @@ pub(crate) fn name_definition( | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | if let Some(nav) = named_target(file_id, &parent) { | 104 | if let Some(nav) = named_target(db, file_id, &parent) { |
105 | return Some(vec![nav]); | 105 | return Some(vec![nav]); |
106 | } | 106 | } |
107 | 107 | ||
108 | None | 108 | None |
109 | } | 109 | } |
110 | 110 | ||
111 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { | 111 | fn named_target(db: &RootDatabase, file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { |
112 | match_ast! { | 112 | match_ast! { |
113 | match node { | 113 | match node { |
114 | ast::StructDef(it) => { | 114 | ast::StructDef(it) => { |
115 | Some(NavigationTarget::from_named( | 115 | Some(NavigationTarget::from_named( |
116 | file_id, | 116 | db, |
117 | file_id.into(), | ||
117 | &it, | 118 | &it, |
118 | it.doc_comment_text(), | 119 | it.doc_comment_text(), |
119 | it.short_label(), | 120 | it.short_label(), |
@@ -121,7 +122,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
121 | }, | 122 | }, |
122 | ast::EnumDef(it) => { | 123 | ast::EnumDef(it) => { |
123 | Some(NavigationTarget::from_named( | 124 | Some(NavigationTarget::from_named( |
124 | file_id, | 125 | db, |
126 | file_id.into(), | ||
125 | &it, | 127 | &it, |
126 | it.doc_comment_text(), | 128 | it.doc_comment_text(), |
127 | it.short_label(), | 129 | it.short_label(), |
@@ -129,7 +131,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
129 | }, | 131 | }, |
130 | ast::EnumVariant(it) => { | 132 | ast::EnumVariant(it) => { |
131 | Some(NavigationTarget::from_named( | 133 | Some(NavigationTarget::from_named( |
132 | file_id, | 134 | db, |
135 | file_id.into(), | ||
133 | &it, | 136 | &it, |
134 | it.doc_comment_text(), | 137 | it.doc_comment_text(), |
135 | it.short_label(), | 138 | it.short_label(), |
@@ -137,7 +140,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
137 | }, | 140 | }, |
138 | ast::FnDef(it) => { | 141 | ast::FnDef(it) => { |
139 | Some(NavigationTarget::from_named( | 142 | Some(NavigationTarget::from_named( |
140 | file_id, | 143 | db, |
144 | file_id.into(), | ||
141 | &it, | 145 | &it, |
142 | it.doc_comment_text(), | 146 | it.doc_comment_text(), |
143 | it.short_label(), | 147 | it.short_label(), |
@@ -145,7 +149,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
145 | }, | 149 | }, |
146 | ast::TypeAliasDef(it) => { | 150 | ast::TypeAliasDef(it) => { |
147 | Some(NavigationTarget::from_named( | 151 | Some(NavigationTarget::from_named( |
148 | file_id, | 152 | db, |
153 | file_id.into(), | ||
149 | &it, | 154 | &it, |
150 | it.doc_comment_text(), | 155 | it.doc_comment_text(), |
151 | it.short_label(), | 156 | it.short_label(), |
@@ -153,7 +158,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
153 | }, | 158 | }, |
154 | ast::ConstDef(it) => { | 159 | ast::ConstDef(it) => { |
155 | Some(NavigationTarget::from_named( | 160 | Some(NavigationTarget::from_named( |
156 | file_id, | 161 | db, |
162 | file_id.into(), | ||
157 | &it, | 163 | &it, |
158 | it.doc_comment_text(), | 164 | it.doc_comment_text(), |
159 | it.short_label(), | 165 | it.short_label(), |
@@ -161,7 +167,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
161 | }, | 167 | }, |
162 | ast::StaticDef(it) => { | 168 | ast::StaticDef(it) => { |
163 | Some(NavigationTarget::from_named( | 169 | Some(NavigationTarget::from_named( |
164 | file_id, | 170 | db, |
171 | file_id.into(), | ||
165 | &it, | 172 | &it, |
166 | it.doc_comment_text(), | 173 | it.doc_comment_text(), |
167 | it.short_label(), | 174 | it.short_label(), |
@@ -169,7 +176,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
169 | }, | 176 | }, |
170 | ast::TraitDef(it) => { | 177 | ast::TraitDef(it) => { |
171 | Some(NavigationTarget::from_named( | 178 | Some(NavigationTarget::from_named( |
172 | file_id, | 179 | db, |
180 | file_id.into(), | ||
173 | &it, | 181 | &it, |
174 | it.doc_comment_text(), | 182 | it.doc_comment_text(), |
175 | it.short_label(), | 183 | it.short_label(), |
@@ -177,7 +185,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
177 | }, | 185 | }, |
178 | ast::RecordFieldDef(it) => { | 186 | ast::RecordFieldDef(it) => { |
179 | Some(NavigationTarget::from_named( | 187 | Some(NavigationTarget::from_named( |
180 | file_id, | 188 | db, |
189 | file_id.into(), | ||
181 | &it, | 190 | &it, |
182 | it.doc_comment_text(), | 191 | it.doc_comment_text(), |
183 | it.short_label(), | 192 | it.short_label(), |
@@ -185,7 +194,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
185 | }, | 194 | }, |
186 | ast::Module(it) => { | 195 | ast::Module(it) => { |
187 | Some(NavigationTarget::from_named( | 196 | Some(NavigationTarget::from_named( |
188 | file_id, | 197 | db, |
198 | file_id.into(), | ||
189 | &it, | 199 | &it, |
190 | it.doc_comment_text(), | 200 | it.doc_comment_text(), |
191 | it.short_label(), | 201 | it.short_label(), |
@@ -193,7 +203,8 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
193 | }, | 203 | }, |
194 | ast::MacroCall(it) => { | 204 | ast::MacroCall(it) => { |
195 | Some(NavigationTarget::from_named( | 205 | Some(NavigationTarget::from_named( |
196 | file_id, | 206 | db, |
207 | file_id.into(), | ||
197 | &it, | 208 | &it, |
198 | it.doc_comment_text(), | 209 | it.doc_comment_text(), |
199 | None, | 210 | None, |
@@ -335,6 +346,46 @@ mod tests { | |||
335 | } | 346 | } |
336 | 347 | ||
337 | #[test] | 348 | #[test] |
349 | fn goto_definition_works_for_macro_defined_fn_with_arg() { | ||
350 | check_goto( | ||
351 | " | ||
352 | //- /lib.rs | ||
353 | macro_rules! define_fn { | ||
354 | ($name:ident) => (fn $name() {}) | ||
355 | } | ||
356 | |||
357 | define_fn!( | ||
358 | foo | ||
359 | ) | ||
360 | |||
361 | fn bar() { | ||
362 | <|>foo(); | ||
363 | } | ||
364 | ", | ||
365 | "foo FN_DEF FileId(1) [80; 83) [80; 83)", | ||
366 | ); | ||
367 | } | ||
368 | |||
369 | #[test] | ||
370 | fn goto_definition_works_for_macro_defined_fn_no_arg() { | ||
371 | check_goto( | ||
372 | " | ||
373 | //- /lib.rs | ||
374 | macro_rules! define_fn { | ||
375 | () => (fn foo() {}) | ||
376 | } | ||
377 | |||
378 | define_fn!(); | ||
379 | |||
380 | fn bar() { | ||
381 | <|>foo(); | ||
382 | } | ||
383 | ", | ||
384 | "foo FN_DEF FileId(1) [39; 42) [39; 42)", | ||
385 | ); | ||
386 | } | ||
387 | |||
388 | #[test] | ||
338 | fn goto_definition_works_for_methods() { | 389 | fn goto_definition_works_for_methods() { |
339 | covers!(goto_definition_works_for_methods); | 390 | covers!(goto_definition_works_for_methods); |
340 | check_goto( | 391 | check_goto( |
diff --git a/crates/ra_ide_api/src/status.rs b/crates/ra_ide_api/src/status.rs index f91f16c8e..1bb27eb85 100644 --- a/crates/ra_ide_api/src/status.rs +++ b/crates/ra_ide_api/src/status.rs | |||
@@ -94,10 +94,10 @@ impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStat | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | impl FromIterator<TableEntry<MacroFile, Option<Parse<SyntaxNode>>>> for SyntaxTreeStats { | 97 | impl<M> FromIterator<TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>> for SyntaxTreeStats { |
98 | fn from_iter<T>(iter: T) -> SyntaxTreeStats | 98 | fn from_iter<T>(iter: T) -> SyntaxTreeStats |
99 | where | 99 | where |
100 | T: IntoIterator<Item = TableEntry<MacroFile, Option<Parse<SyntaxNode>>>>, | 100 | T: IntoIterator<Item = TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>>, |
101 | { | 101 | { |
102 | let mut res = SyntaxTreeStats::default(); | 102 | let mut res = SyntaxTreeStats::default(); |
103 | for entry in iter { | 103 | for entry in iter { |