]> git.lizzy.rs Git - rust.git/commitdiff
Show GotoTypeAction for TypeParam
authorLukas Wirth <lukastw97@gmail.com>
Mon, 4 Jan 2021 14:44:19 +0000 (15:44 +0100)
committerLukas Wirth <lukastw97@gmail.com>
Mon, 4 Jan 2021 14:54:45 +0000 (15:54 +0100)
crates/hir/src/code_model.rs
crates/ide/src/hover.rs

index a7a38d43a3bde33754c5da93e8e8a8ee621ad47e..071e553a88b7aaa9c3964d9ba8398829aec56cb8 100644 (file)
@@ -1276,6 +1276,18 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type {
         }
     }
 
+    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
+        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<Type> {
         let params = db.generic_defaults(self.id.parent);
         let local_idx = hir_ty::param_idx(db, self.id)?;
index 932279a06395a8439b22e9a84f7a4a1c7c959069..f2ad95cb607f62e9ce6a2994740ea439418adfa9 100644 (file)
@@ -228,11 +228,6 @@ fn runnable_action(
 }
 
 fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
-    let ty = match def {
-        Definition::Local(it) => it.ty(db),
-        Definition::ConstParam(it) => it.ty(db),
-        _ => return None,
-    };
     let mut targets: Vec<ModuleDef> = 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<HoverAction> {
         }
     };
 
-    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 test_hover_const_param_has_goto_type_action() {
 struct Bar;
 struct Foo<const BAR: Bar>;
 
-impl<const BAR: Bar> Foo<BAR<|>> {} 
+impl<const BAR: Bar> Foo<BAR<|>> {}
 "#,
             expect![[r#"
                 [
@@ -3112,6 +3117,38 @@ impl<const BAR: Bar> Foo<BAR<|>> {}
         );
     }
 
+    #[test]
+    fn test_hover_type_param_has_goto_type_action() {
+        check_actions(
+            r#"
+trait Foo {}
+
+fn foo<T: 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(