diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/code_model.rs | 18 | ||||
-rw-r--r-- | crates/ide/src/hover.rs | 177 |
2 files changed, 150 insertions, 45 deletions
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index a2255508e..071e553a8 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -1276,6 +1276,18 @@ impl TypeParam { | |||
1276 | } | 1276 | } |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1280 | db.generic_predicates_for_param(self.id) | ||
1281 | .into_iter() | ||
1282 | .filter_map(|pred| match &pred.value { | ||
1283 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1284 | Some(Trait::from(trait_ref.trait_)) | ||
1285 | } | ||
1286 | _ => None, | ||
1287 | }) | ||
1288 | .collect() | ||
1289 | } | ||
1290 | |||
1279 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | 1291 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { |
1280 | let params = db.generic_defaults(self.id.parent); | 1292 | let params = db.generic_defaults(self.id.parent); |
1281 | let local_idx = hir_ty::param_idx(db, self.id)?; | 1293 | let local_idx = hir_ty::param_idx(db, self.id)?; |
@@ -1343,6 +1355,12 @@ impl ConstParam { | |||
1343 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | 1355 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { |
1344 | self.id.parent.into() | 1356 | self.id.parent.into() |
1345 | } | 1357 | } |
1358 | |||
1359 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1360 | let def = self.id.parent; | ||
1361 | let krate = def.module(db.upcast()).krate; | ||
1362 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1363 | } | ||
1346 | } | 1364 | } |
1347 | 1365 | ||
1348 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1366 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
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 | ||
197 | fn runnable_action( | 199 | fn runnable_action( |
@@ -226,45 +228,46 @@ fn runnable_action( | |||
226 | } | 228 | } |
227 | 229 | ||
228 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 230 | fn 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 | ||
270 | fn hover_markup( | 273 | fn 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#" | ||
3091 | struct Bar; | ||
3092 | struct Foo<const BAR: Bar>; | ||
3093 | |||
3094 | impl<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#" | ||
3124 | trait Foo {} | ||
3125 | |||
3126 | fn 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#" |