Skip to content

Commit 97fa2a7

Browse files
committed
fix: panics in inlay hints that produce empty text edits for closure return types
1 parent 723121e commit 97fa2a7

File tree

3 files changed

+31
-41
lines changed

3 files changed

+31
-41
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir::{
88
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
99
HirWrite, ModuleDef, ModuleDefId, Semantics, sym,
1010
};
11-
use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs};
11+
use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
1212
use ide_db::{FxHashSet, text_edit::TextEdit};
1313
use itertools::Itertools;
1414
use smallvec::{SmallVec, smallvec};
@@ -813,7 +813,8 @@ fn ty_to_text_edit(
813813
config: &InlayHintsConfig,
814814
node_for_hint: &SyntaxNode,
815815
ty: &hir::Type,
816-
offset_to_insert: TextSize,
816+
offset_to_insert_ty: TextSize,
817+
additional_edits: &dyn Fn(&mut TextEditBuilder),
817818
prefix: impl Into<String>,
818819
) -> Option<LazyProperty<TextEdit>> {
819820
// FIXME: Limit the length and bail out on excess somehow?
@@ -822,8 +823,11 @@ fn ty_to_text_edit(
822823
.and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?;
823824
Some(config.lazy_text_edit(|| {
824825
let mut builder = TextEdit::builder();
825-
builder.insert(offset_to_insert, prefix.into());
826-
builder.insert(offset_to_insert, rendered);
826+
builder.insert(offset_to_insert_ty, prefix.into());
827+
builder.insert(offset_to_insert_ty, rendered);
828+
829+
additional_edits(&mut builder);
830+
827831
builder.finish()
828832
}))
829833
}

crates/ide/src/inlay_hints/bind_pat.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub(super) fn hints(
8787
.as_ref()
8888
.map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
8989
.end(),
90+
&|_| (),
9091
if colon_token.is_some() { "" } else { ": " },
9192
)
9293
} else {

crates/ide/src/inlay_hints/closure_ret.rs

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Implementation of "closure return type" inlay hints.
22
//!
33
//! Tests live in [`bind_pat`][super::bind_pat] module.
4-
use hir::{DisplayTarget, HirDisplay};
5-
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
4+
use hir::DisplayTarget;
5+
use ide_db::{famous_defs::FamousDefs, text_edit::TextEditBuilder};
66
use syntax::ast::{self, AstNode};
77

88
use crate::{
@@ -49,45 +49,30 @@ pub(super) fn hints(
4949
if arrow.is_none() {
5050
label.prepend_str(" -> ");
5151
}
52-
let text_edit = if has_block_body {
53-
ty_to_text_edit(
54-
sema,
55-
config,
56-
descended_closure.syntax(),
57-
&ty,
58-
arrow
59-
.as_ref()
60-
.map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
61-
.end(),
62-
if arrow.is_none() { " -> " } else { "" },
63-
)
64-
} else {
65-
Some(config.lazy_text_edit(|| {
66-
let body = closure.body();
67-
let body_range = match body {
68-
Some(body) => body.syntax().text_range(),
69-
None => return TextEdit::builder().finish(),
70-
};
71-
let mut builder = TextEdit::builder();
72-
let insert_pos = param_list.syntax().text_range().end();
7352

74-
let rendered = match sema.scope(descended_closure.syntax()).and_then(|scope| {
75-
ty.display_source_code(scope.db, scope.module().into(), false).ok()
76-
}) {
77-
Some(rendered) => rendered,
78-
None => return TextEdit::builder().finish(),
79-
};
53+
let offset_to_insert_ty =
54+
arrow.as_ref().map_or_else(|| param_list.syntax().text_range(), |t| t.text_range()).end();
8055

81-
let arrow_text = if arrow.is_none() { " -> ".to_owned() } else { "".to_owned() };
82-
builder.insert(insert_pos, arrow_text);
83-
builder.insert(insert_pos, rendered);
84-
builder.insert(body_range.start(), "{ ".to_owned());
85-
builder.insert(body_range.end(), " }".to_owned());
86-
87-
builder.finish()
88-
}))
56+
// Insert braces if necessary
57+
let insert_braces = |builder: &mut TextEditBuilder| {
58+
if !has_block_body {
59+
if let Some(range) = closure.body().map(|b| b.syntax().text_range()) {
60+
builder.insert(range.start(), "{ ".to_owned());
61+
builder.insert(range.end(), " }".to_owned());
62+
}
63+
}
8964
};
9065

66+
let text_edit = ty_to_text_edit(
67+
sema,
68+
config,
69+
descended_closure.syntax(),
70+
&ty,
71+
offset_to_insert_ty,
72+
&insert_braces,
73+
if arrow.is_none() { " -> " } else { "" },
74+
);
75+
9176
acc.push(InlayHint {
9277
range: param_list.syntax().text_range(),
9378
kind: InlayKind::Type,

0 commit comments

Comments
 (0)