about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ide/Cargo.toml1
-rw-r--r--crates/ide/src/inlay_hints.rs117
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs49
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs34
-rw-r--r--crates/ide/src/inlay_hints/binding_mode.rs26
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs192
-rw-r--r--crates/ide/src/inlay_hints/closing_brace.rs9
-rw-r--r--crates/ide/src/inlay_hints/closure_ret.rs7
-rw-r--r--crates/ide/src/inlay_hints/discriminant.rs25
-rw-r--r--crates/ide/src/inlay_hints/fn_lifetime_fn.rs11
-rw-r--r--crates/ide/src/inlay_hints/implicit_static.rs5
-rw-r--r--crates/ide/src/inlay_hints/param_name.rs11
-rw-r--r--crates/ide/src/lib.rs3
-rw-r--r--crates/rust-analyzer/src/handlers.rs50
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs7
-rw-r--r--crates/rust-analyzer/src/to_proto.rs203
-rw-r--r--docs/dev/lsp-extensions.md2
18 files changed, 282 insertions, 471 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5f426d88562..13d8d40ddd3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -645,6 +645,7 @@ dependencies = [
  "profile",
  "pulldown-cmark",
  "pulldown-cmark-to-cmark",
+ "smallvec",
  "stdx",
  "syntax",
  "test-utils",
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 73f202630f1..397383bc3a0 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -20,6 +20,7 @@ pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.1", default-features = false }
 url = "2.3.1"
 dot = "0.1.4"
+smallvec = "1.10.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 48a7bbfecff..861bf1c66cb 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -7,10 +7,11 @@ use either::Either;
 use hir::{known, HasVisibility, HirDisplay, HirWrite, ModuleDef, ModuleDefId, Semantics};
 use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
 use itertools::Itertools;
+use smallvec::{smallvec, SmallVec};
 use stdx::never;
 use syntax::{
     ast::{self, AstNode},
-    match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize,
+    match_ast, NodeOrToken, SyntaxNode, TextRange,
 };
 
 use crate::{navigation_target::TryToNav, FileId};
@@ -83,75 +84,108 @@ pub enum AdjustmentHintsMode {
     PreferPostfix,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum InlayKind {
-    BindingModeHint,
-    ChainingHint,
-    ClosingBraceHint,
-    ClosureReturnTypeHint,
-    GenericParamListHint,
-    AdjustmentHint,
-    AdjustmentHintPostfix,
-    LifetimeHint,
-    ParameterHint,
-    TypeHint,
-    DiscriminantHint,
+    BindingMode,
+    Chaining,
+    ClosingBrace,
+    ClosureReturnType,
+    GenericParamList,
+    Adjustment,
+    AdjustmentPostfix,
+    Lifetime,
+    Parameter,
+    Type,
+    Discriminant,
     OpeningParenthesis,
     ClosingParenthesis,
 }
 
 #[derive(Debug)]
 pub struct InlayHint {
+    /// The text range this inlay hint applies to.
     pub range: TextRange,
+    /// The kind of this inlay hint. This is used to determine side and padding of the hint for
+    /// rendering purposes.
     pub kind: InlayKind,
+    /// The actual label to show in the inlay hint.
     pub label: InlayHintLabel,
-    pub tooltip: Option<InlayTooltip>,
+}
+
+impl InlayHint {
+    fn closing_paren(range: TextRange) -> InlayHint {
+        InlayHint { range, kind: InlayKind::ClosingParenthesis, label: InlayHintLabel::from(")") }
+    }
+    fn opening_paren(range: TextRange) -> InlayHint {
+        InlayHint { range, kind: InlayKind::OpeningParenthesis, label: InlayHintLabel::from("(") }
+    }
 }
 
 #[derive(Debug)]
 pub enum InlayTooltip {
     String(String),
-    HoverRanged(FileId, TextRange),
-    HoverOffset(FileId, TextSize),
+    Markdown(String),
 }
 
 #[derive(Default)]
 pub struct InlayHintLabel {
-    pub parts: Vec<InlayHintLabelPart>,
+    pub parts: SmallVec<[InlayHintLabelPart; 1]>,
 }
 
 impl InlayHintLabel {
-    pub fn as_simple_str(&self) -> Option<&str> {
-        match &*self.parts {
-            [part] => part.as_simple_str(),
-            _ => None,
+    pub fn simple(
+        s: impl Into<String>,
+        tooltip: Option<InlayTooltip>,
+        linked_location: Option<FileRange>,
+    ) -> InlayHintLabel {
+        InlayHintLabel {
+            parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }],
         }
     }
 
     pub fn prepend_str(&mut self, s: &str) {
         match &mut *self.parts {
-            [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
-            _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
+            [InlayHintLabelPart { text, linked_location: None, tooltip: None }, ..] => {
+                text.insert_str(0, s)
+            }
+            _ => self.parts.insert(
+                0,
+                InlayHintLabelPart { text: s.into(), linked_location: None, tooltip: None },
+            ),
         }
     }
 
     pub fn append_str(&mut self, s: &str) {
         match &mut *self.parts {
-            [.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
-            _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
+            [.., InlayHintLabelPart { text, linked_location: None, tooltip: None }] => {
+                text.push_str(s)
+            }
+            _ => self.parts.push(InlayHintLabelPart {
+                text: s.into(),
+                linked_location: None,
+                tooltip: None,
+            }),
         }
     }
 }
 
 impl From<String> for InlayHintLabel {
     fn from(s: String) -> Self {
-        Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
+        Self {
+            parts: smallvec![InlayHintLabelPart { text: s, linked_location: None, tooltip: None }],
+        }
     }
 }
 
 impl From<&str> for InlayHintLabel {
     fn from(s: &str) -> Self {
-        Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] }
+        Self {
+            parts: smallvec![InlayHintLabelPart {
+                text: s.into(),
+                linked_location: None,
+                tooltip: None
+            }],
+        }
     }
 }
 
@@ -175,25 +209,25 @@ pub struct InlayHintLabelPart {
     /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
     /// them both.
     pub linked_location: Option<FileRange>,
-}
-
-impl InlayHintLabelPart {
-    pub fn as_simple_str(&self) -> Option<&str> {
-        match self {
-            Self { text, linked_location: None } => Some(text),
-            _ => None,
-        }
-    }
+    /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
+    /// hover requests to show.
+    pub tooltip: Option<InlayTooltip>,
 }
 
 impl fmt::Debug for InlayHintLabelPart {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.as_simple_str() {
-            Some(string) => string.fmt(f),
-            None => f
+        match self {
+            Self { text, linked_location: None, tooltip: None } => text.fmt(f),
+            Self { text, linked_location, tooltip } => f
                 .debug_struct("InlayHintLabelPart")
-                .field("text", &self.text)
-                .field("linked_location", &self.linked_location)
+                .field("text", text)
+                .field("linked_location", linked_location)
+                .field(
+                    "tooltip",
+                    &tooltip.as_ref().map_or("", |it| match it {
+                        InlayTooltip::String(it) | InlayTooltip::Markdown(it) => it,
+                    }),
+                )
                 .finish(),
         }
     }
@@ -242,6 +276,7 @@ impl InlayHintLabelBuilder<'_> {
         self.result.parts.push(InlayHintLabelPart {
             text: take(&mut self.last_part),
             linked_location: self.location.take(),
+            tooltip: None,
         });
     }
 
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index bdd7c05e008..581813f3b77 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -44,27 +44,12 @@ pub(super) fn hints(
         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,
-            label: "(".into(),
-            tooltip: None,
-        });
+        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
     }
 
     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,
