aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Penttinen <[email protected]>2019-03-07 08:32:39 +0000
committerVille Penttinen <[email protected]>2019-03-07 15:34:44 +0000
commit4a0bb3d7c53c2a914649087bf206d52ed5768576 (patch)
treef51670df82dfc0df68e6fda77d40878297af2ad6
parenta41d8e140ca65cb87bf6e69a35c3e86410aba374 (diff)
Add support for goto definition and hover on Self
This fixes #943
-rw-r--r--crates/ra_hir/src/source_binder.rs49
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs96
-rw-r--r--crates/ra_ide_api/src/hover.rs58
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs13
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
235fn 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),