about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs228
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs119
4 files changed, 153 insertions, 246 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 97e712356b5..fcf262877dd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index c37c469dff4..ab44d8c3b50 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/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 || (!postfix && needs_inner_parens) {
+        post.label.append_str(")");
     }
-    if needs_outer_parens {
-        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+    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 {};
                        //^^^^^^^<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 +321,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 +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
-                       //^^^^^^^.<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 +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<RHS = Self> {}
 
 fn hello(it: &&[impl T]) {
     it.len();
-  //^^(
-  //^^&
-  //^^*
-  //^^*
+  //^^(&**
   //^^)
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index d1c0677863d..beba2ad748c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/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<InlayHint>,
@@ -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/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index f399bd01d07..628ddc6154c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/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<InlayHint>,
@@ -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;
     };
 }