-        });
+        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
     }
 
     let (mut tmp0, mut tmp1);
@@ -112,36 +97,16 @@ pub(super) fn hints(
         };
         acc.push(InlayHint {
             range: expr.syntax().text_range(),
-            kind: if postfix {
-                InlayKind::AdjustmentHintPostfix
-            } else {
-                InlayKind::AdjustmentHint
-            },
+            kind: if postfix { InlayKind::AdjustmentPostfix } else { InlayKind::Adjustment },
             label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() },
-            tooltip: None,
         });
     }
     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,
-        });
+        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
     }
     if needs_outer_parens {
-        acc.push(InlayHint {
-            range: expr.syntax().text_range(),
-            kind: InlayKind::ClosingParenthesis,
-            label: ")".into(),
-            tooltip: None,
-        });
+        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
     }
     Some(())
 }
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index adec19c765a..5227c651ff4 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -12,9 +12,7 @@ use syntax::{
     match_ast,
 };
 
-use crate::{
-    inlay_hints::closure_has_block_body, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip,
-};
+use crate::{inlay_hints::closure_has_block_body, InlayHint, InlayHintsConfig, InlayKind};
 
 use super::label_of_ty;
 
@@ -22,7 +20,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: FileId,
+    _file_id: FileId,
     pat: &ast::IdentPat,
 ) -> Option<()> {
     if !config.type_hints {
@@ -50,12 +48,8 @@ pub(super) fn hints(
             Some(name) => name.syntax().text_range(),
             None => pat.syntax().text_range(),
         },
-        kind: InlayKind::TypeHint,
+        kind: InlayKind::Type,
         label,
-        tooltip: pat
-            .name()
-            .map(|it| it.syntax().text_range())
-            .map(|it| InlayTooltip::HoverRanged(file_id, it)),
     });
 
     Some(())
