aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/hover.rs177
1 files changed, 132 insertions, 45 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c0786eb51..f2ad95cb6 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<Hov
182 }) 182 })
183 } 183 }
184 184
185 match def { 185 let adt = match def {
186 Definition::ModuleDef(it) => match it { 186 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
187 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), 187 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
188 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), 188 Definition::SelfType(it) => it.target_ty(db).as_adt(),
189 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
190 ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
191 _ => None,
192 },
193 _ => None, 189 _ => None,
190 }?;
191 match adt {
192 Adt::Struct(it) => it.try_to_nav(db),
193 Adt::Union(it) => it.try_to_nav(db),
194 Adt::Enum(it) => it.try_to_nav(db),
194 } 195 }
196 .map(to_action)
195} 197}
196 198
197fn runnable_action( 199fn runnable_action(
@@ -226,45 +228,46 @@ fn runnable_action(
226} 228}
227 229
228fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 230fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
229 match def { 231 let mut targets: Vec<ModuleDef> = Vec::new();
230 Definition::Local(it) => { 232 let mut push_new_def = |item: ModuleDef| {
231 let mut targets: Vec<ModuleDef> = Vec::new(); 233 if !targets.contains(&item) {
232 let mut push_new_def = |item: ModuleDef| { 234 targets.push(item);
233 if !targets.contains(&item) {
234 targets.push(item);
235 }
236 };
237
238 it.ty(db).walk(db, |t| {
239 if let Some(adt) = t.as_adt() {
240 push_new_def(adt.into());
241 } else if let Some(trait_) = t.as_dyn_trait() {
242 push_new_def(trait_.into());
243 } else if let Some(traits) = t.as_impl_traits(db) {
244 traits.into_iter().for_each(|it| push_new_def(it.into()));
245 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
246 push_new_def(trait_.into());
247 }
248 });
249
250 let targets = targets
251 .into_iter()
252 .filter_map(|it| {
253 Some(HoverGotoTypeData {
254 mod_path: render_path(
255 db,
256 it.module(db)?,
257 it.name(db).map(|name| name.to_string()),
258 ),
259 nav: it.try_to_nav(db)?,
260 })
261 })
262 .collect();
263
264 Some(HoverAction::GoToType(targets))
265 } 235 }
266 _ => None, 236 };
237
238 if let Definition::TypeParam(it) = def {
239 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
240 } else {
241 let ty = match def {
242 Definition::Local(it) => it.ty(db),
243 Definition::ConstParam(it) => it.ty(db),
244 _ => return None,
245 };
246
247 ty.walk(db, |t| {
248 if let Some(adt) = t.as_adt() {
249 push_new_def(adt.into());
250 } else if let Some(trait_) = t.as_dyn_trait() {
251 push_new_def(trait_.into());
252 } else if let Some(traits) = t.as_impl_traits(db) {
253 traits.into_iter().for_each(|it| push_new_def(it.into()));
254 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
255 push_new_def(trait_.into());
256 }
257 });
267 } 258 }
259
260 let targets = targets
261 .into_iter()
262 .filter_map(|it| {
263 Some(HoverGotoTypeData {
264 mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())),
265 nav: it.try_to_nav(db)?,
266 })
267 })
268 .collect();
269
270 Some(HoverAction::GoToType(targets))
268} 271}
269 272
270fn hover_markup( 273fn hover_markup(
@@ -2175,6 +2178,25 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2175 } 2178 }
2176 2179
2177 #[test] 2180 #[test]
2181 fn test_hover_self_has_impl_action() {
2182 check_actions(
2183 r#"struct foo where Self<|>:;"#,
2184 expect![[r#"
2185 [
2186 Implementation(
2187 FilePosition {
2188 file_id: FileId(
2189 0,
2190 ),
2191 offset: 7,
2192 },
2193 ),
2194 ]
2195 "#]],
2196 );
2197 }
2198
2199 #[test]
2178 fn test_hover_test_has_action() { 2200 fn test_hover_test_has_action() {
2179 check_actions( 2201 check_actions(
2180 r#" 2202 r#"
@@ -3063,6 +3085,71 @@ fn main() { let s<|>t = test().get(); }
3063 } 3085 }
3064 3086
3065 #[test] 3087 #[test]
3088 fn test_hover_const_param_has_goto_type_action() {
3089 check_actions(
3090 r#"
3091struct Bar;
3092struct Foo<const BAR: Bar>;
3093
3094impl<const BAR: Bar> Foo<BAR<|>> {}
3095"#,
3096 expect![[r#"
3097 [
3098 GoToType(
3099 [
3100 HoverGotoTypeData {
3101 mod_path: "test::Bar",
3102 nav: NavigationTarget {
3103 file_id: FileId(
3104 0,
3105 ),
3106 full_range: 0..11,
3107 focus_range: 7..10,
3108 name: "Bar",
3109 kind: Struct,
3110 description: "struct Bar",
3111 },
3112 },
3113 ],
3114 ),
3115 ]
3116 "#]],
3117 );
3118 }
3119
3120 #[test]
3121 fn test_hover_type_param_has_goto_type_action() {
3122 check_actions(
3123 r#"
3124trait Foo {}
3125
3126fn foo<T: Foo>(t: T<|>){}
3127"#,
3128 expect![[r#"
3129 [
3130 GoToType(
3131 [
3132 HoverGotoTypeData {
3133 mod_path: "test::Foo",
3134 nav: NavigationTarget {
3135 file_id: FileId(
3136 0,
3137 ),
3138 full_range: 0..12,
3139 focus_range: 6..9,
3140 name: "Foo",
3141 kind: Trait,
3142 description: "trait Foo",
3143 },
3144 },
3145 ],
3146 ),
3147 ]
3148 "#]],
3149 );
3150 }
3151
3152 #[test]
3066 fn hover_displays_normalized_crate_names() { 3153 fn hover_displays_normalized_crate_names() {
3067 check( 3154 check(
3068 r#" 3155 r#"