about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-10 09:50:40 +0000
committerbors <bors@rust-lang.org>2024-07-10 09:50:40 +0000
commit2faa2cb0db83159e8cf7b974fa294bffb575d565 (patch)
tree1383fb6c0b981e8d70e953a6144eacd72ca31ed8
parent5445aef843f1a921ba146ace01a2cbbfc33ee38f (diff)
parent7da46157636deae7cd6a4df18432296861c0e6a3 (diff)
downloadrust-2faa2cb0db83159e8cf7b974fa294bffb575d565.tar.gz
rust-2faa2cb0db83159e8cf7b974fa294bffb575d565.zip
Auto merge of #17544 - MikeWalrus:inlay-hint-generic-param-name, r=Veykril
feat: add inlay hints for generic parameters

fixes #11091

By default, only hints for const generic parameters are shown, and this can be configured through `rust-analyzer.inlayHints.genericParameterHints.enable`.

Probably needs more testing.
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs315
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs17
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs4
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc15
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json30
10 files changed, 430 insertions, 14 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 3f10bed5110..944951f26a2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -29,6 +29,7 @@ mod closure_captures;
 mod closure_ret;
 mod discriminant;
 mod fn_lifetime_fn;
+mod generic_param;
 mod implicit_drop;
 mod implicit_static;
 mod param_name;
