diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 97e712356b..fcf262877d 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -475,6 +475,18 @@ impl InlayHintLabel { } } + pub fn append_part(&mut self, part: InlayHintLabelPart) { + if part.linked_location.is_none() && part.tooltip.is_none() { + if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = + self.parts.last_mut() + { + text.push_str(&part.text); + return; + } + } + self.parts.push(part); + } + pub fn needs_resolve(&self) -> bool { self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some()) } diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index c37c469dff..ab44d8c3b5 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -17,8 +17,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( @@ -64,19 +64,34 @@ pub(super) fn hints( 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 { @@ -138,35 +153,28 @@ 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 { - acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range())); + if needs_outer_parens || (!postfix && needs_inner_parens) { + post.label.append_str(")"); + } + if !pre.label.parts.is_empty() { + acc.push(pre); + } + if !post.label.parts.is_empty() { + acc.push(post); } Some(()) } @@ -293,25 +301,19 @@ fn main() { let _: u32 = loop {}; //^^^^^^^ 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; //^^^^ let _: unsafe fn() = main; - //^^^^ - //^^^^ + //^^^^ let _: unsafe fn() = main as fn(); - //^^^^^^^^^^^^ - //^^^^^^^^^^^^( + //^^^^^^^^^^^^( //^^^^^^^^^^^^) //^^^^ let _: fn() = || {}; @@ -319,72 +321,51 @@ fn main() { let _: unsafe fn() = || {}; //^^^^^ let _: *const u32 = &mut 0u32 as *mut u32; - //^^^^^^^^^^^^^^^^^^^^^ - //^^^^^^^^^^^^^^^^^^^^^( + //^^^^^^^^^^^^^^^^^^^^^( //^^^^^^^^^^^^^^^^^^^^^) - //^^^^^^^^^&raw mut $ - //^^^^^^^^^* + //^^^^^^^^^&raw mut * let _: &mut [_] = &mut [0; 0]; - //^^^^^^^^^^^ - //^^^^^^^^^^^&mut $ - //^^^^^^^^^^^* + //^^^^^^^^^^^&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 []); - //^^^^^^^ - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^&mut * let _: &mut [u32] = { &mut [] }; - //^^^^^^^ - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^&mut * let _: &mut [u32] = unsafe { &mut [] }; - //^^^^^^^ - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^&mut * let _: &mut [u32] = if true { &mut [] - //^^^^^^^ - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^&mut * } else { loop {} //^^^^^^^ }; let _: &mut [u32] = match () { () => &mut [] }; - //^^^^^^^ - //^^^^^^^&mut $ - //^^^^^^^* + //^^^^^^^&mut * let _: &mut dyn Fn() = &mut || (); - //^^^^^^^^^^ - //^^^^^^^^^^&mut $ - //^^^^^^^^^^* + //^^^^^^^^^^&mut * () == (); // ^^& // ^^& @@ -393,16 +374,13 @@ fn main() { // ^^^^& let closure: dyn Fn = || (); closure(); - //^^^^^^^( - //^^^^^^^& + //^^^^^^^(& //^^^^^^^) Struct[0]; - //^^^^^^( - //^^^^^^& + //^^^^^^(& //^^^^^^) &mut Struct[0]; - //^^^^^^( - //^^^^^^&mut $ + //^^^^^^(&mut $ //^^^^^^) } @@ -442,72 +420,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 - //^^^^^^^. + //^^^^^^^).*.&mut. let _: &mut [u32] = { &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^. + //^^^^^^^).*.&mut. let _: &mut [u32] = unsafe { &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^. + //^^^^^^^).*.&mut. let _: &mut [u32] = if true { &mut [] //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^. + //^^^^^^^).*.&mut. } else { loop {} //^^^^^^^. }; let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^( - //^^^^^^^) - //^^^^^^^.* - //^^^^^^^.&mut - //^^^^^^^. + //^^^^^^^).*.&mut. let _: &mut dyn Fn() = &mut || (); //^^^^^^^^^^( - //^^^^^^^^^^) - //^^^^^^^^^^.* - //^^^^^^^^^^.&mut - //^^^^^^^^^^. + //^^^^^^^^^^).*.&mut. () == (); // ^^.& // ^^.& @@ -619,9 +571,7 @@ fn or_else() { r#" unsafe fn enabled() { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } fn disabled() { @@ -633,9 +583,7 @@ fn mixed() { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } } @@ -644,9 +592,7 @@ const _: () = { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } }; @@ -655,18 +601,14 @@ static STATIC: () = { unsafe { f(&&()); - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } }; enum E { Disable = { f(&&()); 0 }, Enable = unsafe { f(&&()); 1 }, - //^^^^& - //^^^^* - //^^^^* + //^^^^&** } const fn f(_: &()) {} @@ -692,8 +634,7 @@ fn a() { _ = Struct.by_ref(); _ = unsafe { Struct.by_ref() }; - //^^^^^^( - //^^^^^^& + //^^^^^^(& //^^^^^^) } "#, @@ -726,10 +667,7 @@ trait T {} fn hello(it: &&[impl T]) { it.len(); - //^^( - //^^& - //^^* - //^^* + //^^(&** //^^) } "#, diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs index d1c0677863..beba2ad748 100644 --- a/crates/ide/src/inlay_hints/binding_mode.rs +++ b/crates/ide/src/inlay_hints/binding_mode.rs @@ -2,13 +2,15 @@ //! ```no_run //! let /* & */ (/* ref */ x,) = &(0,); //! ``` +use std::mem; + use hir::Mutability; use ide_db::famous_defs::FamousDefs; use span::EditionedFileId; use syntax::ast::{self, AstNode}; -use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind}; +use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; pub(super) fn hints( acc: &mut Vec, @@ -42,7 +44,18 @@ pub(super) fn hints( }, |it| it.syntax().text_range(), ); + let mut hint = InlayHint { + range, + kind: InlayKind::BindingMode, + label: InlayHintLabel::default(), + text_edit: None, + position: InlayHintPosition::Before, + pad_left: false, + pad_right: false, + resolve_parent: Some(pat.syntax().text_range()), + }; let pattern_adjustments = sema.pattern_adjustments(pat); + let mut was_mut_last = false; pattern_adjustments.iter().for_each(|ty| { let reference = ty.is_reference(); let mut_reference = ty.is_mutable_reference(); @@ -51,17 +64,15 @@ pub(super) fn hints( (true, false) => "&", _ => return, }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingMode, - label: r.into(), - text_edit: None, - position: InlayHintPosition::Before, - pad_left: false, - pad_right: mut_reference, - resolve_parent: Some(pat.syntax().text_range()), - }); + if mem::replace(&mut was_mut_last, mut_reference) { + hint.label.append_str(" "); + } + hint.label.append_str(r); }); + hint.pad_right = was_mut_last; + if !hint.label.parts.is_empty() { + acc.push(hint); + } match pat { ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { let bm = sema.binding_mode_of_pat(pat)?; @@ -117,6 +128,13 @@ fn __( (x,): &mut (u32,) //^^^^&mut //^ ref mut + (x,): &mut &mut (u32,) + //^^^^&mut &mut + //^ ref mut + (x,): &&(u32,) + //^^^^&& + //^ ref + ) { let (x,) = (0,); let (x,) = &(0,); diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs index f399bd01d0..628ddc6154 100644 --- a/crates/ide/src/inlay_hints/closure_captures.rs +++ b/crates/ide/src/inlay_hints/closure_captures.rs @@ -7,7 +7,9 @@ use stdx::{never, TupleExt}; use syntax::ast::{self, AstNode}; use text_edit::{TextRange, TextSize}; -use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; +use crate::{ + InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind, +}; pub(super) fn hints( acc: &mut Vec, @@ -27,34 +29,27 @@ pub(super) fn hints( return None; } - let move_kw_range = match closure.move_token() { - Some(t) => t.text_range(), + let (range, label) = match closure.move_token() { + Some(t) => (t.text_range(), InlayHintLabel::default()), None => { - let range = closure.syntax().first_token()?.prev_token()?.text_range(); - let range = TextRange::new(range.end() - TextSize::from(1), range.end()); - acc.push(InlayHint { - range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from("move"), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: Some(closure.syntax().text_range()), - }); - range + let prev_token = closure.syntax().first_token()?.prev_token()?.text_range(); + ( + TextRange::new(prev_token.end() - TextSize::from(1), prev_token.end()), + InlayHintLabel::from("move"), + ) } }; - acc.push(InlayHint { - range: move_kw_range, + let mut hint = InlayHint { + range, kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from("("), + label, text_edit: None, position: InlayHintPosition::After, pad_left: false, - pad_right: false, - resolve_parent: None, - }); + pad_right: true, + resolve_parent: Some(closure.syntax().text_range()), + }; + hint.label.append_str("("); let last = captures.len() - 1; for (idx, capture) in captures.into_iter().enumerate() { let local = capture.local(); @@ -76,48 +71,20 @@ pub(super) fn hints( if never!(label.is_empty()) { continue; } - let label = InlayHintLabel::simple( - label, - None, - source.name().and_then(|name| { + hint.label.append_part(InlayHintLabelPart { + text: label, + linked_location: source.name().and_then(|name| { name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into) }), - ); - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label, - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: Some(closure.syntax().text_range()), + tooltip: None, }); if idx != last { - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from(", "), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: false, - resolve_parent: None, - }); + hint.label.append_str(", "); } } - acc.push(InlayHint { - range: move_kw_range, - kind: InlayKind::ClosureCapture, - label: InlayHintLabel::from(")"), - text_edit: None, - position: InlayHintPosition::After, - pad_left: false, - pad_right: true, - resolve_parent: None, - }); - + hint.label.append_str(")"); + acc.push(hint); Some(()) } @@ -147,51 +114,25 @@ fn main() { let mut baz = NonCopy; let qux = &mut NonCopy; || { -// ^ move -// ^ ( -// ^ &foo -// ^ , $ -// ^ bar -// ^ , $ -// ^ baz -// ^ , $ -// ^ qux -// ^ ) +// ^ move(&foo, bar, baz, qux) foo; bar; baz; qux; }; || { -// ^ move -// ^ ( -// ^ &foo -// ^ , $ -// ^ &bar -// ^ , $ -// ^ &baz -// ^ , $ -// ^ &qux -// ^ ) +// ^ move(&foo, &bar, &baz, &qux) &foo; &bar; &baz; &qux; }; || { -// ^ move -// ^ ( -// ^ &mut baz -// ^ ) +// ^ move(&mut baz) &mut baz; }; || { -// ^ move -// ^ ( -// ^ &mut baz -// ^ , $ -// ^ &mut *qux -// ^ ) +// ^ move(&mut baz, &mut *qux) baz = NonCopy; *qux = NonCopy; }; @@ -209,9 +150,7 @@ fn main() { fn main() { let foo = u32; move || { -// ^^^^ ( -// ^^^^ foo -// ^^^^ ) +// ^^^^ (foo) foo; }; }