Skip to content

Commit 2c5c12a

Browse files
committed
fix: Fix inlay hint resolution being broken
1 parent ff9ebc7 commit 2c5c12a

File tree

8 files changed

+89
-37
lines changed

8 files changed

+89
-37
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{
22
fmt::{self, Write},
3-
hash::{BuildHasher, BuildHasherDefault},
43
mem::take,
54
};
65

@@ -9,7 +8,7 @@ use hir::{
98
known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
109
ModuleDefId, Semantics,
1110
};
12-
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, FxHasher, RootDatabase};
11+
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
1312
use itertools::Itertools;
1413
use smallvec::{smallvec, SmallVec};
1514
use stdx::never;
@@ -495,6 +494,7 @@ pub(crate) fn inlay_hints_resolve(
495494
position: TextSize,
496495
hash: u64,
497496
config: &InlayHintsConfig,
497+
hasher: impl Fn(&InlayHint) -> u64,
498498
) -> Option<InlayHint> {
499499
let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
500500
let sema = Semantics::new(db);
@@ -506,20 +506,16 @@ pub(crate) fn inlay_hints_resolve(
506506
let mut acc = Vec::new();
507507

508508
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,
509+
let token = file.token_at_offset(position).left_biased()?;
510+
if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) {
511+
parent_block.syntax().descendants().for_each(hints)
512+
} else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) {
513+
parent_item.syntax().descendants().for_each(hints)
514+
} else {
515+
return None;
520516
}
521517

522-
acc.into_iter().find(|hint| BuildHasherDefault::<FxHasher>::default().hash_one(hint) == hash)
518+
acc.into_iter().find(|hint| hasher(hint) == hash)
523519
}
524520

525521
fn hints(

crates/ide/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ mod view_item_tree;
5858
mod view_memory_layout;
5959
mod view_mir;
6060

61+
use std::panic::UnwindSafe;
62+
6163
use cfg::CfgOptions;
6264
use fetch_crates::CrateInfo;
6365
use hir::ChangeWithProcMacros;
@@ -428,8 +430,11 @@ impl Analysis {
428430
file_id: FileId,
429431
position: TextSize,
430432
hash: u64,
433+
hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe,
431434
) -> Cancellable<Option<InlayHint>> {
432-
self.with_db(|db| inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config))
435+
self.with_db(|db| {
436+
inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config, hasher)
437+
})
433438
}
434439

435440
/// Returns the set of folding ranges.

crates/rust-analyzer/src/handlers/request.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,11 +1508,18 @@ pub(crate) fn handle_inlay_hints_resolve(
15081508
file_id,
15091509
hint_position,
15101510
resolve_data.hash,
1511+
|hint| {
1512+
std::hash::BuildHasher::hash_one(
1513+
&std::hash::BuildHasherDefault::<ide_db::FxHasher>::default(),
1514+
hint,
1515+
)
1516+
// json only supports numbers up to 2^53 - 1 as integers, so mask the rest
1517+
& ((1 << 53) - 1)
1518+
},
15111519
)?;
15121520

