diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-07 16:10:36 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-07 16:10:36 +0000 |
commit | 711b82a7019bfc7be95b05afe022e6c9a6c08e64 (patch) | |
tree | f51670df82dfc0df68e6fda77d40878297af2ad6 | |
parent | a41d8e140ca65cb87bf6e69a35c3e86410aba374 (diff) | |
parent | 4a0bb3d7c53c2a914649087bf206d52ed5768576 (diff) |
Merge #944
944: Add support for goto definition and hover on Self r=matklad a=vipentti
This fixes #943
Co-authored-by: Ville Penttinen <[email protected]>
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 49 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 96 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 58 | ||||
-rw-r--r-- | crates/ra_ide_api/src/navigation_target.rs | 13 |
4 files changed, 190 insertions, 26 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index ea20cd15a..4a9921a85 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -205,19 +205,8 @@ pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> R | |||
205 | // TODO const/static/array length | 205 | // TODO const/static/array length |
206 | None | 206 | None |
207 | } | 207 | } |
208 | } else if let Some(module) = ast::Module::cast(node) { | ||
209 | Some(module_from_declaration(db, file_id, module)?.resolver(db)) | ||
210 | } else if let Some(_) = ast::SourceFile::cast(node) { | ||
211 | Some(module_from_source(db, file_id.into(), None)?.resolver(db)) | ||
212 | } else if let Some(s) = ast::StructDef::cast(node) { | ||
213 | let module = module_from_child_node(db, file_id, s.syntax())?; | ||
214 | Some(struct_from_module(db, module, s).resolver(db)) | ||
215 | } else if let Some(e) = ast::EnumDef::cast(node) { | ||
216 | let module = module_from_child_node(db, file_id, e.syntax())?; | ||
217 | Some(enum_from_module(db, module, e).resolver(db)) | ||
218 | } else { | 208 | } else { |
219 | // TODO add missing cases | 209 | try_get_resolver_for_node(db, file_id, node) |
220 | None | ||
221 | } | 210 | } |
222 | }) | 211 | }) |
223 | }) | 212 | }) |
@@ -236,20 +225,32 @@ pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNo | |||
236 | // TODO const/static/array length | 225 | // TODO const/static/array length |
237 | None | 226 | None |
238 | } | 227 | } |
239 | } else if let Some(module) = ast::Module::cast(node) { | ||
240 | Some(module_from_declaration(db, file_id, module)?.resolver(db)) | ||
241 | } else if let Some(_) = ast::SourceFile::cast(node) { | ||
242 | Some(module_from_source(db, file_id.into(), None)?.resolver(db)) | ||
243 | } else if let Some(s) = ast::StructDef::cast(node) { | ||
244 | let module = module_from_child_node(db, file_id, s.syntax())?; | ||
245 | Some(struct_from_module(db, module, s).resolver(db)) | ||
246 | } else if let Some(e) = ast::EnumDef::cast(node) { | ||
247 | let module = module_from_child_node(db, file_id, e.syntax())?; | ||
248 | Some(enum_from_module(db, module, e).resolver(db)) | ||
249 | } else { | 228 | } else { |
250 | // TODO add missing cases | 229 | try_get_resolver_for_node(db, file_id, node) |
251 | None | ||
252 | } | 230 | } |
253 | }) | 231 | }) |
254 | .unwrap_or_default() | 232 | .unwrap_or_default() |
255 | } | 233 | } |
234 | |||
235 | fn try_get_resolver_for_node( | ||
236 | db: &impl HirDatabase, | ||
237 | file_id: FileId, | ||
238 | node: &SyntaxNode, | ||
239 | ) -> Option<Resolver> { | ||
240 | if let Some(module) = ast::Module::cast(node) { | ||
241 | Some(module_from_declaration(db, file_id, module)?.resolver(db)) | ||
242 | } else if let Some(_) = ast::SourceFile::cast(node) { | ||
243 | Some(module_from_source(db, file_id.into(), None)?.resolver(db)) | ||
244 | } else if let Some(s) = ast::StructDef::cast(node) { | ||
245 | let module = module_from_child_node(db, file_id, s.syntax())?; | ||
246 | Some(struct_from_module(db, module, s).resolver(db)) | ||
247 | } else if let Some(e) = ast::EnumDef::cast(node) { | ||
248 | let module = module_from_child_node(db, file_id, e.syntax())?; | ||
249 | Some(enum_from_module(db, module, e).resolver(db)) | ||
250 | } else if let Some(f) = ast::FnDef::cast(node) { | ||
251 | function_from_source(db, file_id, f).map(|f| f.resolver(db)) | ||
252 | } else { | ||
253 | // TODO add missing cases | ||
254 | None | ||
255 | } | ||
256 | } | ||
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index dd5f9f31c..d4e10b69c 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -121,8 +121,12 @@ pub(crate) fn reference_definition( | |||
121 | Some(Resolution::GenericParam(..)) => { | 121 | Some(Resolution::GenericParam(..)) => { |
122 | // TODO: go to the generic param def | 122 | // TODO: go to the generic param def |
123 | } | 123 | } |
124 | Some(Resolution::SelfType(_impl_block)) => { | 124 | Some(Resolution::SelfType(impl_block)) => { |
125 | // TODO: go to the implemented type | 125 | let ty = impl_block.target_ty(db); |
126 | |||
127 | if let hir::Ty::Adt { def_id, .. } = ty { | ||
128 | return Exact(NavigationTarget::from_adt_def(db, def_id)); | ||
129 | } | ||
126 | } | 130 | } |
127 | None => { | 131 | None => { |
128 | // If we failed to resolve then check associated items | 132 | // If we failed to resolve then check associated items |
@@ -337,6 +341,94 @@ mod tests { | |||
337 | "spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)", | 341 | "spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)", |
338 | ); | 342 | ); |
339 | } | 343 | } |
344 | #[test] | ||
345 | fn goto_definition_on_self() { | ||
346 | check_goto( | ||
347 | " | ||
348 | //- /lib.rs | ||
349 | struct Foo; | ||
350 | impl Foo { | ||
351 | pub fn new() -> Self { | ||
352 | Self<|> {} | ||
353 | } | ||
354 | } | ||
355 | ", | ||
356 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
357 | ); | ||
358 | |||
359 | check_goto( | ||
360 | " | ||
361 | //- /lib.rs | ||
362 | struct Foo; | ||
363 | impl Foo { | ||
364 | pub fn new() -> Self<|> { | ||
365 | Self {} | ||
366 | } | ||
367 | } | ||
368 | ", | ||
369 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
370 | ); | ||
371 | |||
372 | check_goto( | ||
373 | " | ||
374 | //- /lib.rs | ||
375 | enum Foo { A } | ||
376 | impl Foo { | ||
377 | pub fn new() -> Self<|> { | ||
378 | Foo::A | ||
379 | } | ||
380 | } | ||
381 | ", | ||
382 | "Foo ENUM_DEF FileId(1) [0; 14) [5; 8)", | ||
383 | ); | ||
384 | |||
385 | check_goto( | ||
386 | " | ||
387 | //- /lib.rs | ||
388 | enum Foo { A } | ||
389 | impl Foo { | ||
390 | pub fn thing(a: &Self<|>) { | ||
391 | } | ||
392 | } | ||
393 | ", | ||
394 | "Foo ENUM_DEF FileId(1) [0; 14) [5; 8)", | ||
395 | ); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn goto_definition_on_self_in_trait_impl() { | ||
400 | check_goto( | ||
401 | " | ||
402 | //- /lib.rs | ||
403 | struct Foo; | ||
404 | trait Make { | ||
405 | fn new() -> Self; | ||
406 | } | ||
407 | impl Make for Foo { | ||
408 | fn new() -> Self { | ||
409 | Self<|> {} | ||
410 | } | ||
411 | } | ||
412 | ", | ||
413 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
414 | ); | ||
415 | |||
416 | check_goto( | ||
417 | " | ||
418 | //- /lib.rs | ||
419 | struct Foo; | ||
420 | trait Make { | ||
421 | fn new() -> Self; | ||
422 | } | ||
423 | impl Make for Foo { | ||
424 | fn new() -> Self<|> { | ||
425 | Self{} | ||
426 | } | ||
427 | } | ||
428 | ", | ||
429 | "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", | ||
430 | ); | ||
431 | } | ||
340 | 432 | ||
341 | #[test] | 433 | #[test] |
342 | fn goto_definition_works_when_used_on_definition_name_itself() { | 434 | fn goto_definition_works_when_used_on_definition_name_itself() { |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 638c24e31..f14001e84 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -557,4 +557,62 @@ mod tests { | |||
557 | assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32")); | 557 | assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32")); |
558 | assert_eq!(hover.info.is_exact(), true); | 558 | assert_eq!(hover.info.is_exact(), true); |
559 | } | 559 | } |
560 | |||
561 | #[test] | ||
562 | fn test_hover_self() { | ||
563 | let (analysis, position) = single_file_with_position( | ||
564 | " | ||
565 | struct Thing { x: u32 }; | ||
566 | impl Thing { | ||
567 | fn new() -> Self { | ||
568 | Self<|> { x: 0 } | ||
569 | } | ||
570 | } | ||
571 | ", | ||
572 | ); | ||
573 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
574 | assert_eq!(trim_markup_opt(hover.info.first()), Some("struct Thing")); | ||
575 | assert_eq!(hover.info.is_exact(), true); | ||
576 | |||
577 | let (analysis, position) = single_file_with_position( | ||
578 | " | ||
579 | struct Thing { x: u32 }; | ||
580 | impl Thing { | ||
581 | fn new() -> Self<|> { | ||
582 | Self { x: 0 } | ||
583 | } | ||
584 | } | ||
585 | ", | ||
586 | ); | ||
587 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
588 | assert_eq!(trim_markup_opt(hover.info.first()), Some("struct Thing")); | ||
589 | assert_eq!(hover.info.is_exact(), true); | ||
590 | |||
591 | let (analysis, position) = single_file_with_position( | ||
592 | " | ||
593 | enum Thing { A }; | ||
594 | impl Thing { | ||
595 | pub fn new() -> Self<|> { | ||
596 | Thing::A | ||
597 | } | ||
598 | } | ||
599 | ", | ||
600 | ); | ||
601 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
602 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); | ||
603 | assert_eq!(hover.info.is_exact(), true); | ||
604 | |||
605 | let (analysis, position) = single_file_with_position( | ||
606 | " | ||
607 | enum Thing { A }; | ||
608 | impl Thing { | ||
609 | pub fn thing(a: Self<|>) { | ||
610 | } | ||
611 | } | ||
612 | ", | ||
613 | ); | ||
614 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
615 | assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); | ||
616 | assert_eq!(hover.info.is_exact(), true); | ||
617 | } | ||
560 | } | 618 | } |
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index d806cb368..f6d7f3192 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs | |||
@@ -126,6 +126,19 @@ impl NavigationTarget { | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | 128 | ||
129 | pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget { | ||
130 | match adt_def { | ||
131 | hir::AdtDef::Struct(s) => { | ||
132 | let (file_id, node) = s.source(db); | ||
133 | NavigationTarget::from_named(file_id.original_file(db), &*node) | ||
134 | } | ||
135 | hir::AdtDef::Enum(s) => { | ||
136 | let (file_id, node) = s.source(db); | ||
137 | NavigationTarget::from_named(file_id.original_file(db), &*node) | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
129 | pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget { | 142 | pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget { |
130 | match module_def { | 143 | match module_def { |
131 | hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), | 144 | hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), |