Repository: rust-lang/rust-analyzer
Pull request #18946 (2025-01-16 06:37:30)

feat: show go-to-type-def actions for func param and trait bound when hovering


Patch:
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 1431bd8ca2..87f666fa40 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -557,12 +557,28 @@ fn goto_type_action_for_def(
             .into_iter()
             .filter(|&it| Some(it.into()) != sized_trait)
             .for_each(|it| push_new_def(it.into()));
+    } else if let Definition::Function(function) = def {
+        walk_and_push_ty(db, &function.ret_type(db), &mut push_new_def);
+
+        let krate = function.module(db).krate();
+        let sized_trait =
+            db.lang_item(krate.into(), LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
+        for param in function.params_without_self(db) {
+            if let Some(type_param) = param.ty().as_type_param(db) {
+                type_param
+                    .trait_bounds(db)
+                    .into_iter()
+                    .filter(|&it| Some(it.into()) != sized_trait)
+                    .for_each(|it| push_new_def(it.into()));
+            } else {
+                walk_and_push_ty(db, param.ty(), &mut push_new_def);
+            }
+        }
     } else {
         let ty = match def {
             Definition::Local(it) => it.ty(db),
             Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
             Definition::Field(field) => field.ty(db),
-            Definition::Function(function) => function.ret_type(db),
             _ => return HoverAction::goto_type_from_targets(db, targets, edition),
         };
 


Test patch:
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 4edfa6d5c3..014b751f95 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2368,6 +2368,97 @@ fn test() {
     );
 }
 
+#[test]
+fn test_hover_show_type_def_for_func_param() {
+    check_actions(
+        r#"
+struct Bar;
+fn f(b: Bar) {
+
+}
+
+fn test() {
+    let b = Bar;
+    f$0(b);
+}
+"#,
+        expect![[r#"
+            [
+                Reference(
+                    FilePositionWrapper {
+                        file_id: FileId(
+                            0,
+                        ),
+                        offset: 15,
+                    },
+                ),
+                GoToType(
+                    [
+                        HoverGotoTypeData {
+                            mod_path: "ra_test_fixture::Bar",
+                            nav: NavigationTarget {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                full_range: 0..11,
+                                focus_range: 7..10,
+                                name: "Bar",
+                                kind: Struct,
+                                description: "struct Bar",
+                            },
+                        },
+                    ],
+                ),
+            ]
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_show_type_def_for_trait_bound() {
+    check_actions(
+        r#"
+trait Bar {}
+fn f<T: Bar>(b: T) {
+
+}
+
+fn test() {
+    f$0();
+}
+"#,
+        expect![[r#"
+            [
+                Reference(
+                    FilePositionWrapper {
+                        file_id: FileId(
+                            0,
+                        ),
+                        offset: 16,
+                    },
+                ),
+                GoToType(
+                    [
+                        HoverGotoTypeData {
+                            mod_path: "ra_test_fixture::Bar",
+                            nav: NavigationTarget {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                full_range: 0..12,
+                                focus_range: 6..9,
+                                name: "Bar",
+                                kind: Trait,
+                                description: "trait Bar",
+                            },
+                        },
+                    ],
+                ),
+            ]
+        "#]],
+    );
+}
+
 #[test]
 fn test_hover_non_ascii_space_doc() {
     check(