From c50157f33025b6ff01809b975a3d12c0e43a0072 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 10 Jun 2020 21:24:36 +0300 Subject: Add `Go to Type Definition` hover action. --- crates/ra_ide/src/hover.rs | 811 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 790 insertions(+), 21 deletions(-) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index ad78b7671..c434e5c8b 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1,8 +1,8 @@ use std::iter::once; use hir::{ - Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, - ModuleDef, ModuleSource, Semantics, + Adt, AdtOrTrait, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, + HirDisplay, Module, ModuleDef, ModuleSource, Semantics, }; use itertools::Itertools; use ra_db::SourceDatabase; @@ -24,19 +24,21 @@ pub struct HoverConfig { pub implementations: bool, pub run: bool, pub debug: bool, + pub goto_type_def: bool, } impl Default for HoverConfig { fn default() -> Self { - Self { implementations: true, run: true, debug: true } + Self { implementations: true, run: true, debug: true, goto_type_def: true } } } impl HoverConfig { - pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; + pub const NO_ACTIONS: Self = + Self { implementations: false, run: false, debug: false, goto_type_def: false }; pub fn any(&self) -> bool { - self.implementations || self.runnable() + self.implementations || self.runnable() || self.goto_type_def } pub fn none(&self) -> bool { @@ -52,6 +54,13 @@ impl HoverConfig { pub enum HoverAction { Runnable(Runnable), Implementaion(FilePosition), + GoToType(Vec), +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct HoverGotoTypeData { + pub mod_path: String, + pub nav: NavigationTarget, } /// Contains the results when hovering over an item @@ -138,6 +147,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option Option { + match def { + Definition::Local(it) => { + let ty = it.ty(db); + let v = ty.flattened_type_items(db); + let targets = v.into_iter() + .map(|it| HoverGotoTypeData { + mod_path: adt_or_trait_mod_path(db, &it), + nav: it.to_nav(db), + }) + .collect_vec(); + + Some(HoverAction::GoToType(targets)) + } + _ => None, + } +} + fn hover_text( docs: Option, desc: Option, @@ -248,25 +279,30 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option .map(|name| name.to_string()) } -fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option { - let mod_path = def.module(db).map(|module| { - once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) - .chain( - module - .path_to_root(db) - .into_iter() - .rev() - .map(|it| it.name(db).map(|name| name.to_string())), - ) - .chain(once(definition_owner_name(db, def))) - .flatten() - .join("::") - }); - mod_path +fn determine_mod_path(db: &RootDatabase, module: Module, name: Option) -> String { + once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) + .chain( + module + .path_to_root(db) + .into_iter() + .rev() + .map(|it| it.name(db).map(|name| name.to_string())), + ) + .chain(once(name)) + .flatten() + .join("::") +} + +fn adt_or_trait_mod_path(db: &RootDatabase, item: &AdtOrTrait) -> String { + determine_mod_path(db, item.module(db), Some(item.name(db).to_string())) +} + +fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { + def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def))) } fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option { - let mod_path = determine_mod_path(db, &def); + let mod_path = definition_mod_path(db, &def); return match def { Definition::Macro(it) => { let src = it.source(db); @@ -1310,4 +1346,737 @@ fn func(foo: i32) { if true { <|>foo; }; } ] "###); } + + #[test] + fn test_hover_struct_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + struct S{ f1: u32 } + + fn main() { + let s<|>t = S{ f1:0 }; + } + ", + &["S"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..19, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 7..8, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_generic_struct_has_goto_type_actions() { + let (_, actions) = check_hover_result( + " + //- /main.rs + struct Arg(u32); + struct S{ f1: T } + + fn main() { + let s<|>t = S{ f1:Arg(0) }; + } + ", + &["S"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 17..37, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 24..25, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Arg", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..16, + name: "Arg", + kind: STRUCT_DEF, + focus_range: Some( + 7..10, + ), + container_name: None, + description: Some( + "struct Arg", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_generic_struct_has_flattened_goto_type_actions() { + let (_, actions) = check_hover_result( + " + //- /main.rs + struct Arg(u32); + struct S{ f1: T } + + fn main() { + let s<|>t = S{ f1: S{ f1: Arg(0) } }; + } + ", + &["S>"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 17..37, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 24..25, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Arg", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..16, + name: "Arg", + kind: STRUCT_DEF, + focus_range: Some( + 7..10, + ), + container_name: None, + description: Some( + "struct Arg", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_tuple_has_goto_type_actions() { + let (_, actions) = check_hover_result( + " + //- /main.rs + struct A(u32); + struct B(u32); + mod M { + pub struct C(u32); + } + + fn main() { + let s<|>t = (A(1), B(2), M::C(3) ); + } + ", + &["(A, B, C)"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "A", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..14, + name: "A", + kind: STRUCT_DEF, + focus_range: Some( + 7..8, + ), + container_name: None, + description: Some( + "struct A", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "B", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 15..29, + name: "B", + kind: STRUCT_DEF, + focus_range: Some( + 22..23, + ), + container_name: None, + description: Some( + "struct B", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "M::C", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 42..60, + name: "C", + kind: STRUCT_DEF, + focus_range: Some( + 53..54, + ), + container_name: None, + description: Some( + "pub struct C", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_return_impl_trait_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo {} + + fn foo() -> impl Foo {} + + fn main() { + let s<|>t = foo(); + } + ", + &["impl Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_generic_return_impl_trait_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo {} + struct S; + + fn foo() -> impl Foo {} + + fn main() { + let s<|>t = foo(); + } + ", + &["impl Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..15, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 16..25, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 23..24, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_arg_impl_trait_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait Foo {} + fn foo(ar<|>g: &impl Foo) {} + ", + &["&impl Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_arg_generic_impl_trait_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait Foo {} + struct S {} + fn foo(ar<|>g: &impl Foo) {} + ", + &["&impl Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..15, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 16..27, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 23..24, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_dyn_return_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo {} + struct S; + impl Foo for S {} + + struct B{} + + fn foo() -> B {} + + fn main() { + let s<|>t = foo(); + } + ", + &["B"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "B", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 41..54, + name: "B", + kind: STRUCT_DEF, + focus_range: Some( + 48..49, + ), + container_name: None, + description: Some( + "struct B", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_dyn_arg_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait Foo {} + fn foo(ar<|>g: &dyn Foo) {} + ", + &["&dyn Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_generic_dyn_arg_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait Foo {} + struct S {} + fn foo(ar<|>g: &dyn Foo) {} + ", + &["&dyn Foo"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..15, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 16..27, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 23..24, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_arg_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait ImplTrait {} + trait DynTrait {} + struct B {} + struct S {} + + fn foo(a<|>rg: &impl ImplTrait>>) {} + ", + &["&impl ImplTrait>>"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "ImplTrait", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..21, + name: "ImplTrait", + kind: TRAIT_DEF, + focus_range: Some( + 6..15, + ), + container_name: None, + description: Some( + "trait ImplTrait", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 58..69, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 65..66, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "DynTrait", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 22..42, + name: "DynTrait", + kind: TRAIT_DEF, + focus_range: Some( + 28..36, + ), + container_name: None, + description: Some( + "trait DynTrait", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "B", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 43..57, + name: "B", + kind: STRUCT_DEF, + focus_range: Some( + 50..51, + ), + container_name: None, + description: Some( + "struct B", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } } -- cgit v1.2.3 From 283ec13fc06dda7ec4d22955e2d2eb96aaff95fd Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 10 Jun 2020 22:56:49 +0300 Subject: Fix type "items" order. --- crates/ra_ide/src/hover.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index c434e5c8b..c4ee2ff79 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -234,9 +234,10 @@ fn runnable_action( fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { match def { Definition::Local(it) => { - let ty = it.ty(db); - let v = ty.flattened_type_items(db); - let targets = v.into_iter() + let targets = it + .ty(db) + .flattened_type_items(db) + .into_iter() .map(|it| HoverGotoTypeData { mod_path: adt_or_trait_mod_path(db, &it), nav: it.to_nav(db), @@ -1980,7 +1981,7 @@ fn func(foo: i32) { if true { <|>foo; }; } } #[test] - fn test_hover_arg_goto_type_action() { + fn test_hover_goto_type_action_links_order() { let (_, actions) = check_hover_result( " //- /lib.rs @@ -1988,10 +1989,10 @@ fn func(foo: i32) { if true { <|>foo; }; } trait DynTrait {} struct B {} struct S {} - - fn foo(a<|>rg: &impl ImplTrait>>) {} + + fn foo(a<|>rg: &impl ImplTrait>>>) {} ", - &["&impl ImplTrait>>"], + &["&impl ImplTrait>>>"], ); assert_debug_snapshot!(actions, @r###" @@ -2018,20 +2019,20 @@ fn func(foo: i32) { if true { <|>foo; }; } }, }, HoverGotoTypeData { - mod_path: "S", + mod_path: "B", nav: NavigationTarget { file_id: FileId( 1, ), - full_range: 58..69, - name: "S", + full_range: 43..57, + name: "B", kind: STRUCT_DEF, focus_range: Some( - 65..66, + 50..51, ), container_name: None, description: Some( - "struct S", + "struct B", ), docs: None, }, @@ -2056,20 +2057,20 @@ fn func(foo: i32) { if true { <|>foo; }; } }, }, HoverGotoTypeData { - mod_path: "B", + mod_path: "S", nav: NavigationTarget { file_id: FileId( 1, ), - full_range: 43..57, - name: "B", + full_range: 58..69, + name: "S", kind: STRUCT_DEF, focus_range: Some( - 50..51, + 65..66, ), container_name: None, description: Some( - "struct B", + "struct S", ), docs: None, }, -- cgit v1.2.3 From d4e75312ba64c2541e0d97b9ad8d6e2a735882a4 Mon Sep 17 00:00:00 2001 From: vsrs Date: Wed, 10 Jun 2020 22:58:25 +0300 Subject: Add associated type test. --- crates/ra_ide/src/hover.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index c4ee2ff79..2a06006e1 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -2080,4 +2080,61 @@ fn func(foo: i32) { if true { <|>foo; }; } ] "###); } + + #[test] + fn test_hover_associated_type_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo { + type Item; + fn get(self) -> Self::Item {} + } + + struct Bar{} + struct S{} + + impl Foo for S{ + type Item = Bar; + } + + fn test() -> impl Foo { + S{} + } + + fn main() { + let s<|>t = test().get(); + } + ", + &["Foo::Item"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..62, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } } -- cgit v1.2.3 From 7ec0064409f90334f6b0dd61e572a65702702985 Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 11 Jun 2020 14:41:42 +0300 Subject: Remove AdtOrTrait --- crates/ra_ide/src/hover.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 2a06006e1..045713519 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -1,8 +1,8 @@ use std::iter::once; use hir::{ - Adt, AdtOrTrait, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, - HirDisplay, Module, ModuleDef, ModuleSource, Semantics, + Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, + Module, ModuleDef, ModuleSource, Semantics, }; use itertools::Itertools; use ra_db::SourceDatabase; @@ -13,7 +13,9 @@ use ra_ide_db::{ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; use crate::{ - display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, + display::{ + macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav, + }, runnables::runnable, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, }; @@ -238,9 +240,11 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { .ty(db) .flattened_type_items(db) .into_iter() - .map(|it| HoverGotoTypeData { - mod_path: adt_or_trait_mod_path(db, &it), - nav: it.to_nav(db), + .filter_map(|it| { + Some(HoverGotoTypeData { + mod_path: mod_path(db, &it)?, + nav: it.try_to_nav(db)?, + }) }) .collect_vec(); @@ -294,8 +298,9 @@ fn determine_mod_path(db: &RootDatabase, module: Module, name: Option) - .join("::") } -fn adt_or_trait_mod_path(db: &RootDatabase, item: &AdtOrTrait) -> String { - determine_mod_path(db, item.module(db), Some(item.name(db).to_string())) +// returns None only for ModuleDef::BuiltinType +fn mod_path(db: &RootDatabase, item: &ModuleDef) -> Option { + Some(determine_mod_path(db, item.module(db)?, item.name(db).map(|name| name.to_string()))) } fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { -- cgit v1.2.3 From 4b07c1e77515ae9198aae6275700aacd43181b50 Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 11 Jun 2020 20:17:32 +0300 Subject: Add Type::walk method --- crates/ra_ide/src/hover.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 045713519..c2909e200 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -236,9 +236,26 @@ fn runnable_action( fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { match def { Definition::Local(it) => { - let targets = it - .ty(db) - .flattened_type_items(db) + let mut targets: Vec = Vec::new(); + let mut push_new_def = |item: ModuleDef| { + if !targets.contains(&item) { + targets.push(item); + } + }; + + it.ty(db).walk(db, |t| { + if let Some(adt) = t.as_adt() { + push_new_def(adt.into()); + } else if let Some(trait_) = t.as_dyn_trait() { + push_new_def(trait_.into()); + } else if let Some(trait_) = t.as_impl_trait(db) { + push_new_def(trait_.into()); + } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { + push_new_def(trait_.into()); + } + }); + + let targets = targets .into_iter() .filter_map(|it| { Some(HoverGotoTypeData { @@ -246,7 +263,7 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { nav: it.try_to_nav(db)?, }) }) - .collect_vec(); + .collect(); Some(HoverAction::GoToType(targets)) } -- cgit v1.2.3 From 022fbefffad0d7c402ac5607457f2828decb2188 Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 11 Jun 2020 23:06:58 +0300 Subject: Apply suggestions from code review --- crates/ra_ide/src/hover.rs | 255 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 253 insertions(+), 2 deletions(-) (limited to 'crates/ra_ide/src/hover.rs') diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index c2909e200..d870e4cbc 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs @@ -248,8 +248,8 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { push_new_def(adt.into()); } else if let Some(trait_) = t.as_dyn_trait() { push_new_def(trait_.into()); - } else if let Some(trait_) = t.as_impl_trait(db) { - push_new_def(trait_.into()); + } else if let Some(traits) = t.as_impl_traits(db) { + traits.into_iter().for_each(|it| push_new_def(it.into())); } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push_new_def(trait_.into()); } @@ -1734,6 +1734,176 @@ fn func(foo: i32) { if true { <|>foo; }; } "###); } + #[test] + fn test_hover_return_impl_traits_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo {} + trait Bar {} + + fn foo() -> impl Foo + Bar {} + + fn main() { + let s<|>t = foo(); + } + ", + &["impl Foo + Bar"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Bar", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 13..25, + name: "Bar", + kind: TRAIT_DEF, + focus_range: Some( + 19..22, + ), + container_name: None, + description: Some( + "trait Bar", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + + #[test] + fn test_hover_generic_return_impl_traits_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /main.rs + trait Foo {} + trait Bar {} + struct S1 {} + struct S2 {} + + fn foo() -> impl Foo + Bar {} + + fn main() { + let s<|>t = foo(); + } + ", + &["impl Foo + Bar"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..15, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Bar", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 16..31, + name: "Bar", + kind: TRAIT_DEF, + focus_range: Some( + 22..25, + ), + container_name: None, + description: Some( + "trait Bar", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S1", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 32..44, + name: "S1", + kind: STRUCT_DEF, + focus_range: Some( + 39..41, + ), + container_name: None, + description: Some( + "struct S1", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S2", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 45..57, + name: "S2", + kind: STRUCT_DEF, + focus_range: Some( + 52..54, + ), + container_name: None, + description: Some( + "struct S2", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + #[test] fn test_hover_arg_impl_trait_has_goto_type_action() { let (_, actions) = check_hover_result( @@ -1774,6 +1944,87 @@ fn func(foo: i32) { if true { <|>foo; }; } "###); } + #[test] + fn test_hover_arg_impl_traits_has_goto_type_action() { + let (_, actions) = check_hover_result( + " + //- /lib.rs + trait Foo {} + trait Bar {} + struct S{} + + fn foo(ar<|>g: &impl Foo + Bar) {} + ", + &["&impl Foo + Bar"], + ); + assert_debug_snapshot!(actions, + @r###" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "Foo", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 0..12, + name: "Foo", + kind: TRAIT_DEF, + focus_range: Some( + 6..9, + ), + container_name: None, + description: Some( + "trait Foo", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "Bar", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 13..28, + name: "Bar", + kind: TRAIT_DEF, + focus_range: Some( + 19..22, + ), + container_name: None, + description: Some( + "trait Bar", + ), + docs: None, + }, + }, + HoverGotoTypeData { + mod_path: "S", + nav: NavigationTarget { + file_id: FileId( + 1, + ), + full_range: 29..39, + name: "S", + kind: STRUCT_DEF, + focus_range: Some( + 36..37, + ), + container_name: None, + description: Some( + "struct S", + ), + docs: None, + }, + }, + ], + ), + ] + "###); + } + #[test] fn test_hover_arg_generic_impl_trait_has_goto_type_action() { let (_, actions) = check_hover_result( -- cgit v1.2.3