Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit f40c7d8

Browse files
committed
Auto merge of rust-lang#16822 - Veykril:inlays, r=Veykril
fix: Make inlay hint resolving work better for inlays targetting the same position
2 parents f6e2895 + 4a93368 commit f40c7d8

19 files changed

+114
-91
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
fmt::{self, Write},
3+
hash::{BuildHasher, BuildHasherDefault},
34
mem::take,
45
};
56

@@ -8,7 +9,7 @@ use hir::{
89
known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
910
ModuleDefId, Semantics,
1011
};
11-
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
12+
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, FxHasher, RootDatabase};
1213
use itertools::Itertools;
1314
use smallvec::{smallvec, SmallVec};
1415
use stdx::never;
@@ -116,7 +117,7 @@ pub enum AdjustmentHintsMode {
116117
PreferPostfix,
117118
}
118119

119-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
120+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
120121
pub enum InlayKind {
121122
Adjustment,
122123
BindingMode,
@@ -132,7 +133,7 @@ pub enum InlayKind {
132133
RangeExclusive,
133134
}
134135

135-
#[derive(Debug)]
136+
#[derive(Debug, Hash)]
136137
pub enum InlayHintPosition {
137138
Before,
138139
After,
@@ -151,13 +152,23 @@ pub struct InlayHint {
151152
pub label: InlayHintLabel,
152153
/// Text edit to apply when "accepting" this inlay hint.
153154
pub text_edit: Option<TextEdit>,
154-
pub needs_resolve: bool,
155+
}
156+
157+
impl std::hash::Hash for InlayHint {
158+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159+
self.range.hash(state);
160+
self.position.hash(state);
161+
self.pad_left.hash(state);
162+
self.pad_right.hash(state);
163+
self.kind.hash(state);
164+
self.label.hash(state);
165+
self.text_edit.is_some().hash(state);
166+
}
155167
}
156168

157169
impl InlayHint {
158170
fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
159171
InlayHint {
160-
needs_resolve: false,
161172
range,
162173
kind,
163174
label: InlayHintLabel::from(")"),
@@ -167,9 +178,9 @@ impl InlayHint {
167178
pad_right: false,
168179
}
169180
}
181+
170182
fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
171183
InlayHint {
172-
needs_resolve: false,
173184
range,
174185
kind,
175186
label: InlayHintLabel::from("("),
@@ -179,15 +190,19 @@ impl InlayHint {
179190
pad_right: false,
180191
}
181192
}
193+
194+
pub fn needs_resolve(&self) -> bool {
195+
self.text_edit.is_some() || self.label.needs_resolve()
196+
}
182197
}
183198

184-
#[derive(Debug)]
199+
#[derive(Debug, Hash)]
185200
pub enum InlayTooltip {
186201
String(String),
187202
Markdown(String),
188203
}
189204

190-
#[derive(Default)]
205+
#[derive(Default, Hash)]
191206
pub struct InlayHintLabel {
192207
pub parts: SmallVec<[InlayHintLabelPart; 1]>,
193208
}
@@ -265,6 +280,7 @@ impl fmt::Debug for InlayHintLabel {
265280
}
266281
}
267282

