From cd6426afe5daaeb90c4398669bcae03a6c353658 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Jan 2021 14:57:59 +0100 Subject: Show implementations when hovering over SelfType --- crates/ide/src/hover.rs | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c0786eb51..399e3e484 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -182,16 +182,18 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option match it { - ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), - ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), - ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), - ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), - _ => None, - }, + let adt = match def { + Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), + Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), + Definition::SelfType(it) => it.target_ty(db).as_adt(), _ => None, + }?; + match adt { + Adt::Struct(it) => it.try_to_nav(db), + Adt::Union(it) => it.try_to_nav(db), + Adt::Enum(it) => it.try_to_nav(db), } + .map(to_action) } fn runnable_action( @@ -2174,6 +2176,25 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } ); } + #[test] + fn test_hover_self_has_impl_action() { + check_actions( + r#"struct foo where Self<|>:;"#, + expect![[r#" + [ + Implementation( + FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + ), + ] + "#]], + ); + } + #[test] fn test_hover_test_has_action() { check_actions( -- cgit v1.2.3 From bd47e140b6f6f39743d52f72437e6eaa2bfd9de1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Jan 2021 15:19:09 +0100 Subject: Show GotoTypeAction for ConstParam --- crates/hir/src/code_model.rs | 6 +++ crates/ide/src/hover.rs | 103 +++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index a2255508e..a7a38d43a 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -1343,6 +1343,12 @@ impl ConstParam { pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { self.id.parent.into() } + + pub fn ty(self, db: &dyn HirDatabase) -> Type { + let def = self.id.parent; + let krate = def.module(db.upcast()).krate; + Type::new(db, krate, def, db.const_param_ty(self.id)) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 399e3e484..932279a06 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -228,45 +228,41 @@ fn runnable_action( } fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { - match def { - Definition::Local(it) => { - let mut targets: Vec = Vec::new(); - let mut push_new_def = |item: ModuleDef| { - if !targets.contains(&item) { - targets.push(item); - } - }; + let ty = match def { + Definition::Local(it) => it.ty(db), + Definition::ConstParam(it) => it.ty(db), + _ => return None, + }; + 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(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()); - } - }); - - let targets = targets - .into_iter() - .filter_map(|it| { - Some(HoverGotoTypeData { - mod_path: render_path( - db, - it.module(db)?, - it.name(db).map(|name| name.to_string()), - ), - nav: it.try_to_nav(db)?, - }) - }) - .collect(); - - Some(HoverAction::GoToType(targets)) + ty.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(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()); } - _ => None, - } + }); + + let targets = targets + .into_iter() + .filter_map(|it| { + Some(HoverGotoTypeData { + mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())), + nav: it.try_to_nav(db)?, + }) + }) + .collect(); + + Some(HoverAction::GoToType(targets)) } fn hover_markup( @@ -3083,6 +3079,39 @@ fn main() { let s<|>t = test().get(); } ); } + #[test] + fn test_hover_const_param_has_goto_type_action() { + check_actions( + r#" +struct Bar; +struct Foo; + +impl Foo> {} +"#, + expect![[r#" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..11, + focus_range: 7..10, + name: "Bar", + kind: Struct, + description: "struct Bar", + }, + }, + ], + ), + ] + "#]], + ); + } + #[test] fn hover_displays_normalized_crate_names() { check( -- cgit v1.2.3 From 54b9b03ca2e90083fd1d1fe199c5dde595423b53 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Jan 2021 15:44:19 +0100 Subject: Show GotoTypeAction for TypeParam --- crates/hir/src/code_model.rs | 12 ++++++++ crates/ide/src/hover.rs | 71 +++++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index a7a38d43a..071e553a8 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -1276,6 +1276,18 @@ impl TypeParam { } } + pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec { + db.generic_predicates_for_param(self.id) + .into_iter() + .filter_map(|pred| match &pred.value { + hir_ty::GenericPredicate::Implemented(trait_ref) => { + Some(Trait::from(trait_ref.trait_)) + } + _ => None, + }) + .collect() + } + pub fn default(self, db: &dyn HirDatabase) -> Option { let params = db.generic_defaults(self.id.parent); let local_idx = hir_ty::param_idx(db, self.id)?; diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 932279a06..f2ad95cb6 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -228,11 +228,6 @@ fn runnable_action( } fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { - let ty = match def { - Definition::Local(it) => it.ty(db), - Definition::ConstParam(it) => it.ty(db), - _ => return None, - }; let mut targets: Vec = Vec::new(); let mut push_new_def = |item: ModuleDef| { if !targets.contains(&item) { @@ -240,17 +235,27 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option { } }; - ty.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(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()); - } - }); + if let Definition::TypeParam(it) = def { + it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); + } else { + let ty = match def { + Definition::Local(it) => it.ty(db), + Definition::ConstParam(it) => it.ty(db), + _ => return None, + }; + + ty.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(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()); + } + }); + } let targets = targets .into_iter() @@ -3086,7 +3091,7 @@ fn main() { let s<|>t = test().get(); } struct Bar; struct Foo; -impl Foo> {} +impl Foo> {} "#, expect![[r#" [ @@ -3112,6 +3117,38 @@ impl Foo> {} ); } + #[test] + fn test_hover_type_param_has_goto_type_action() { + check_actions( + r#" +trait Foo {} + +fn foo(t: T<|>){} +"#, + expect![[r#" + [ + GoToType( + [ + HoverGotoTypeData { + mod_path: "test::Foo", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Foo", + kind: Trait, + description: "trait Foo", + }, + }, + ], + ), + ] + "#]], + ); + } + #[test] fn hover_displays_normalized_crate_names() { check( -- cgit v1.2.3