@@ -40,6 +41,7 @@ pub struct InlayHintsConfig {
     pub type_hints: bool,
     pub discriminant_hints: DiscriminantHints,
     pub parameter_hints: bool,
+    pub generic_parameter_hints: GenericParameterHints,
     pub chaining_hints: bool,
     pub adjustment_hints: AdjustmentHints,
     pub adjustment_hints_mode: AdjustmentHintsMode,
@@ -95,6 +97,13 @@ pub enum DiscriminantHints {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
+pub struct GenericParameterHints {
+    pub type_hints: bool,
+    pub lifetime_hints: bool,
+    pub const_hints: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum LifetimeElisionHints {
     Always,
     SkipTrivial,
@@ -127,6 +136,7 @@ pub enum InlayKind {
     GenericParamList,
     Lifetime,
     Parameter,
+    GenericParameter,
     Type,
     Drop,
     RangeExclusive,
@@ -447,6 +457,7 @@ fn ty_to_text_edit(
 //
 // * types of local variables
 // * names of function arguments
+// * names of const generic parameters
 // * types of chained expressions
 //
 // Optionally, one can enable additional hints for
@@ -454,6 +465,7 @@ fn ty_to_text_edit(
 // * return types of closure expressions
 // * elided lifetimes
 // * compiler inserted reborrows
+// * names of generic type and lifetime parameters
 //
 // Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
 // any of the
@@ -543,6 +555,9 @@ fn hints(
     node: SyntaxNode,
 ) {
     closing_brace::hints(hints, sema, config, file_id, node.clone());
+    if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
+        generic_param::hints(hints, sema, config, any_has_generic_args);
+    }
     match_ast! {
         match node {
             ast::Expr(expr) => {
@@ -645,13 +660,18 @@ mod tests {
     use crate::DiscriminantHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
-    use super::{ClosureReturnTypeHints, InlayFieldsToResolve};
+    use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
 
     pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
         parameter_hints: false,
+        generic_parameter_hints: GenericParameterHints {
+            type_hints: false,
+            lifetime_hints: false,
+            const_hints: false,
+        },
         chaining_hints: false,
         lifetime_elision_hints: LifetimeElisionHints::Never,
         closure_return_type_hints: ClosureReturnTypeHints::Never,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
new file mode 100644
index 00000000000..51855eeae23
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -0,0 +1,315 @@
+//! Implementation of inlay hints for generic parameters.
+use ide_db::{active_parameter::generic_def_for_node, RootDatabase};
+use syntax::{
+    ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
+    AstNode,
+};
+
+use crate::{inlay_hints::GenericParameterHints, InlayHint, InlayHintsConfig, InlayKind};
+
+use super::param_name::{is_argument_similar_to_param_name, render_label};
+
+pub(crate) fn hints(
+    acc: &mut Vec<InlayHint>,
+    sema: &hir::Semantics<'_, RootDatabase>,
+    config: &InlayHintsConfig,
+    node: AnyHasGenericArgs,
+) -> Option<()> {
+    let GenericParameterHints { type_hints, lifetime_hints, const_hints } =
+        config.generic_parameter_hints;
+    if !(type_hints || lifetime_hints || const_hints) {
+        return None;
+    }
+
+    let generic_arg_list = node.generic_arg_list()?;
+
+    let (generic_def, _, _, _) =
+        generic_def_for_node(sema, &generic_arg_list, &node.syntax().first_token()?)?;
+
+    let mut args = generic_arg_list.generic_args().peekable();
+    let start_with_lifetime = matches!(args.peek()?, ast::GenericArg::LifetimeArg(_));
+    let params = generic_def.params(sema.db).into_iter().filter(|p| {
+        if let hir::GenericParam::TypeParam(it) = p {
+            if it.is_implicit(sema.db) {
+                return false;
+            }
+        }
+        if !start_with_lifetime {
+            return !matches!(p, hir::GenericParam::LifetimeParam(_));
+        }
+        true
+    });
+
+    let hints = params.zip(args).filter_map(|(param, arg)| {
+        if matches!(arg, ast::GenericArg::AssocTypeArg(_)) {
+            return None;
+        }
+
+        let name = param.name(sema.db);
+        let param_name = name.as_str()?;
+
+        let should_hide = {
+            let argument = get_string_representation(&arg)?;
+            is_argument_similar_to_param_name(&argument, param_name)
+        };
+
+        if should_hide {
+            return None;
+        }
+
+        let range = sema.original_range_opt(arg.syntax())?.range;
+
+        let source_syntax = match param {
+            hir::GenericParam::TypeParam(it) => {
+                if !type_hints || !matches!(arg, ast::GenericArg::TypeArg(_)) {
+                    return None;
+                }
+                sema.source(it.merge())?.value.syntax().clone()
+            }
+            hir::GenericParam::ConstParam(it) => {
+                if !const_hints || !matches!(arg, ast::GenericArg::ConstArg(_)) {
+                    return None;
+                }
+                let syntax = sema.source(it.merge())?.value.syntax().clone();
+                let const_param = ast::ConstParam::cast(syntax)?;
+                const_param.name()?.syntax().clone()
+            }
+            hir::GenericParam::LifetimeParam(it) => {
+                if !lifetime_hints || !matches!(arg, ast::GenericArg::LifetimeArg(_)) {
+                    return None;
+                }
+                sema.source(it)?.value.syntax().clone()
+            }
+        };
+        let linked_location = sema.original_range_opt(&source_syntax);
+        let label = render_label(param_name, config, linked_location);
+
+        Some(InlayHint {
+            range,
+            position: crate::InlayHintPosition::Before,
+            pad_left: false,
+            pad_right: true,
+            kind: InlayKind::GenericParameter,
+            label,
+            text_edit: None,
+        })
+    });
+
+    acc.extend(hints);
+    Some(())
+}
+
+fn get_string_representation(arg: &ast::GenericArg) -> Option<String> {
+    return match arg {
+        ast::GenericArg::AssocTypeArg(_) => None,
+        ast::GenericArg::ConstArg(const_arg) => Some(const_arg.to_string()),
+        ast::GenericArg::LifetimeArg(lifetime_arg) => {
+            let lifetime = lifetime_arg.lifetime()?;
+            Some(lifetime.to_string())
+        }
+        ast::GenericArg::TypeArg(type_arg) => {
+            let ty = type_arg.ty()?;
+            Some(
+                type_path_segment(&ty)
+                    .map_or_else(|| type_arg.to_string(), |segment| segment.to_string()),
+            )
+        }
+    };
+
+    fn type_path_segment(ty: &ast::Type) -> Option<ast::PathSegment> {
+        match ty {
+            ast::Type::ArrayType(it) => type_path_segment(&it.ty()?),
+            ast::Type::ForType(it) => type_path_segment(&it.ty()?),
+            ast::Type::ParenType(it) => type_path_segment(&it.ty()?),
+            ast::Type::PathType(path_type) => path_type.path()?.segment(),
+            ast::Type::PtrType(it) => type_path_segment(&it.ty()?),
+            ast::Type::RefType(it) => type_path_segment(&it.ty()?),
+            ast::Type::SliceType(it) => type_path_segment(&it.ty()?),
+            _ => None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{
+        inlay_hints::{
+            tests::{check_with_config, DISABLED_CONFIG},
+            GenericParameterHints,
+        },
+        InlayHintsConfig,
+    };
+
+    #[track_caller]
+    fn generic_param_name_hints_always(ra_fixture: &str) {
+        check_with_config(
+            InlayHintsConfig {
+                generic_parameter_hints: GenericParameterHints {
+                    type_hints: true,
+                    lifetime_hints: true,
+                    const_hints: true,
+                },
+                ..DISABLED_CONFIG
+            },
+            ra_fixture,
+        );
+    }
+
+    #[track_caller]
+    fn generic_param_name_hints_const_only(ra_fixture: &str) {
+        check_with_config(
+            InlayHintsConfig {
+                generic_parameter_hints: GenericParameterHints {
+                    type_hints: false,
+                    lifetime_hints: false,
+                    const_hints: true,
+                },
+                ..DISABLED_CONFIG
+            },
+            ra_fixture,
+        );
+    }
+
+    #[test]
+    fn type_only() {
+        generic_param_name_hints_always(
+            r#"
+struct A<X, Y> {
+    x: X,
+    y: Y,
+}
+
+fn foo(a: A<usize,  u32>) {}
+          //^^^^^ X ^^^ Y
+"#,
+        )
+    }
+
+    #[test]
+    fn lifetime_and_type() {
+        generic_param_name_hints_always(
+            r#"
+struct A<'a, X> {
+    x: &'a X
+}
+
+fn foo<'b>(a: A<'b,  u32>) {}
+              //^^ 'a^^^ X
+"#,
+        )
+    }
+
+    #[test]
+    fn omit_lifetime() {
+        generic_param_name_hints_always(
+            r#"
+struct A<'a, X> {
+    x: &'a X
+}
+
+fn foo() {
+    let x: i32 = 1;
+    let a: A<i32> = A { x: &x };
+          // ^^^ X
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn const_only() {
+        generic_param_name_hints_always(
+            r#"
+struct A<const X: usize, const Y: usize> {};
+
+fn foo(a: A<12, 2>) {}
+          //^^ X^ Y
+"#,
+        )
+    }
+
+    #[test]
+    fn lifetime_and_type_and_const() {
+        generic_param_name_hints_always(
+            r#"
+struct A<'a, X, const LEN: usize> {
+    x: &'a [X; LEN],
+}
+
+fn foo<'b>(a: A<
+    'b,
+ // ^^ 'a
+    u32,
+ // ^^^ X
+    3
+ // ^ LEN
+    >) {}
+"#,
+        )
+    }
+
+    #[test]
+    fn const_only_config() {
+        generic_param_name_hints_const_only(
+            r#"
+struct A<'a, X, const LEN: usize> {
+    x: &'a [X; LEN],
+}
+
+fn foo<'b>(a: A<
+    'b,
+    u32,
+    3
+ // ^ LEN
+    >) {}
+"#,
+        )
+    }
+
+    #[test]
+    fn assoc_type() {
+        generic_param_name_hints_always(
+            r#"
+trait Trait<T> {
+    type Assoc1;
+    type Assoc2;
+}
+
+fn foo() -> impl Trait<i32, Assoc1 = u32, Assoc2 = u32> {}
+                    // ^^^ T
+"#,
+        )
+    }
+
+    #[test]
+    fn hide_similar() {
+        generic_param_name_hints_always(
+            r#"
+struct A<'a, X, const N: usize> {
+    x: &'a [X; N],
+}
+
+const N: usize = 3;
+
+mod m {
+    type X = u32;
+}
+
+fn foo<'a>(a: A<'a, m::X, N>) {}
+"#,
+        )
+    }
+
+    #[test]
+    fn mismatching_args() {
+        generic_param_name_hints_always(
+            r#"
+struct A<X, const N: usize> {
+    x: [X; N]
+}
+
+type InvalidType = A<3, i32>;
+"#,
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 9819d0e3fbb..2e2a64c5520 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -3,6 +3,8 @@
 //! fn max(x: i32, y: i32) -> i32 { x + y }
 //! _ = max(/*x*/4, /*y*/4);
 //! ```
+use std::fmt::Display;
+
 use either::Either;
 use hir::{Callable, Semantics};
 use ide_db::{base_db::FileRange, RootDatabase};
@@ -46,9 +48,7 @@ pub(super) fn hints(
         .map(|(param, param_name, _, FileRange { range, .. })| {
             let linked_location = param.and_then(|name| sema.original_range_opt(name.syntax()));
 
-            let colon = if config.render_colons { ":" } else { "" };
-            let label =
-                InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
+            let label = render_label(&param_name, config, linked_location);
             InlayHint {
                 range,
                 kind: InlayKind::Parameter,
@@ -64,6 +64,16 @@ pub(super) fn hints(
     Some(())
 }
 
+pub(super) fn render_label(
+    param_name: impl Display,
+    config: &InlayHintsConfig,
+    linked_location: Option<FileRange>,
+) -> InlayHintLabel {
+    let colon = if config.render_colons { ":" } else { "" };
+
+    InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location)
+}
+
 fn get_callable(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
@@ -113,7 +123,7 @@ fn should_hide_param_name_hint(
     };
     let fn_name = fn_name.as_deref();
     is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
-        || is_argument_similar_to_param_name(argument, param_name)
+        || is_argument_expr_similar_to_param_name(argument, param_name)
         || param_name.starts_with("ra_fixture")
         || (callable.n_params() == 1 && is_obvious_param(param_name))
         || is_adt_constructor_similar_to_param_name(sema, argument, param_name)
@@ -143,14 +153,17 @@ fn is_param_name_suffix_of_fn_name(
     }
 }
 
-fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
-    // check whether param_name and argument are the same or
-    // whether param_name is a prefix/suffix of argument(split at `_`)
+fn is_argument_expr_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
     let argument = match get_string_representation(argument) {
         Some(argument) => argument,
         None => return false,
     };
+    is_argument_similar_to_param_name(&argument, param_name)
+}
 
+/// Check whether param_name and argument are the same or
+/// whether param_name is a prefix/suffix of argument(split at `_`).
+pub(super) fn is_argument_similar_to_param_name(argument: &str, param_name: &str) -> bool {
     // std is honestly too panic happy...
     let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at));
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 28ae0dce987..f0b35903f38 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -89,8 +89,8 @@ pub use crate::{
     },
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
-        InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
-        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+        GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
+        InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 0d2311b6e98..5eb5c87f13e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -131,6 +131,11 @@ impl StaticIndex<'_> {
                     discriminant_hints: crate::DiscriminantHints::Fieldless,
                     type_hints: true,
                     parameter_hints: true,
+                    generic_parameter_hints: crate::GenericParameterHints {
+                        type_hints: false,
+                        lifetime_hints: false,
+                        const_hints: true,
+                    },
                     chaining_hints: true,
                     closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 16a880e18bf..90316f3b89d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -1008,6 +1008,11 @@ impl flags::AnalysisStats {
                     type_hints: true,
                     discriminant_hints: ide::DiscriminantHints::Always,
                     parameter_hints: true,
+                    generic_parameter_hints: ide::GenericParameterHints {
+                        type_hints: true,
+                        lifetime_hints: true,
+                        const_hints: true,
+                    },
                     chaining_hints: true,
                     adjustment_hints: ide::AdjustmentHints::Always,
                     adjustment_hints_mode: ide::AdjustmentHintsMode::Postfix,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 94e01158629..3594cdda2e9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -10,9 +10,9 @@ use dirs::config_dir;
 use flycheck::{CargoOptions, FlycheckConfig};
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
-    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
-    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
-    Snippet, SnippetScope, SourceRootId,
+    GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
+    InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig,
+    MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@@ -509,6 +509,12 @@ config_data! {
         inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false,
         /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
         inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix,
+        /// Whether to show const generic parameter name inlay hints.
+        inlayHints_genericParameterHints_const_enable: bool= false,
+        /// Whether to show generic lifetime parameter name inlay hints.
+        inlayHints_genericParameterHints_lifetime_enable: bool = true,
+        /// Whether to show generic type parameter name inlay hints.
+        inlayHints_genericParameterHints_type_enable: bool = false,
         /// Whether to show implicit drop hints.
         inlayHints_implicitDrops_enable: bool                      = false,
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
@@ -1391,6 +1397,11 @@ impl Config {
             render_colons: self.inlayHints_renderColons().to_owned(),
             type_hints: self.inlayHints_typeHints_enable().to_owned(),
             parameter_hints: self.inlayHints_parameterHints_enable().to_owned(),
+            generic_parameter_hints: GenericParameterHints {
+                type_hints: self.inlayHints_genericParameterHints_type_enable().to_owned(),
+                lifetime_hints: self.inlayHints_genericParameterHints_lifetime_enable().to_owned(),
+                const_hints: self.inlayHints_genericParameterHints_const_enable().to_owned(),
+            },
             chaining_hints: self.inlayHints_chainingHints_enable().to_owned(),
             discriminant_hints: match self.inlayHints_discriminantHints_enable() {
                 DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index c82ce110d16..de394d3d118 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -501,7 +501,9 @@ pub(crate) fn inlay_hint(
         padding_left: Some(inlay_hint.pad_left),
         padding_right: Some(inlay_hint.pad_right),
         kind: match inlay_hint.kind {
-            InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER),
+            InlayKind::Parameter | InlayKind::GenericParameter => {
+                Some(lsp_types::InlayHintKind::PARAMETER)
+            }
             InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE),
             _ => None,
         },
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index a95c897991d..edb95abdb8e 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -655,6 +655,21 @@ Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
 --
 Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
 --
+[[rust-analyzer.inlayHints.genericParameterHints.const.enable]]rust-analyzer.inlayHints.genericParameterHints.const.enable (default: `false`)::
++
+--
+Whether to show const generic parameter name inlay hints.
+--
+[[rust-analyzer.inlayHints.genericParameterHints.lifetime.enable]]rust-analyzer.inlayHints.genericParameterHints.lifetime.enable (default: `true`)::
++
+--
+Whether to show generic lifetime parameter name inlay hints.
+--
+[[rust-analyzer.inlayHints.genericParameterHints.type.enable]]rust-analyzer.inlayHints.genericParameterHints.type.enable (default: `false`)::
++
+--
+Whether to show generic type parameter name inlay hints.
+--
 [[rust-analyzer.inlayHints.implicitDrops.enable]]rust-analyzer.inlayHints.implicitDrops.enable (default: `false`)::
 +
 --
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1fec6f621d1..a06ca8d8f6a 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1912,6 +1912,36 @@
             {
                 "title": "inlayHints",
                 "properties": {
+                    "rust-analyzer.inlayHints.genericParameterHints.const.enable": {
+                        "markdownDescription": "Whether to show const generic parameter name inlay hints.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.genericParameterHints.lifetime.enable": {
+                        "markdownDescription": "Whether to show generic lifetime parameter name inlay hints.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
+                    "rust-analyzer.inlayHints.genericParameterHints.type.enable": {
+                        "markdownDescription": "Whether to show generic type parameter name inlay hints.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "inlayHints",
+                "properties": {
                     "rust-analyzer.inlayHints.implicitDrops.enable": {
                         "markdownDescription": "Whether to show implicit drop hints.",
                         "default": false,