283+
#[derive(Hash)]
268284
pub struct InlayHintLabelPart {
269285
pub text: String,
270286
/// Source location represented by this label part. The client will use this to fetch the part's
@@ -313,9 +329,7 @@ impl fmt::Write for InlayHintLabelBuilder<'_> {
313329

314330
impl HirWrite for InlayHintLabelBuilder<'_> {
315331
fn start_location_link(&mut self, def: ModuleDefId) {
316-
if self.location.is_some() {
317-
never!("location link is already started");
318-
}
332+
never!(self.location.is_some(), "location link is already started");
319333
self.make_new_part();
320334
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
321335
let location = location.call_site();
@@ -425,11 +439,6 @@ fn ty_to_text_edit(
425439
Some(builder.finish())
426440
}
427441

428-
pub enum RangeLimit {
429-
Fixed(TextRange),
430-
NearestParent(TextSize),
431-
}
432-
433442
// Feature: Inlay Hints
434443
//
435444
// rust-analyzer shows additional information inline with the source code.
@@ -451,7 +460,7 @@ pub enum RangeLimit {
451460
pub(crate) fn inlay_hints(
452461
db: &RootDatabase,
453462
file_id: FileId,
454-
range_limit: Option<RangeLimit>,
463+
range_limit: Option<TextRange>,
455464
config: &InlayHintsConfig,
456465
) -> Vec<InlayHint> {
457466
let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
@@ -466,38 +475,53 @@ pub(crate) fn inlay_hints(
466475

467476
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
468477
match range_limit {
469-
Some(RangeLimit::Fixed(range)) => match file.covering_element(range) {
478+
Some(range) => match file.covering_element(range) {
470479
NodeOrToken::Token(_) => return acc,
471480
NodeOrToken::Node(n) => n
472481
.descendants()
473482
.filter(|descendant| range.intersect(descendant.text_range()).is_some())
474483
.for_each(hints),
475484
},
476-
Some(RangeLimit::NearestParent(position)) => {
477-
match file.token_at_offset(position).left_biased() {
478-
Some(token) => {
479-
if let Some(parent_block) =
480-
token.parent_ancestors().find_map(ast::BlockExpr::cast)
481-
{
482-
parent_block.syntax().descendants().for_each(hints)
483-
} else if let Some(parent_item) =
484-
token.parent_ancestors().find_map(ast::Item::cast)
485-
{
486-
parent_item.syntax().descendants().for_each(hints)
487-
} else {
488-
return acc;
489-
}
490-
}
491-
None => return acc,
492-
}
493-
}
494485
None => file.descendants().for_each(hints),
495486
};
496487
}
497488

498489
acc
499490
}
500491

492+
pub(crate) fn inlay_hints_resolve(
493+
db: &RootDatabase,
494+
file_id: FileId,
495+
position: TextSize,
496+
hash: u64,
497+
config: &InlayHintsConfig,
498+
) -> Option<InlayHint> {
499+
let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
500+
let sema = Semantics::new(db);
501+
let file = sema.parse(file_id);
502+
let file = file.syntax();
503+
504+
let scope = sema.scope(file)?;
505+
let famous_defs = FamousDefs(&sema, scope.krate());
506+
let mut acc = Vec::new();
507+
508+
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
509+
match file.token_at_offset(position).left_biased() {
510+
Some(token) => {
511+
if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) {
512+
parent_block.syntax().descendants().for_each(hints)
513+
} else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) {
514+
parent_item.syntax().descendants().for_each(hints)
515+
} else {
516+
return None;
517+
}
518+
}
519+
None => return None,
520+
}
521+
522+
acc.into_iter().find(|hint| BuildHasherDefault::<FxHasher>::default().hash_one(hint) == hash)
523+
}
524+
501525
fn hints(
502526
hints: &mut Vec<InlayHint>,
503527
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,

crates/ide/src/inlay_hints/adjustment.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ pub(super) fn hints(
147147
None,
148148
);
149149
acc.push(InlayHint {
150-
needs_resolve: label.needs_resolve(),
151150
range: expr.syntax().text_range(),
152151
pad_left: false,
153152
pad_right: false,

crates/ide/src/inlay_hints/bind_pat.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ pub(super) fn hints(
9999
None => pat.syntax().text_range(),
100100
};
101101
acc.push(InlayHint {
102-
needs_resolve: label.needs_resolve() || text_edit.is_some(),
103102
range: match type_ascriptable {
104103
Some(Some(t)) => text_range.cover(t.text_range()),
105104
_ => text_range,
@@ -177,11 +176,7 @@ mod tests {
177176
use syntax::{TextRange, TextSize};
178177
use test_utils::extract_annotations;
179178

180-
use crate::{
181-
fixture,
182-
inlay_hints::{InlayHintsConfig, RangeLimit},
183-
ClosureReturnTypeHints,
184-
};
179+
use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints};
185180

186181
use crate::inlay_hints::tests::{
187182
check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
@@ -404,7 +399,7 @@ fn main() {
404399
.inlay_hints(
405400
&InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
406401
file_id,
407-
Some(RangeLimit::Fixed(TextRange::new(TextSize::from(500), TextSize::from(600)))),
402+
Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
408403
)
409404
.unwrap();
410405
let actual =

crates/ide/src/inlay_hints/binding_mode.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ pub(super) fn hints(
5050
_ => return,
5151
};
5252
acc.push(InlayHint {
53-
needs_resolve: false,
5453
range,
5554
kind: InlayKind::BindingMode,
5655
label: r.into(),
@@ -69,7 +68,6 @@ pub(super) fn hints(
6968
hir::BindingMode::Ref(Mutability::Shared) => "ref",
7069
};
7170
acc.push(InlayHint {
72-
needs_resolve: false,
7371
range: pat.syntax().text_range(),
7472
kind: InlayKind::BindingMode,
7573
label: bm.into(),

crates/ide/src/inlay_hints/chaining.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ pub(super) fn hints(
5959
}
6060
let label = label_of_ty(famous_defs, config, &ty)?;
6161
acc.push(InlayHint {
62-
needs_resolve: label.needs_resolve(),
6362
range: expr.syntax().text_range(),
6463
kind: InlayKind::Chaining,
6564
label,

crates/ide/src/inlay_hints/closing_brace.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ pub(super) fn hints(
109109

110110
let linked_location = name_range.map(|range| FileRange { file_id, range });
111111
acc.push(InlayHint {
112-
needs_resolve: linked_location.is_some(),
113112
range: closing_token.text_range(),
114113
kind: InlayKind::ClosingBrace,
115114
label: InlayHintLabel::simple(label, None, linked_location),

crates/ide/src/inlay_hints/closure_captures.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ pub(super) fn hints(
3232
let range = closure.syntax().first_token()?.prev_token()?.text_range();
3333
let range = TextRange::new(range.end() - TextSize::from(1), range.end());
3434
acc.push(InlayHint {
35-
needs_resolve: false,
3635
range,
3736
kind: InlayKind::ClosureCapture,
3837
label: InlayHintLabel::from("move"),
@@ -45,7 +44,6 @@ pub(super) fn hints(
4544
}
4645
};
4746
acc.push(InlayHint {
48-
needs_resolve: false,
4947
range: move_kw_range,
5048
kind: InlayKind::ClosureCapture,
5149
label: InlayHintLabel::from("("),
@@ -79,7 +77,6 @@ pub(super) fn hints(
7977
}),
8078
);
8179
acc.push(InlayHint {
82-
needs_resolve: label.needs_resolve(),
8380
range: move_kw_range,
8481
kind: InlayKind::ClosureCapture,
8582
label,
@@ -91,7 +88,6 @@ pub(super) fn hints(
9188

9289
if idx != last {
9390
acc.push(InlayHint {
94-
needs_resolve: false,
9591
range: move_kw_range,
9692
kind: InlayKind::ClosureCapture,
9793
label: InlayHintLabel::from(", "),
@@ -103,7 +99,6 @@ pub(super) fn hints(
10399
}
104100
}
105101
acc.push(InlayHint {
106-
needs_resolve: false,
107102
range: move_kw_range,
108103
kind: InlayKind::ClosureCapture,
109104
label: InlayHintLabel::from(")"),

crates/ide/src/inlay_hints/closure_ret.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ pub(super) fn hints(
6464
};
6565

6666
acc.push(InlayHint {
67-
needs_resolve: label.needs_resolve() || text_edit.is_some(),
6867
range: param_list.syntax().text_range(),
6968
kind: InlayKind::Type,
7069
label,

crates/ide/src/inlay_hints/discriminant.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ fn variant_hints(
7979
None,
8080
);
8181
acc.push(InlayHint {
82-
needs_resolve: label.needs_resolve(),
8382
range: match eq_token {
8483
Some(t) => range.cover(t.text_range()),
8584
_ => range,

crates/ide/src/inlay_hints/fn_lifetime_fn.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ pub(super) fn hints(
2222
}
2323

2424
let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
25-
needs_resolve: false,
2625
range: t.text_range(),
2726
kind: InlayKind::Lifetime,
2827
label: label.into(),
@@ -184,7 +183,6 @@ pub(super) fn hints(
184183
let angle_tok = gpl.l_angle_token()?;
185184
let is_empty = gpl.generic_params().next().is_none();
186185
acc.push(InlayHint {
187-
needs_resolve: false,
188186
range: angle_tok.text_range(),
189187
kind: InlayKind::Lifetime,
190188
label: format!(
@@ -200,7 +198,6 @@ pub(super) fn hints(
200198
});
201199
}
202200
(None, allocated_lifetimes) => acc.push(InlayHint {
203-
needs_resolve: false,
204201
range: func.name()?.syntax().text_range(),
205202
kind: InlayKind::GenericParamList,
206203
label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),

crates/ide/src/inlay_hints/implicit_drop.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ pub(super) fn hints(
105105
pad_left: true,
106106
pad_right: true,
107107
kind: InlayKind::Drop,
108-
needs_resolve: label.needs_resolve(),
109108
label,
110109
text_edit: None,
111110
})

crates/ide/src/inlay_hints/implicit_static.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ pub(super) fn hints(
3131
if ty.lifetime().is_none() {
3232
let t = ty.amp_token()?;
3333
acc.push(InlayHint {
34-
needs_resolve: false,
3534
range: t.text_range(),
3635
kind: InlayKind::Lifetime,
3736
label: "'static".into(),

crates/ide/src/inlay_hints/param_name.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ pub(super) fn hints(
5757
let label =
5858
InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
5959
InlayHint {
60-
needs_resolve: label.needs_resolve(),
6160
range,
6261
kind: InlayKind::Parameter,
6362
label,

crates/ide/src/inlay_hints/range_exclusive.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint {
3030
kind: crate::InlayKind::RangeExclusive,
3131
label: crate::InlayHintLabel::from("<"),
3232
text_edit: None,
33-
needs_resolve: false,
3433
}
3534
}
3635

0 commit comments

Comments
 (0)