1513-
let mut resolved_hints = resolve_hints
1514-
.into_iter()
1515-
.filter_map(|it| {
1521+
Ok(resolve_hints
1522+
.and_then(|it| {
15161523
to_proto::inlay_hint(
15171524
&snap,
15181525
&forced_resolve_inlay_hints_config.fields_to_resolve,
@@ -1523,13 +1530,8 @@ pub(crate) fn handle_inlay_hints_resolve(
15231530
.ok()
15241531
})
15251532
.filter(|hint| hint.position == original_hint.position)
1526-
.filter(|hint| hint.kind == original_hint.kind);
1527-
if let Some(resolved_hint) = resolved_hints.next() {
1528-
if resolved_hints.next().is_none() {
1529-
return Ok(resolved_hint);
1530-
}
1531-
}
1532-
Ok(original_hint)
1533+
.filter(|hint| hint.kind == original_hint.kind)
1534+
.unwrap_or(original_hint))
15331535
}
15341536

15351537
pub(crate) fn handle_call_hierarchy_prepare(

crates/rust-analyzer/src/lsp/ext.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -463,13 +463,6 @@ pub struct TestInfo {
463463
pub runnable: Runnable,
464464
}
465465

466-
#[derive(Serialize, Deserialize, Debug)]
467-
#[serde(rename_all = "camelCase")]
468-
pub struct InlayHintsParams {
469-
pub text_document: TextDocumentIdentifier,
470-
pub range: Option<lsp_types::Range>,
471-
}
472-
473466
pub enum Ssr {}
474467

475468
impl Request for Ssr {

crates/rust-analyzer/src/lsp/to_proto.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ pub(crate) fn inlay_hint(
453453
&std::hash::BuildHasherDefault::<FxHasher>::default(),
454454
&inlay_hint,
455455
)
456+
// json only supports numbers up to 2^53 - 1 as integers, so mask the rest
457+
& ((1 << 53) - 1)
456458
});
457459

458460
let mut something_to_resolve = false;

crates/rust-analyzer/tests/slow-tests/main.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ use lsp_types::{
2323
notification::DidOpenTextDocument,
2424
request::{
2525
CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest,
26-
WillRenameFiles, WorkspaceSymbolRequest,
26+
InlayHintRequest, InlayHintResolveRequest, WillRenameFiles, WorkspaceSymbolRequest,
2727
},
2828
CodeActionContext, CodeActionParams, CompletionParams, DidOpenTextDocumentParams,
2929
DocumentFormattingParams, FileRename, FormattingOptions, GotoDefinitionParams, HoverParams,
30-
PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem,
31-
TextDocumentPositionParams, WorkDoneProgressParams,
30+
InlayHint, InlayHintLabel, InlayHintParams, PartialResultParams, Position, Range,
31+
RenameFilesParams, TextDocumentItem, TextDocumentPositionParams, WorkDoneProgressParams,
3232
};
3333
use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams, UnindexedProject};
3434
use serde_json::json;
@@ -75,6 +75,48 @@ use std::collections::Spam;
7575
assert!(res.to_string().contains("HashMap"));
7676
}
7777

78+
#[test]
79+
fn resolves_inlay_hints() {
80+
if skip_slow_tests() {
81+
return;
82+
}
83+
84+
let server = Project::with_fixture(
85+
r#"
86+
//- /Cargo.toml
87+
[package]
88+
name = "foo"
89+
version = "0.0.0"
90+
91+
//- /src/lib.rs
92+
struct Foo;
93+
fn f() {
94+
let x = Foo;
95+
}
96+
"#,
97+
)
98+
.server()
99+
.wait_until_workspace_is_loaded();
100+
101+
let res = server.send_request::<InlayHintRequest>(InlayHintParams {
102+
range: Range::new(Position::new(0, 0), Position::new(3, 1)),
103+
text_document: server.doc_id("src/lib.rs"),
104+
work_done_progress_params: WorkDoneProgressParams::default(),
105+
});
106+
let mut hints = serde_json::from_value::<Option<Vec<InlayHint>>>(res).unwrap().unwrap();
107+
let hint = hints.pop().unwrap();
108+
assert!(hint.data.is_some());
109+
assert!(
110+
matches!(&hint.label, InlayHintLabel::LabelParts(parts) if parts[1].location.is_none())
111+
);
112+
let res = server.send_request::<InlayHintResolveRequest>(hint);
113+
let hint = serde_json::from_value::<InlayHint>(res).unwrap();
114+
assert!(hint.data.is_none());
115+
assert!(
116+
matches!(&hint.label, InlayHintLabel::LabelParts(parts) if parts[1].location.is_some())
117+
);
118+
}
119+
78120
#[test]
79121
fn test_runnables_project() {
80122
if skip_slow_tests() {

crates/rust-analyzer/tests/slow-tests/support.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ impl Project<'_> {
159159
content_format: Some(vec![lsp_types::MarkupKind::Markdown]),
160160
..Default::default()
161161
}),
162+
inlay_hint: Some(lsp_types::InlayHintClientCapabilities {
163+
resolve_support: Some(lsp_types::InlayHintResolveClientCapabilities {
164+
properties: vec![
165+
"textEdits".to_owned(),
166+
"tooltip".to_owned(),
167+
"label.tooltip".to_owned(),
168+
"label.location".to_owned(),
169+
"label.command".to_owned(),
170+
],
171+
}),
172+
..Default::default()
173+
}),
162174
..Default::default()
163175
}),
164176
window: Some(lsp_types::WindowClientCapabilities {

docs/dev/lsp-extensions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!---
2-
lsp/ext.rs hash: 223f48a89a5126a0
2+
lsp/ext.rs hash: 4aacf4cca1c9ff5e
33
44
If you need to change the above hash to make the test pass, please check if you
55
need to adjust this doc as well and ping this issue:
@@ -444,7 +444,7 @@ interface DiscoverTestResults {
444444
// For each file which its uri is in this list, the response
445445
// contains all tests that are located in this file, and
446446
// client should remove old tests not included in the response.
447-
scopeFile: lc.TextDocumentIdentifier[] | undefined;
447+
scopeFile: lc.TextDocumentIdentifier[] | undefined;
448448
}
449449
```
450450

0 commit comments

Comments
 (0)