@@ -322,22 +316,14 @@ fn main(a: SliceIter<'_, Container>) {
                 [
                     InlayHint {
                         range: 484..554,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "impl Iterator<Item = impl Iterator<Item = &&str>>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                484..554,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 484..485,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -350,6 +336,7 @@ fn main(a: SliceIter<'_, Container>) {
                                         range: 289..298,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "<",
                             InlayHintLabelPart {
@@ -362,17 +349,10 @@ fn main(a: SliceIter<'_, Container>) {
                                         range: 238..247,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             ">",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                484..485,
-                            ),
-                        ),
                     },
                 ]
             "#]],
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index a0166d0048a..11b9cd269bf 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -7,7 +7,7 @@ use ide_db::RootDatabase;
 
 use syntax::ast::{self, AstNode};
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
+use crate::{InlayHint, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -40,12 +40,7 @@ pub(super) fn hints(
             (true, false) => "&",
             _ => return,
         };
-        acc.push(InlayHint {
-            range,
-            kind: InlayKind::BindingModeHint,
-            label: r.to_string().into(),
-            tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
-        });
+        acc.push(InlayHint { range, kind: InlayKind::BindingMode, label: r.to_string().into() });
     });
     match pat {
         ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
@@ -57,24 +52,13 @@ pub(super) fn hints(
             };
             acc.push(InlayHint {
                 range: pat.syntax().text_range(),
-                kind: InlayKind::BindingModeHint,
+                kind: InlayKind::BindingMode,
                 label: bm.to_string().into(),
-                tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
             });
         }
         ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
-            acc.push(InlayHint {
-                range: pat.syntax().text_range(),
-                kind: InlayKind::OpeningParenthesis,
-                label: "(".into(),
-                tooltip: None,
-            });
-            acc.push(InlayHint {
-                range: pat.syntax().text_range(),
-                kind: InlayKind::ClosingParenthesis,
-                label: ")".into(),
-                tooltip: None,
-            });
+            acc.push(InlayHint::opening_paren(pat.syntax().text_range()));
+            acc.push(InlayHint::closing_paren(pat.syntax().text_range()));
         }
         _ => (),
     }
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index 8810d5d34db..e0045a53d74 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -5,7 +5,7 @@ use syntax::{
     Direction, NodeOrToken, SyntaxKind, T,
 };
 
-use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
+use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind};
 
 use super::label_of_ty;
 
@@ -13,7 +13,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: FileId,
+    _file_id: FileId,
     expr: &ast::Expr,
 ) -> Option<()> {
     if !config.chaining_hints {
@@ -59,9 +59,8 @@ pub(super) fn hints(
             }
             acc.push(InlayHint {
                 range: expr.syntax().text_range(),
-                kind: InlayKind::ChainingHint,
+                kind: InlayKind::Chaining,
                 label: label_of_ty(famous_defs, config, ty)?,
-                tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
             });
         }
     }
@@ -111,7 +110,7 @@ fn main() {
                 [
                     InlayHint {
                         range: 147..172,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -124,21 +123,14 @@ fn main() {
                                         range: 63..64,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                147..172,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 147..154,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -151,17 +143,10 @@ fn main() {
                                         range: 7..8,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                147..154,
-                            ),
-                        ),
                     },
                 ]
             "#]],
@@ -210,33 +195,17 @@ fn main() {
                 [
                     InlayHint {
                         range: 143..190,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "C",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                143..190,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 143..179,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "B",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                143..179,
-                            ),
-                        ),
                     },
                 ]
             "#]],
