Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/inlay_hints.rs22
-rw-r--r--crates/ide/src/inlay_hints/generic_param.rs315
-rw-r--r--crates/ide/src/inlay_hints/param_name.rs27
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/ide/src/static_index.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--crates/rust-analyzer/src/config.rs17
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs4
-rw-r--r--docs/user/generated_config.adoc15
-rw-r--r--editors/code/package.json30
10 files changed, 430 insertions, 14 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3f10bed511..944951f26a 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/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/crates/ide/src/inlay_hints/generic_param.rs b/crates/ide/src/inlay_hints/generic_param.rs
new file mode 100644
index 0000000000..51855eeae2
--- /dev/null
+++ b/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/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 9819d0e3fb..2e2a64c552 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/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/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 28ae0dce98..f0b35903f3 100644
--- a/crates/ide/src/lib.rs
+++ b/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/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 0d2311b6e9..5eb5c87f13 100644
--- a/crates/ide/src/static_index.rs
+++ b/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/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 16a880e18b..90316f3b89 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/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/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 94e0115862..3594cdda2e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/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/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index c82ce110d1..de394d3d11 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/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/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index a95c897991..edb95abdb8 100644
--- a/docs/user/generated_config.adoc
+++ b/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/editors/code/package.json b/editors/code/package.json
index 1fec6f621d..a06ca8d8f6 100644
--- a/editors/code/package.json
+++ b/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,