Auto merge of #13816 - WaffleLapkin:postfix_adjustment_hints, r=Veykril

Postfix adjustment hints

# Basic Description

This PR implements "postfix" adjustment hints:
![2022-12-21_19-27](https://user-images.githubusercontent.com/38225716/208941721-d48d316f-a918-408a-9757-8d4e2b402a66.png)

They are identical to normal adjustment hints, but are rendered _after_ the expression. E.g. `expr.*` instead of `*expr`. ~~This mirrors "postfix deref" feature that I'm planning to eventually propose to the compiler.~~

# Motivation

The advantage of being postfix is that you need to add parentheses less often:

![2022-12-21_19-38](https://user-images.githubusercontent.com/38225716/208944302-16718112-14a4-4438-8aed-797766391c63.png)
![2022-12-21_19-37](https://user-images.githubusercontent.com/38225716/208944281-d9614888-6597-41ee-bf5d-a081d8048f94.png)

This is because a lot of "reborrow" hints are caused by field access or method calls, both of which are postfix and have higher "precedence" than prefix `&` and `*`.

Also IMHO it just looks nicer and it's more clear what is happening (order of operations).

# Modes

However, there are some cases where postfix hints need parentheses but prefix don't (for example `&x` being turned into `(&x).*.*.&` or `&**&x`).

This PR allows users to choose which look they like more. There are 4 options (`rust-analyzer.inlayHints.expressionAdjustmentHints.mode` setting):
- `prefix` — always use prefix hints (default, what was used before that PR)
- `postfix` — always use postfix hints
- `prefer_prefix` — try to minimize number of parentheses, breaking ties in favor of prefix
- `prefer_postfix` — try to minimize number of parentheses, breaking ties in favor of postfix

Comparison of all modes:

![2022-12-21_19-53](https://user-images.githubusercontent.com/38225716/208947482-26357c82-2b42-47d9-acec-835f5f03f6b4.png)
![2022-12-21_19-49](https://user-images.githubusercontent.com/38225716/208946731-fe566d3b-52b2-4846-994d-c2cecc769e0f.png)
![2022-12-21_19-48](https://user-images.githubusercontent.com/38225716/208946742-6e237f44-805e-469a-a3db-03d8f76e1317.png)
![2022-12-21_19-47](https://user-images.githubusercontent.com/38225716/208946747-79f25fae-e3ea-47d2-8d27-cb4eeac034fe.png)

# Edge cases

Where are some rare cases where chain hints weirdly interact with adjustment hints, for example (note `SourceAnalyzer.&`):

![image](https://user-images.githubusercontent.com/38225716/208947958-41c12971-f1f0-4a41-a930-47939cce9f58.png)

This is pre-existing, you can get the same effect with prefix hints (`SourceAnalyzer)`).

----

Another weird thing is this:

![2022-12-21_20-00](https://user-images.githubusercontent.com/38225716/208948590-ea26d325-2108-4b35-abaa-716a65a1ae99.png)

Here `.&` is a hint and `?` is written in the source code. It looks like `?` is part of the hint because `?.` is ligature in my font. IMO this is a bug in vscode, but still worth mentioning (I'm also too lazy to report it there...).

# Fixed bugs

I've used the "needs parens" API and this accidentally fixed a bug with parens around `as`, see the test diff:
```diff,rust
     let _: *const u32  = &mut 0u32 as *mut u32;
                        //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
+                       //^^^^^^^^^^^^^^^^^^^^^(
+                       //^^^^^^^^^^^^^^^^^^^^^)
...
     let _: *const u32  = &mut 0u32 as *mut u32;
                        //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
+                       //^^^^^^^^^^^^^^^^^^^^^(
+                       //^^^^^^^^^^^^^^^^^^^^^)
```

# Changelog

changelog feature Add an option to make adjustment hints (aka reborrow hints) postfix
changelog fix Fix placement of parentheses around `as` casts for adjustment hints
This commit is contained in:
bors 2023-01-09 13:47:46 +00:00
commit ec968198b9
8 changed files with 402 additions and 32 deletions

View File

@ -35,6 +35,7 @@ pub struct InlayHintsConfig {
pub parameter_hints: bool,
pub chaining_hints: bool,
pub adjustment_hints: AdjustmentHints,
pub adjustment_hints_mode: AdjustmentHintsMode,
pub adjustment_hints_hide_outside_unsafe: bool,
pub closure_return_type_hints: ClosureReturnTypeHints,
pub binding_mode_hints: bool,
@ -74,6 +75,14 @@ pub enum AdjustmentHints {
Never,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AdjustmentHintsMode {
Prefix,
Postfix,
PreferPrefix,
PreferPostfix,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InlayKind {
BindingModeHint,
@ -82,6 +91,7 @@ pub enum InlayKind {
ClosureReturnTypeHint,
GenericParamListHint,
AdjustmentHint,
AdjustmentHintPostfix,
LifetimeHint,
ParameterHint,
TypeHint,
@ -430,7 +440,7 @@ mod tests {
use itertools::Itertools;
use test_utils::extract_annotations;
use crate::inlay_hints::AdjustmentHints;
use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
use crate::DiscriminantHints;
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
@ -446,6 +456,7 @@ mod tests {
lifetime_elision_hints: LifetimeElisionHints::Never,
closure_return_type_hints: ClosureReturnTypeHints::Never,
adjustment_hints: AdjustmentHints::Never,
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
binding_mode_hints: false,
hide_named_constructor_hints: false,

View File

@ -5,9 +5,13 @@
//! ```
use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
use ide_db::RootDatabase;
use syntax::ast::{self, AstNode};
use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
use syntax::{
ast::{self, make, AstNode},
ted,
};
use crate::{AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintsConfig, InlayKind};
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
@ -32,28 +36,14 @@ pub(super) fn hints(
return None;
}
let parent = expr.syntax().parent().and_then(ast::Expr::cast);
let descended = sema.descend_node_into_attributes(expr.clone()).pop();
let desc_expr = descended.as_ref().unwrap_or(expr);
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
let needs_parens = match parent {
Some(parent) => {
match parent {
ast::Expr::AwaitExpr(_)
| ast::Expr::CallExpr(_)
| ast::Expr::CastExpr(_)
| ast::Expr::FieldExpr(_)
| ast::Expr::MethodCallExpr(_)
| ast::Expr::TryExpr(_) => true,
// FIXME: shorthands need special casing, though not sure if adjustments are even valid there
ast::Expr::RecordExpr(_) => false,
ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr),
_ => false,
}
}
None => false,
};
if needs_parens {
let (postfix, needs_outer_parens, needs_inner_parens) =
mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
if needs_outer_parens {
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::OpeningParenthesis,
@ -61,7 +51,32 @@ pub(super) fn hints(
tooltip: None,
});
}
for adjustment in adjustments.into_iter().rev() {
if postfix && needs_inner_parens {
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::OpeningParenthesis,
label: "(".into(),
tooltip: None,
});
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::ClosingParenthesis,
label: ")".into(),
tooltip: None,
});
}
let (mut tmp0, mut tmp1);
let iter: &mut dyn Iterator<Item = _> = if postfix {
tmp0 = adjustments.into_iter();
&mut tmp0
} else {
tmp1 = adjustments.into_iter().rev();
&mut tmp1
};
for adjustment in iter {
if adjustment.source == adjustment.target {
continue;
}
@ -97,12 +112,30 @@ pub(super) fn hints(
};
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::AdjustmentHint,
label: text.into(),
kind: if postfix {
InlayKind::AdjustmentHintPostfix
} else {
InlayKind::AdjustmentHint
},
label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() },
tooltip: None,
});
}
if needs_parens {
if !postfix && needs_inner_parens {
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::OpeningParenthesis,
label: "(".into(),
tooltip: None,
});
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::ClosingParenthesis,
label: ")".into(),
tooltip: None,
});
}
if needs_outer_parens {
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::ClosingParenthesis,
@ -113,11 +146,111 @@ pub(super) fn hints(
Some(())
}
/// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`,
/// if we are going to add (`postfix`) adjustments hints to it.
fn mode_and_needs_parens_for_adjustment_hints(
expr: &ast::Expr,
mode: AdjustmentHintsMode,
) -> (bool, bool, bool) {
use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
match mode {
Prefix | Postfix => {
let postfix = matches!(mode, Postfix);
let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix);
(postfix, inside, outside)
}
PreferPrefix | PreferPostfix => {
let prefer_postfix = matches!(mode, PreferPostfix);
let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false);
let prefix = (false, pre_inside, pre_outside);
let pre_count = pre_inside as u8 + pre_outside as u8;
let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true);
let postfix = (true, post_inside, post_outside);
let post_count = post_inside as u8 + post_outside as u8;
match pre_count.cmp(&post_count) {
Less => prefix,
Greater => postfix,
Equal if prefer_postfix => postfix,
Equal => prefix,
}
}
}
}
/// Returns whatever we need to add paretheses on the inside and/or outside of `expr`,
/// if we are going to add (`postfix`) adjustments hints to it.
fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
// This is a very miserable pile of hacks...
//
// `Expr::needs_parens_in` requires that the expression is the child of the other expression,
// that is supposed to be its parent.
//
// But we want to check what would happen if we add `*`/`.*` to the inner expression.
// To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
// to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
// where "expr" is the `expr` parameter, `*expr` is the editted `expr`,
// and "parent" is the parent of the original expression...
//
// For this we utilize mutable mutable trees, which is a HACK, but it works.
//
// FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this*
// Make `&expr`/`expr?`
let dummy_expr = {
// `make::*` function go through a string, so they parse wrongly.
// for example `` make::expr_try(`|| a`) `` would result in a
// `|| (a?)` and not `(|| a)?`.
//
// Thus we need dummy parens to preserve the relationship we want.
// The parens are then simply ignored by the following code.
let dummy_paren = make::expr_paren(expr.clone());
if postfix {
make::expr_try(dummy_paren)
} else {
make::expr_ref(dummy_paren, false)
}
};
// Do the dark mutable tree magic.
// This essentially makes `dummy_expr` and `expr` switch places (families),
// so that `expr`'s parent is not `dummy_expr`'s parent.
let dummy_expr = dummy_expr.clone_for_update();
let expr = expr.clone_for_update();
ted::replace(expr.syntax(), dummy_expr.syntax());
let parent = dummy_expr.syntax().parent();
let expr = if postfix {
let ast::Expr::TryExpr(e) = &dummy_expr else { unreachable!() };
let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() };
e.expr().unwrap()
} else {
let ast::Expr::RefExpr(e) = &dummy_expr else { unreachable!() };
let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() };
e.expr().unwrap()
};
// At this point
// - `parent` is the parrent of the original expression
// - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
// - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p));
let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone());
(needs_outer_parens, needs_inner_parens)
}
#[cfg(test)]
mod tests {
use crate::{
inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
AdjustmentHints, InlayHintsConfig,
AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
};
#[test]
@ -125,7 +258,7 @@ mod tests {
check_with_config(
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
r#"
//- minicore: coerce_unsized
//- minicore: coerce_unsized, fn
fn main() {
let _: u32 = loop {};
//^^^^^^^<never-to-any>
@ -148,12 +281,16 @@ fn main() {
//^^^^<fn-item-to-fn-pointer>
let _: unsafe fn() = main as fn();
//^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
//^^^^^^^^^^^^(
//^^^^^^^^^^^^)
let _: fn() = || {};
//^^^^^<closure-to-fn-pointer>
let _: unsafe fn() = || {};
//^^^^^<closure-to-unsafe-fn-pointer>
let _: *const u32 = &mut 0u32 as *mut u32;
//^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
//^^^^^^^^^^^^^^^^^^^^^(
//^^^^^^^^^^^^^^^^^^^^^)
let _: &mut [_] = &mut [0; 0];
//^^^^^^^^^^^<unsize>
//^^^^^^^^^^^&mut $
@ -206,6 +343,11 @@ fn main() {
//^^^^^^^<unsize>
//^^^^^^^&mut $
//^^^^^^^*
let _: &mut dyn Fn() = &mut || ();
//^^^^^^^^^^<unsize>
//^^^^^^^^^^&mut $
//^^^^^^^^^^*
}
#[derive(Copy, Clone)]
@ -215,12 +357,153 @@ impl Struct {
fn by_ref(&self) {}
fn by_ref_mut(&mut self) {}
}
trait Trait {}
impl Trait for Struct {}
"#,
)
}
#[test]
fn adjustment_hints_postfix() {
check_with_config(
InlayHintsConfig {
adjustment_hints: AdjustmentHints::Always,
adjustment_hints_mode: AdjustmentHintsMode::Postfix,
..DISABLED_CONFIG
},
r#"
//- minicore: coerce_unsized, fn
fn main() {
Struct.consume();
Struct.by_ref();
//^^^^^^.&
Struct.by_ref_mut();
//^^^^^^.&mut
(&Struct).consume();
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
(&Struct).by_ref();
(&mut Struct).consume();
//^^^^^^^^^^^(
//^^^^^^^^^^^)
//^^^^^^^^^^^.*
(&mut Struct).by_ref();
//^^^^^^^^^^^(
//^^^^^^^^^^^)
//^^^^^^^^^^^.*
//^^^^^^^^^^^.&
(&mut Struct).by_ref_mut();
// Check that block-like expressions don't duplicate hints
let _: &mut [u32] = (&mut []);
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
//^^^^^^^.&mut
//^^^^^^^.<unsize>
let _: &mut [u32] = { &mut [] };
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
//^^^^^^^.&mut
//^^^^^^^.<unsize>
let _: &mut [u32] = unsafe { &mut [] };
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
//^^^^^^^.&mut
//^^^^^^^.<unsize>
let _: &mut [u32] = if true {
&mut []
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
//^^^^^^^.&mut
//^^^^^^^.<unsize>
} else {
loop {}
//^^^^^^^.<never-to-any>
};
let _: &mut [u32] = match () { () => &mut [] }
//^^^^^^^(
//^^^^^^^)
//^^^^^^^.*
//^^^^^^^.&mut
//^^^^^^^.<unsize>
let _: &mut dyn Fn() = &mut || ();
//^^^^^^^^^^(
//^^^^^^^^^^)
//^^^^^^^^^^.*
//^^^^^^^^^^.&mut
//^^^^^^^^^^.<unsize>
}
#[derive(Copy, Clone)]
struct Struct;
impl Struct {
fn consume(self) {}
fn by_ref(&self) {}
fn by_ref_mut(&mut self) {}
}
"#,
);
}
#[test]
fn adjustment_hints_prefer_prefix() {
check_with_config(
InlayHintsConfig {
adjustment_hints: AdjustmentHints::Always,
adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix,
..DISABLED_CONFIG
},
r#"
fn main() {
let _: u32 = loop {};
//^^^^^^^<never-to-any>
Struct.by_ref();
//^^^^^^.&
let (): () = return ();
//^^^^^^^^^<never-to-any>
struct Struct;
impl Struct { fn by_ref(&self) {} }
}
"#,
)
}
#[test]
fn adjustment_hints_prefer_postfix() {
check_with_config(
InlayHintsConfig {
adjustment_hints: AdjustmentHints::Always,
adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix,
..DISABLED_CONFIG
},
r#"
fn main() {
let _: u32 = loop {};
//^^^^^^^.<never-to-any>
Struct.by_ref();
//^^^^^^.&
let (): () = return ();
//^^^^^^^^^<never-to-any>
struct Struct;
impl Struct { fn by_ref(&self) {} }
}
"#,
)
}
#[test]
fn never_to_never_is_never_shown() {
check_with_config(
@ -328,4 +611,20 @@ fn a() {
"#,
);
}
#[test]
fn bug() {
check_with_config(
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
r#"
fn main() {
// These should be identical, but they are not...
let () = return;
let (): () = return;
//^^^^^^<never-to-any>
}
"#,
)
}
}

View File

@ -81,8 +81,8 @@ pub use crate::{
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
inlay_hints::{
AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel,
InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
},
join_lines::JoinLinesConfig,
markup::Markup,

View File

@ -13,6 +13,7 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
use crate::{
hover::hover_for_definition,
inlay_hints::AdjustmentHintsMode,
moniker::{def_to_moniker, MonikerResult},
parent_module::crates_for,
Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
@ -115,6 +116,7 @@ impl StaticIndex<'_> {
closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
adjustment_hints: crate::AdjustmentHints::Never,
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,

View File

@ -333,6 +333,8 @@ config_data! {
inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
/// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
/// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = "\"prefix\"",
/// Whether to show inlay type hints for elided lifetimes in function signatures.
inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
/// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@ -1252,6 +1254,12 @@ impl Config {
},
AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
},
adjustment_hints_mode: match self.data.inlayHints_expressionAdjustmentHints_mode {
AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
},
adjustment_hints_hide_outside_unsafe: self
.data
.inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
@ -1768,6 +1776,15 @@ enum DiscriminantHintsDef {
Fieldless,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum AdjustmentHintsModeDef {
Prefix,
Postfix,
PreferPrefix,
PreferPostfix,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum FilesWatcherDef {
@ -2101,6 +2118,21 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
"Only show discriminant hints on fieldless enum variants."
]
},
"AdjustmentHintsModeDef" => set! {
"type": "string",
"enum": [
"prefix",
"postfix",
"prefer_prefix",
"prefer_postfix",
],
"enumDescriptions": [
"Always show adjustment hints as prefix (`*expr`).",
"Always show adjustment hints as postfix (`expr.*`).",
"Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
"Show prefix or postfix depending on which uses less parenthesis, prefering postfix.",
]
},
"CargoFeaturesDef" => set! {
"anyOf": [
{

View File

@ -452,6 +452,7 @@ pub(crate) fn inlay_hint(
| InlayKind::ChainingHint
| InlayKind::GenericParamListHint
| InlayKind::ClosingParenthesis
| InlayKind::AdjustmentHintPostfix
| InlayKind::LifetimeHint
| InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
},
@ -465,6 +466,7 @@ pub(crate) fn inlay_hint(
| InlayKind::ClosureReturnTypeHint
| InlayKind::GenericParamListHint
| InlayKind::AdjustmentHint
| InlayKind::AdjustmentHintPostfix
| InlayKind::LifetimeHint
| InlayKind::ParameterHint => false,
}),
@ -475,6 +477,7 @@ pub(crate) fn inlay_hint(
| InlayKind::ClosureReturnTypeHint
| InlayKind::GenericParamListHint
| InlayKind::AdjustmentHint
| InlayKind::AdjustmentHintPostfix
| InlayKind::TypeHint
| InlayKind::DiscriminantHint
| InlayKind::ClosingBraceHint => false,
@ -493,6 +496,7 @@ pub(crate) fn inlay_hint(
| InlayKind::GenericParamListHint
| InlayKind::LifetimeHint
| InlayKind::AdjustmentHint
| InlayKind::AdjustmentHintPostfix
| InlayKind::ClosingBraceHint => None,
},
text_edits: None,

View File

@ -469,6 +469,11 @@ Whether to show inlay hints for type adjustments.
--
Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
--
[[rust-analyzer.inlayHints.expressionAdjustmentHints.mode]]rust-analyzer.inlayHints.expressionAdjustmentHints.mode (default: `"prefix"`)::
+
--
Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
--
[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
+
--

View File

@ -1000,6 +1000,23 @@
"default": false,
"type": "boolean"
},
"rust-analyzer.inlayHints.expressionAdjustmentHints.mode": {
"markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).",
"default": "prefix",
"type": "string",
"enum": [
"prefix",
"postfix",
"prefer_prefix",
"prefer_postfix"
],
"enumDescriptions": [
"Always show adjustment hints as prefix (`*expr`).",
"Always show adjustment hints as postfix (`expr.*`).",
"Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
"Show prefix or postfix depending on which uses less parenthesis, prefering postfix."
]
},
"rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
"markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
"default": "never",