@@ -269,7 +238,7 @@ fn main() {
                 [
                     InlayHint {
                         range: 143..190,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -282,21 +251,14 @@ fn main() {
                                         range: 51..52,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                143..190,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 143..179,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -309,17 +271,10 @@ fn main() {
                                         range: 29..30,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                143..179,
-                            ),
-                        ),
                     },
                 ]
             "#]],
@@ -353,7 +308,7 @@ fn main() {
                 [
                     InlayHint {
                         range: 246..283,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -366,6 +321,7 @@ fn main() {
                                         range: 23..24,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "<",
                             InlayHintLabelPart {
@@ -378,21 +334,14 @@ fn main() {
                                         range: 55..56,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "<i32, bool>>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                246..283,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 246..265,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -405,6 +354,7 @@ fn main() {
                                         range: 7..8,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "<",
                             InlayHintLabelPart {
@@ -417,17 +367,10 @@ fn main() {
                                         range: 55..56,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "<i32, bool>>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                246..265,
-                            ),
-                        ),
                     },
                 ]
             "#]],
@@ -463,52 +406,28 @@ fn main() {
                 [
                     InlayHint {
                         range: 174..241,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "impl Iterator<Item = ()>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                174..241,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 174..224,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "impl Iterator<Item = ()>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                174..224,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 174..206,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "impl Iterator<Item = ()>",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                174..206,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 174..189,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "&mut ",
                             InlayHintLabelPart {
@@ -521,17 +440,10 @@ fn main() {
                                         range: 24..30,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                174..189,
-                            ),
-                        ),
                     },
                 ]
             "#]],
@@ -564,7 +476,7 @@ fn main() {
                 [
                     InlayHint {
                         range: 124..130,
-                        kind: TypeHint,
+                        kind: Type,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -577,21 +489,14 @@ fn main() {
                                         range: 7..13,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                124..130,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 145..185,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -604,21 +509,14 @@ fn main() {
                                         range: 7..13,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                145..185,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 145..168,
-                        kind: ChainingHint,
+                        kind: Chaining,
                         label: [
                             "",
                             InlayHintLabelPart {
@@ -631,32 +529,28 @@ fn main() {
                                         range: 7..13,
                                     },
                                 ),
+                                tooltip: "",
                             },
                             "",
                         ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                145..168,
-                            ),
-                        ),
                     },
                     InlayHint {
                         range: 222..228,
-                        kind: ParameterHint,
+                        kind: Parameter,
                         label: [
-                            "self",
-                        ],
-                        tooltip: Some(
-                            HoverOffset(
-                                FileId(
-                                    0,
+                            InlayHintLabelPart {
+                                text: "self",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            0,
+                                        ),
+                                        range: 42..46,
+                                    },
                                 ),
-                                42,
-                            ),
-                        ),
+                                tooltip: "",
+                            },
+                        ],
                     },
                 ]
             "#]],
diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs
index e340c64c54b..aae805f78d6 100644
--- a/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/crates/ide/src/inlay_hints/closing_brace.rs
@@ -10,9 +10,7 @@ use syntax::{
     match_ast, SyntaxKind, SyntaxNode, T,
 };
 
-use crate::{
-    inlay_hints::InlayHintLabelPart, FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
-};
+use crate::{FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -115,9 +113,8 @@ pub(super) fn hints(
         .flatten();
     acc.push(InlayHint {
         range: closing_token.text_range(),
-        kind: InlayKind::ClosingBraceHint,
-        label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] },
-        tooltip: None, // provided by label part location
+        kind: InlayKind::ClosingBrace,
+        label: InlayHintLabel::simple(label, None, linked_location),
     });
 
     None
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index d9929beaac0..f03a18b8e96 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -4,7 +4,7 @@ use syntax::ast::{self, AstNode};
 
 use crate::{
     inlay_hints::closure_has_block_body, ClosureReturnTypeHints, InlayHint, InlayHintsConfig,
-    InlayKind, InlayTooltip,
+    InlayKind,
 };
 
 use super::label_of_ty;
@@ -13,7 +13,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: FileId,
+    _file_id: FileId,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if config.closure_return_type_hints == ClosureReturnTypeHints::Never {
@@ -41,9 +41,8 @@ pub(super) fn hints(
     }
     acc.push(InlayHint {
         range: param_list.syntax().text_range(),
-        kind: InlayKind::ClosureReturnTypeHint,
+        kind: InlayKind::ClosureReturnType,
         label: label_of_ty(famous_defs, config, ty)?,
-        tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
     });
     Some(())
 }
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index f32c4bdf288..310295cc379 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -7,7 +7,9 @@
 use ide_db::{base_db::FileId, famous_defs::FamousDefs};
 use syntax::ast::{self, AstNode, HasName};
 
-use crate::{DiscriminantHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
+use crate::{
+    DiscriminantHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip,
+};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -41,15 +43,18 @@ pub(super) fn hints(
             Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()),
             None => name.syntax().text_range(),
         },
-        kind: InlayKind::DiscriminantHint,
-        label: match &d {
-            Ok(v) => format!("{}", v).into(),
-            Err(_) => "?".into(),
-        },
-        tooltip: Some(InlayTooltip::String(match &d {
-            Ok(_) => "enum variant discriminant".into(),
-            Err(e) => format!("{e:?}").into(),
-        })),
+        kind: InlayKind::Discriminant,
+        label: InlayHintLabel::simple(
+            match &d {
+                Ok(v) => format!("{}", v),
+                Err(_) => "?".into(),
+            },
+            Some(InlayTooltip::String(match &d {
+                Ok(_) => "enum variant discriminant".into(),
+                Err(e) => format!("{e:?}").into(),
+            })),
+            None,
+        ),
     });
 
     Some(())
diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
index 2aa5e3dc734..b7182085b31 100644
--- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
+++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
@@ -10,7 +10,7 @@ use syntax::{
     SyntaxToken,
 };
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints};
+use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -23,9 +23,8 @@ pub(super) fn hints(
 
     let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
         range: t.text_range(),
-        kind: InlayKind::LifetimeHint,
+        kind: InlayKind::Lifetime,
         label: label.into(),
-        tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
     };
 
     let param_list = func.param_list()?;
@@ -183,21 +182,19 @@ pub(super) fn hints(
             let is_empty = gpl.generic_params().next().is_none();
             acc.push(InlayHint {
                 range: angle_tok.text_range(),
-                kind: InlayKind::LifetimeHint,
+                kind: InlayKind::Lifetime,
                 label: format!(
                     "{}{}",
                     allocated_lifetimes.iter().format(", "),
                     if is_empty { "" } else { ", " }
                 )
                 .into(),
-                tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
             });
         }
         (None, allocated_lifetimes) => acc.push(InlayHint {
             range: func.name()?.syntax().text_range(),
-            kind: InlayKind::GenericParamListHint,
+            kind: InlayKind::GenericParamList,
             label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
-            tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
         }),
     }
     Some(())
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index 588a0e3b6a4..1122ee2e392 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -8,7 +8,7 @@ use syntax::{
     SyntaxKind,
 };
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints};
+use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -32,9 +32,8 @@ pub(super) fn hints(
             let t = ty.amp_token()?;
             acc.push(InlayHint {
                 range: t.text_range(),
-                kind: InlayKind::LifetimeHint,
+                kind: InlayKind::Lifetime,
                 label: "'static".to_owned().into(),
-                tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
             });
         }
     }
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index ecee67632e3..9cdae632410 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -10,7 +10,7 @@ use ide_db::{base_db::FileRange, RootDatabase};
 use stdx::to_lower_snake_case;
 use syntax::ast::{self, AstNode, HasArgList, HasName, UnaryOp};
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
+use crate::{InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -43,21 +43,20 @@ pub(super) fn hints(
             !should_hide_param_name_hint(sema, &callable, param_name, arg)
         })
         .map(|(param, param_name, _, FileRange { range, .. })| {
-            let mut tooltip = None;
+            let mut linked_location = None;
             if let Some(name) = param {
                 if let hir::CallableKind::Function(f) = callable.kind() {
                     // assert the file is cached so we can map out of macros
                     if let Some(_) = sema.source(f) {
-                        tooltip = sema.original_range_opt(name.syntax());
+                        linked_location = sema.original_range_opt(name.syntax());
                     }
                 }
             }
 
             InlayHint {
                 range,
-                kind: InlayKind::ParameterHint,
-                label: param_name.into(),
-                tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
+                kind: InlayKind::Parameter,
+                label: InlayHintLabel::simple(param_name, None, linked_location),
             }
         });
 
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 239456cb281..8424d82aa18 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -82,7 +82,8 @@ pub use crate::{
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
-        InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+        InlayHintLabel, InlayHintLabelPart, InlayHintsConfig, InlayKind, InlayTooltip,
+        LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 59bdd306127..033ef75cca0 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -29,7 +29,6 @@ use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
-use tracing::error;
 use vfs::AbsPathBuf;
 
 use crate::{
@@ -1360,55 +1359,10 @@ pub(crate) fn handle_inlay_hints(
 }
 
 pub(crate) fn handle_inlay_hints_resolve(
-    snap: GlobalStateSnapshot,
-    mut hint: InlayHint,
+    _snap: GlobalStateSnapshot,
+    hint: InlayHint,
 ) -> Result<InlayHint> {
     let _p = profile::span("handle_inlay_hints_resolve");
-    let data = match hint.data.take() {
-        Some(it) => it,
-        None => return Ok(hint),
-    };
-
-    let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
-
-    match snap.url_file_version(&resolve_data.text_document.uri) {
-        Some(version) if version == resolve_data.text_document.version => {}
-        Some(version) => {
-            error!(
-                "attempted inlayHints/resolve of '{}' at version {} while server version is {}",
-                resolve_data.text_document.uri, resolve_data.text_document.version, version,
-            );
-            return Ok(hint);
-        }
-        None => {
-            error!(
-                "attempted inlayHints/resolve of unknown file '{}' at version {}",
-                resolve_data.text_document.uri, resolve_data.text_document.version,
-            );
-            return Ok(hint);
-        }
-    }
-    let file_range = from_proto::file_range_uri(
-        &snap,
-        &resolve_data.text_document.uri,
-        match resolve_data.position {
-            PositionOrRange::Position(pos) => Range::new(pos, pos),
-            PositionOrRange::Range(range) => range,
-        },
-    )?;
-    let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
-        None => return Ok(hint),
-        Some(info) => info,
-    };
-
-    let markup_kind =
-        snap.config.hover().documentation.map_or(ide::HoverDocFormat::Markdown, |kind| kind);
-
-    // FIXME: hover actions?
-    hint.tooltip = Some(lsp_types::InlayHintTooltip::MarkupContent(to_proto::markup_content(
-        info.info.markup,
-        markup_kind,
-    )));
     Ok(hint)
 }
 
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 65620b4209b..b117acd1b0f 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -3,11 +3,11 @@
 use std::{collections::HashMap, path::PathBuf};
 
 use lsp_types::request::Request;
+use lsp_types::PositionEncodingKind;
 use lsp_types::{
     notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
     PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
 };
-use lsp_types::{PositionEncodingKind, VersionedTextDocumentIdentifier};
 use serde::{Deserialize, Serialize};
 
 pub enum AnalyzerStatus {}
@@ -568,10 +568,7 @@ pub struct CompletionResolveData {
 }
 
 #[derive(Debug, Serialize, Deserialize)]
-pub struct InlayHintResolveData {
-    pub text_document: VersionedTextDocumentIdentifier,
-    pub position: PositionOrRange,
-}
+pub struct InlayHintResolveData {}
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct CompletionImport {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index e736b2ff9a3..0f0642bb4b5 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -9,9 +9,9 @@ use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
-    InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
-    Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
-    TextSize,
+    InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory,
+    RenameError, Runnable, Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind,
+    TextEdit, TextRange, TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -431,137 +431,140 @@ pub(crate) fn inlay_hint(
     mut inlay_hint: InlayHint,
 ) -> Cancellable<lsp_types::InlayHint> {
     match inlay_hint.kind {
-        InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
-        InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
-        InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
-        InlayKind::DiscriminantHint => inlay_hint.label.prepend_str(" = "),
+        InlayKind::Parameter if render_colons => inlay_hint.label.append_str(":"),
+        InlayKind::Type if render_colons => inlay_hint.label.prepend_str(": "),
+        InlayKind::ClosureReturnType => inlay_hint.label.prepend_str(" -> "),
+        InlayKind::Discriminant => inlay_hint.label.prepend_str(" = "),
         _ => {}
     }
 
+    let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?;
+
     Ok(lsp_types::InlayHint {
         position: match inlay_hint.kind {
             // before annotated thing
             InlayKind::OpeningParenthesis
-            | InlayKind::ParameterHint
-            | InlayKind::AdjustmentHint
-            | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
+            | InlayKind::Parameter
+            | InlayKind::Adjustment
+            | InlayKind::BindingMode => position(line_index, inlay_hint.range.start()),
             // after annotated thing
-            InlayKind::ClosureReturnTypeHint
-            | InlayKind::TypeHint
-            | InlayKind::DiscriminantHint
-            | InlayKind::ChainingHint
-            | InlayKind::GenericParamListHint
+            InlayKind::ClosureReturnType
+            | InlayKind::Type
+            | InlayKind::Discriminant
+            | InlayKind::Chaining
+            | InlayKind::GenericParamList
             | InlayKind::ClosingParenthesis
-            | InlayKind::AdjustmentHintPostfix
-            | InlayKind::LifetimeHint
-            | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
+            | InlayKind::AdjustmentPostfix
+            | InlayKind::Lifetime
+            | InlayKind::ClosingBrace => position(line_index, inlay_hint.range.end()),
         },
         padding_left: Some(match inlay_hint.kind {
-            InlayKind::TypeHint => !render_colons,
-            InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
+            InlayKind::Type => !render_colons,
+            InlayKind::Chaining | InlayKind::ClosingBrace => true,
             InlayKind::ClosingParenthesis
-            | InlayKind::DiscriminantHint
+            | InlayKind::Discriminant
             | InlayKind::OpeningParenthesis
-            | InlayKind::BindingModeHint
-            | InlayKind::ClosureReturnTypeHint
-            | InlayKind::GenericParamListHint
-            | InlayKind::AdjustmentHint
-            | InlayKind::AdjustmentHintPostfix
-            | InlayKind::LifetimeHint
-            | InlayKind::ParameterHint => false,
+            | InlayKind::BindingMode
+            | InlayKind::ClosureReturnType
+            | InlayKind::GenericParamList
+            | InlayKind::Adjustment
+            | InlayKind::AdjustmentPostfix
+            | InlayKind::Lifetime
+            | InlayKind::Parameter => false,
         }),
         padding_right: Some(match inlay_hint.kind {
             InlayKind::ClosingParenthesis
             | InlayKind::OpeningParenthesis
-            | InlayKind::ChainingHint
-            | InlayKind::ClosureReturnTypeHint
-            | InlayKind::GenericParamListHint
-            | InlayKind::AdjustmentHint
-            | InlayKind::AdjustmentHintPostfix
-            | InlayKind::TypeHint
-            | InlayKind::DiscriminantHint
-            | InlayKind::ClosingBraceHint => false,
-            InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
-            InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
+            | InlayKind::Chaining
+            | InlayKind::ClosureReturnType
+            | InlayKind::GenericParamList
+            | InlayKind::Adjustment
+            | InlayKind::AdjustmentPostfix
+            | InlayKind::Type
+            | InlayKind::Discriminant
+            | InlayKind::ClosingBrace => false,
+            InlayKind::BindingMode => {
+                matches!(&label, lsp_types::InlayHintLabel::String(s) if s != "&")
+            }
+            InlayKind::Parameter | InlayKind::Lifetime => true,
         }),
         kind: match inlay_hint.kind {
-            InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
-            InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
+            InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER),
+            InlayKind::ClosureReturnType | InlayKind::Type | InlayKind::Chaining => {
                 Some(lsp_types::InlayHintKind::TYPE)
             }
             InlayKind::ClosingParenthesis
-            | InlayKind::DiscriminantHint
+            | InlayKind::Discriminant
             | InlayKind::OpeningParenthesis
-            | InlayKind::BindingModeHint
-            | InlayKind::GenericParamListHint
-            | InlayKind::LifetimeHint
-            | InlayKind::AdjustmentHint
-            | InlayKind::AdjustmentHintPostfix
-            | InlayKind::ClosingBraceHint => None,
+            | InlayKind::BindingMode
+            | InlayKind::GenericParamList
+            | InlayKind::Lifetime
+            | InlayKind::Adjustment
+            | InlayKind::AdjustmentPostfix
+            | InlayKind::ClosingBrace => None,
         },
         text_edits: None,
-        data: (|| match inlay_hint.tooltip {
-            Some(ide::InlayTooltip::HoverOffset(file_id, offset)) => {
-                let uri = url(snap, file_id);
-                let line_index = snap.file_line_index(file_id).ok()?;
-
-                let text_document = lsp_types::VersionedTextDocumentIdentifier {
-                    version: snap.url_file_version(&uri)?,
-                    uri,
-                };
-                to_value(lsp_ext::InlayHintResolveData {
-                    text_document,
-                    position: lsp_ext::PositionOrRange::Position(position(&line_index, offset)),
-                })
-                .ok()
-            }
-            Some(ide::InlayTooltip::HoverRanged(file_id, text_range)) => {
-                let uri = url(snap, file_id);
-                let text_document = lsp_types::VersionedTextDocumentIdentifier {
-                    version: snap.url_file_version(&uri)?,
-                    uri,
-                };
-                let line_index = snap.file_line_index(file_id).ok()?;
-                to_value(lsp_ext::InlayHintResolveData {
-                    text_document,
-                    position: lsp_ext::PositionOrRange::Range(range(&line_index, text_range)),
-                })
-                .ok()
-            }
-            _ => None,
-        })(),
-        tooltip: Some(match inlay_hint.tooltip {
-            Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
-            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
-        }),
-        label: inlay_hint_label(snap, inlay_hint.label)?,
+        data: None,
+        tooltip,
+        label,
     })
 }
 
 fn inlay_hint_label(
     snap: &GlobalStateSnapshot,
-    label: InlayHintLabel,
-) -> Cancellable<lsp_types::InlayHintLabel> {
-    Ok(match label.as_simple_str() {
-        Some(s) => lsp_types::InlayHintLabel::String(s.into()),
-        None => lsp_types::InlayHintLabel::LabelParts(
-            label
+    mut label: InlayHintLabel,
+) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> {
+    let res = match &*label.parts {
+        [InlayHintLabelPart { linked_location: None, .. }] => {
+            let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
+            (
+                lsp_types::InlayHintLabel::String(text),
+                match tooltip {
+                    Some(ide::InlayTooltip::String(s)) => {
+                        Some(lsp_types::InlayHintTooltip::String(s))
+                    }
+                    Some(ide::InlayTooltip::Markdown(s)) => {
+                        Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
+                            kind: lsp_types::MarkupKind::Markdown,
+                            value: s,
+                        }))
+                    }
+                    None => None,
+                },
+            )
+        }
+        _ => {
+            let parts = label
                 .parts
                 .into_iter()
                 .map(|part| {
-                    Ok(lsp_types::InlayHintLabelPart {
-                        value: part.text,
-                        tooltip: None,
-                        location: part
-                            .linked_location
-                            .map(|range| location(snap, range))
-                            .transpose()?,
-                        command: None,
-                    })
+                    part.linked_location.map(|range| location(snap, range)).transpose().map(
+                        |location| lsp_types::InlayHintLabelPart {
+                            value: part.text,
+                            tooltip: match part.tooltip {
+                                Some(ide::InlayTooltip::String(s)) => {
+                                    Some(lsp_types::InlayHintLabelPartTooltip::String(s))
+                                }
+                                Some(ide::InlayTooltip::Markdown(s)) => {
+                                    Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
+                                        lsp_types::MarkupContent {
+                                            kind: lsp_types::MarkupKind::Markdown,
+                                            value: s,
+                                        },
+                                    ))
+                                }
+                                None => None,
+                            },
+                            location,
+                            command: None,
+                        },
+                    )
                 })
-                .collect::<Cancellable<Vec<_>>>()?,
-        ),
-    })
+                .collect::<Cancellable<_>>()?;
+            (lsp_types::InlayHintLabel::LabelParts(parts), None)
+        }
+    };
+    Ok(res)
 }
 
 static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a4780af1a26..0f24ddbbc00 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: 45bd7985265725c5
+lsp_ext.rs hash: d296ce1226e3568d
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue: