Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints/adjustment.rs')
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs277
1 files changed, 125 insertions, 152 deletions
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index c37c469dff..4d7d6e270e 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,12 +3,15 @@
//! let _: u32 = /* <never-to-any> */ loop {};
//! let _: &u32 = /* &* */ &mut 0;
//! ```
+use std::ops::Not;
+
use either::Either;
use hir::{
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
};
use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEditBuilder;
use span::EditionedFileId;
use stdx::never;
use syntax::{
@@ -17,8 +20,8 @@ use syntax::{
};
use crate::{
- AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
- InlayHintsConfig, InlayKind, InlayTooltip,
+ AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
+ InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip,
};
pub(super) fn hints(
@@ -51,32 +54,47 @@ pub(super) fn hints(
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
- if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
- &*adjustments
- {
- // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
- if source == target {
- return None;
- }
+ // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
+ if matches!(
+ &*adjustments,
+ [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }]
+ if source == target
+ ) {
+ return None;
}
}
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::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
+ let range = expr.syntax().text_range();
+ let mut pre = InlayHint {
+ range,
+ position: InlayHintPosition::Before,
+ pad_left: false,
+ pad_right: false,
+ kind: InlayKind::Adjustment,
+ label: InlayHintLabel::default(),
+ text_edit: None,
+ resolve_parent: Some(range),
+ };
+ let mut post = InlayHint {
+ range,
+ position: InlayHintPosition::After,
+ pad_left: false,
+ pad_right: false,
+ kind: InlayKind::Adjustment,
+ label: InlayHintLabel::default(),
+ text_edit: None,
+ resolve_parent: Some(range),
+ };
+
+ if needs_outer_parens || (postfix && needs_inner_parens) {
+ pre.label.append_str("(");
}
if postfix && needs_inner_parens {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+ post.label.append_str(")");
}
let mut iter = if postfix {
@@ -86,6 +104,7 @@ pub(super) fn hints(
};
let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
+ let mut allow_edit = !postfix;
for Adjustment { source, target, kind } in iter {
if source == target {
cov_mark::hit!(same_type_adjustment);
@@ -95,6 +114,7 @@ pub(super) fn hints(
// FIXME: Add some nicer tooltips to each of these
let (text, coercion) = match kind {
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
("<never-to-any>", "never to any")
}
Adjust::Deref(None) => ("*", "dereference"),
@@ -115,6 +135,7 @@ pub(super) fn hints(
// some of these could be represented via `as` casts, but that's not too nice and
// handling everything as a prefix expr makes the `(` and `)` insertion easier
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
match cast {
PointerCast::ReifyFnPointer => {
("<fn-item-to-fn-pointer>", "fn item to fn pointer")
@@ -138,36 +159,58 @@ pub(super) fn hints(
}
_ => continue,
};
- let label = InlayHintLabel::simple(
- if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
- Some(InlayTooltip::Markdown(format!(
+ let label = InlayHintLabelPart {
+ text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
+ linked_location: None,
+ tooltip: Some(InlayTooltip::Markdown(format!(
"`{}` → `{}` ({coercion} coercion)",
source.display(sema.db, file_id.edition()),
target.display(sema.db, file_id.edition()),
))),
- None,
- );
- acc.push(InlayHint {
- range: expr.syntax().text_range(),
- pad_left: false,
- pad_right: false,
- position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
- kind: InlayKind::Adjustment,
- label,
- text_edit: None,
- resolve_parent: Some(expr.syntax().text_range()),
- });
+ };
+ if postfix { &mut post } else { &mut pre }.label.append_part(label);
}
if !postfix && needs_inner_parens {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::Adjustment,
- expr.syntax().text_range(),
- ));
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+ pre.label.append_str("(");
+ }
+ if needs_outer_parens || (!postfix && needs_inner_parens) {
+ post.label.append_str(")");
}
- if needs_outer_parens {
- acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+
+ let mut pre = pre.label.parts.is_empty().not().then_some(pre);
+ let mut post = post.label.parts.is_empty().not().then_some(post);
+ if pre.is_none() && post.is_none() {
+ return None;
}
+ if allow_edit {
+ let edit = {
+ let mut b = TextEditBuilder::default();
+ if let Some(pre) = &pre {
+ b.insert(
+ pre.range.start(),
+ pre.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+ );
+ }
+ if let Some(post) = &post {
+ b.insert(
+ post.range.end(),
+ post.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+ );
+ }
+ b.finish()
+ };
+ match (&mut pre, &mut post) {
+ (Some(pre), Some(post)) => {
+ pre.text_edit = Some(edit.clone());
+ post.text_edit = Some(edit);
+ }
+ (Some(pre), None) => pre.text_edit = Some(edit),
+ (None, Some(post)) => post.text_edit = Some(edit),
+ (None, None) => (),
+ }
+ }
+ acc.extend(pre);
+ acc.extend(post);
Some(())
}
@@ -293,25 +336,19 @@ fn main() {
let _: u32 = loop {};
//^^^^^^^<never-to-any>
let _: &u32 = &mut 0;
- //^^^^^^&
- //^^^^^^*
+ //^^^^^^&*
let _: &mut u32 = &mut 0;
- //^^^^^^&mut $
- //^^^^^^*
+ //^^^^^^&mut *
let _: *const u32 = &mut 0;
- //^^^^^^&raw const $
- //^^^^^^*
+ //^^^^^^&raw const *
let _: *mut u32 = &mut 0;
- //^^^^^^&raw mut $
- //^^^^^^*
+ //^^^^^^&raw mut *
let _: fn() = main;
//^^^^<fn-item-to-fn-pointer>
let _: unsafe fn() = main;
- //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
- //^^^^<fn-item-to-fn-pointer>
+ //^^^^<safe-fn-pointer-to-unsafe-fn-pointer><fn-item-to-fn-pointer>
let _: unsafe fn() = main as fn();
- //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
- //^^^^^^^^^^^^(
+ //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>(
//^^^^^^^^^^^^)
//^^^^<fn-item-to-fn-pointer>
let _: fn() = || {};
@@ -319,72 +356,51 @@ fn main() {
let _: unsafe fn() = || {};
//^^^^^<closure-to-unsafe-fn-pointer>
let _: *const u32 = &mut 0u32 as *mut u32;
- //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
- //^^^^^^^^^^^^^^^^^^^^^(
+ //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>(
//^^^^^^^^^^^^^^^^^^^^^)
- //^^^^^^^^^&raw mut $
- //^^^^^^^^^*
+ //^^^^^^^^^&raw mut *
let _: &mut [_] = &mut [0; 0];
- //^^^^^^^^^^^<unsize>
- //^^^^^^^^^^^&mut $
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^<unsize>&mut *
Struct.consume();
Struct.by_ref();
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
Struct.by_ref_mut();
- //^^^^^^(
- //^^^^^^&mut $
+ //^^^^^^(&mut $
//^^^^^^)
(&Struct).consume();
//^^^^^^^*
(&Struct).by_ref();
- //^^^^^^^&
- //^^^^^^^*
+ //^^^^^^^&*
(&mut Struct).consume();
//^^^^^^^^^^^*
(&mut Struct).by_ref();
- //^^^^^^^^^^^&
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^&*
(&mut Struct).by_ref_mut();
- //^^^^^^^^^^^&mut $
- //^^^^^^^^^^^*
+ //^^^^^^^^^^^&mut *
// Check that block-like expressions don't duplicate hints
let _: &mut [u32] = (&mut []);
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = { &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = unsafe { &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut [u32] = if true {
&mut []
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
} else {
loop {}
//^^^^^^^<never-to-any>
};
let _: &mut [u32] = match () { () => &mut [] };
- //^^^^^^^<unsize>
- //^^^^^^^&mut $
- //^^^^^^^*
+ //^^^^^^^<unsize>&mut *
let _: &mut dyn Fn() = &mut || ();
- //^^^^^^^^^^<unsize>
- //^^^^^^^^^^&mut $
- //^^^^^^^^^^*
+ //^^^^^^^^^^<unsize>&mut *
() == ();
// ^^&
// ^^&
@@ -393,16 +409,13 @@ fn main() {
// ^^^^&
let closure: dyn Fn = || ();
closure();
- //^^^^^^^(
- //^^^^^^^&
+ //^^^^^^^(&
//^^^^^^^)
Struct[0];
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
&mut Struct[0];
- //^^^^^^(
- //^^^^^^&mut $
+ //^^^^^^(&mut $
//^^^^^^)
}
@@ -442,72 +455,46 @@ fn main() {
(&Struct).consume();
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
+ //^^^^^^^).*
(&Struct).by_ref();
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&
+ //^^^^^^^).*.&
(&mut Struct).consume();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
+ //^^^^^^^^^^^).*
(&mut Struct).by_ref();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
- //^^^^^^^^^^^.&
+ //^^^^^^^^^^^).*.&
(&mut Struct).by_ref_mut();
//^^^^^^^^^^^(
- //^^^^^^^^^^^)
- //^^^^^^^^^^^.*
- //^^^^^^^^^^^.&mut
+ //^^^^^^^^^^^).*.&mut
// Check that block-like expressions don't duplicate hints
let _: &mut [u32] = (&mut []);
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = { &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = unsafe { &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut [u32] = if true {
&mut []
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
} else {
loop {}
//^^^^^^^.<never-to-any>
};
let _: &mut [u32] = match () { () => &mut [] };
//^^^^^^^(
- //^^^^^^^)
- //^^^^^^^.*
- //^^^^^^^.&mut
- //^^^^^^^.<unsize>
+ //^^^^^^^).*.&mut.<unsize>
let _: &mut dyn Fn() = &mut || ();
//^^^^^^^^^^(
- //^^^^^^^^^^)
- //^^^^^^^^^^.*
- //^^^^^^^^^^.&mut
- //^^^^^^^^^^.<unsize>
+ //^^^^^^^^^^).*.&mut.<unsize>
() == ();
// ^^.&
// ^^.&
@@ -619,9 +606,7 @@ fn or_else() {
r#"
unsafe fn enabled() {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
fn disabled() {
@@ -633,9 +618,7 @@ fn mixed() {
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
}
@@ -644,9 +627,7 @@ const _: () = {
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
};
@@ -655,18 +636,14 @@ static STATIC: () = {
unsafe {
f(&&());
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
};
enum E {
Disable = { f(&&()); 0 },
Enable = unsafe { f(&&()); 1 },
- //^^^^&
- //^^^^*
- //^^^^*
+ //^^^^&**
}
const fn f(_: &()) {}
@@ -692,8 +669,7 @@ fn a() {
_ = Struct.by_ref();
_ = unsafe { Struct.by_ref() };
- //^^^^^^(
- //^^^^^^&
+ //^^^^^^(&
//^^^^^^)
}
"#,
@@ -726,10 +702,7 @@ trait T<RHS = Self> {}
fn hello(it: &&[impl T]) {
it.len();
- //^^(
- //^^&
- //^^*
- //^^*
+ //^^(&**
//^^)
}
"#,