Skip to content

Commit 0808ade

Browse files
bors[bot]dimbleby
andauthored
Merge #11182
11182: fix: don't panic on seeing an unexpected offset r=Veykril a=dimbleby Intended as a fix, or at least a sticking plaster, for #11081. I have arranged that [offset()](https://github.com/rust-analyzer/rust-analyzer/blob/1ba9a924d7b161c52e605e157ee16d582e4a8684/crates/ide_db/src/line_index.rs#L105-L107) returns `Option<TextSize>` instead of going out of bounds; other changes are the result of following the compiler after doing this. Perhaps there's still an issue here - I suppose the server and client have gotten out of sync and that probably shouldn't happen in the first place? I see that #10138 (comment) suggests what sounds like a more substantial fix which I think might be aimed in this direction. So perhaps that one should be left open to cover such things? Meanwhile, I hope that not-crashing is a good improvement: and I can confirm that it works out just fine in the repro I have at #11081. Co-authored-by: David Hotham <[email protected]>
2 parents 66870ca + b7cabf1 commit 0808ade

File tree

4 files changed

+38
-30
lines changed

4 files changed

+38
-30
lines changed

crates/ide_db/src/line_index.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,10 @@ impl LineIndex {
102102
LineCol { line: line as u32, col: col.into() }
103103
}
104104

105-
pub fn offset(&self, line_col: LineCol) -> TextSize {
106-
self.newlines[line_col.line as usize] + TextSize::from(line_col.col)
105+
pub fn offset(&self, line_col: LineCol) -> Option<TextSize> {
106+
self.newlines
107+
.get(line_col.line as usize)
108+
.map(|offset| offset + TextSize::from(line_col.col))
107109
}
108110

109111
pub fn to_utf16(&self, line_col: LineCol) -> LineColUtf16 {

crates/rust-analyzer/src/from_proto.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Conversion lsp_types types to rust-analyzer specific ones.
2+
use anyhow::format_err;
23
use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16};
34
use ide_db::base_db::{FileId, FilePosition, FileRange};
45
use syntax::{TextRange, TextSize};
@@ -22,7 +23,7 @@ pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
2223
abs_path(url).map(vfs::VfsPath::from)
2324
}
2425

25-
pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
26+
pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result<TextSize> {
2627
let line_col = match line_index.encoding {
2728
OffsetEncoding::Utf8 => {
2829
LineCol { line: position.line as u32, col: position.character as u32 }
@@ -33,13 +34,16 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> T
3334
line_index.index.to_utf8(line_col)
3435
}
3536
};
36-
line_index.index.offset(line_col)
37+
let text_size =
38+
line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?;
39+
Ok(text_size)
3740
}
3841

39-
pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
40-
let start = offset(line_index, range.start);
41-
let end = offset(line_index, range.end);
42-
TextRange::new(start, end)
42+
pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result<TextRange> {
43+
let start = offset(line_index, range.start)?;
44+
let end = offset(line_index, range.end)?;
45+
let text_range = TextRange::new(start, end);
46+
Ok(text_range)
4347
}
4448

4549
pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
@@ -52,7 +56,7 @@ pub(crate) fn file_position(
5256
) -> Result<FilePosition> {
5357
let file_id = file_id(snap, &tdpp.text_document.uri)?;
5458
let line_index = snap.file_line_index(file_id)?;
55-
let offset = offset(&line_index, tdpp.position);
59+
let offset = offset(&line_index, tdpp.position)?;
5660
Ok(FilePosition { file_id, offset })
5761
}
5862

@@ -63,7 +67,7 @@ pub(crate) fn file_range(
6367
) -> Result<FileRange> {
6468
let file_id = file_id(snap, &text_document_identifier.uri)?;
6569
let line_index = snap.file_line_index(file_id)?;
66-
let range = text_range(&line_index, range);
70+
let range = text_range(&line_index, range)?;
6771
Ok(FileRange { file_id, range })
6872
}
6973

@@ -96,7 +100,7 @@ pub(crate) fn annotation(
96100
let line_index = snap.file_line_index(file_id)?;
97101

98102
Ok(Annotation {
99-
range: text_range(&line_index, code_lens.range),
103+
range: text_range(&line_index, code_lens.range)?,
100104
kind: AnnotationKind::HasImpls {
101105
position: file_position(snap, params.text_document_position_params)?,
102106
data: None,
@@ -108,7 +112,7 @@ pub(crate) fn annotation(
108112
let line_index = snap.file_line_index(file_id)?;
109113

110114
Ok(Annotation {
111-
range: text_range(&line_index, code_lens.range),
115+
range: text_range(&line_index, code_lens.range)?,
112116
kind: AnnotationKind::HasReferences {
113117
position: file_position(snap, params)?,
114118
data: None,

crates/rust-analyzer/src/handlers.rs

+17-16
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub(crate) fn handle_syntax_tree(
108108
let _p = profile::span("handle_syntax_tree");
109109
let id = from_proto::file_id(&snap, &params.text_document.uri)?;
110110
let line_index = snap.file_line_index(id)?;
111-
let text_range = params.range.map(|r| from_proto::text_range(&line_index, r));
111+
let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok());
112112
let res = snap.analysis.syntax_tree(id, text_range)?;
113113
Ok(res)
114114
}
@@ -149,7 +149,7 @@ pub(crate) fn handle_expand_macro(
149149
let _p = profile::span("handle_expand_macro");
150150
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
151151
let line_index = snap.file_line_index(file_id)?;
152-
let offset = from_proto::offset(&line_index, params.position);
152+
let offset = from_proto::offset(&line_index, params.position)?;
153153

154154
let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?;
155155
Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion }))
@@ -166,7 +166,7 @@ pub(crate) fn handle_selection_range(
166166
.positions
167167
.into_iter()
168168
.map(|position| {
169-
let offset = from_proto::offset(&line_index, position);
169+
let offset = from_proto::offset(&line_index, position)?;
170170
let mut ranges = Vec::new();
171171
{
172172
let mut range = TextRange::new(offset, offset);
@@ -205,19 +205,20 @@ pub(crate) fn handle_matching_brace(
205205
let _p = profile::span("handle_matching_brace");
206206
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
207207
let line_index = snap.file_line_index(file_id)?;
208-
let res = params
208+
params
209209
.positions
210210
.into_iter()
211211
.map(|position| {
212212
let offset = from_proto::offset(&line_index, position);
213-
let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) {
214-
Ok(Some(matching_brace_offset)) => matching_brace_offset,
215-
Err(_) | Ok(None) => offset,
216-
};
217-
to_proto::position(&line_index, offset)
213+
offset.map(|offset| {
214+
let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) {
215+
Ok(Some(matching_brace_offset)) => matching_brace_offset,
216+
Err(_) | Ok(None) => offset,
217+
};
218+
to_proto::position(&line_index, offset)
219+
})
218220
})
219-
.collect();
220-
Ok(res)
221+
.collect()
221222
}
222223

223224
pub(crate) fn handle_join_lines(
@@ -232,7 +233,7 @@ pub(crate) fn handle_join_lines(
232233

233234
let mut res = TextEdit::default();
234235
for range in params.ranges {
235-
let range = from_proto::text_range(&line_index, range);
236+
let range = from_proto::text_range(&line_index, range)?;
236237
let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?;
237238
match res.union(edit) {
238239
Ok(()) => (),
@@ -675,7 +676,7 @@ pub(crate) fn handle_runnables(
675676
let _p = profile::span("handle_runnables");
676677
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
677678
let line_index = snap.file_line_index(file_id)?;
678-
let offset = params.position.map(|it| from_proto::offset(&line_index, it));
679+
let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
679680
let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
680681

681682
let expect_test = match offset {
@@ -839,7 +840,7 @@ pub(crate) fn handle_completion_resolve(
839840

840841
let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
841842
let line_index = snap.file_line_index(file_id)?;
842-
let offset = from_proto::offset(&line_index, resolve_data.position.position);
843+
let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
843844

844845
let additional_edits = snap
845846
.analysis
@@ -1089,7 +1090,7 @@ pub(crate) fn handle_code_action(
10891090
.ranges
10901091
.iter()
10911092
.copied()
1092-
.map(|range| from_proto::text_range(&line_index, range))
1093+
.filter_map(|range| from_proto::text_range(&line_index, range).ok())
10931094
.any(|fix_range| fix_range.intersect(frange.range).is_some());
10941095
if intersect_fix_range {
10951096
res.push(fix.action.clone());
@@ -1111,7 +1112,7 @@ pub(crate) fn handle_code_action_resolve(
11111112

11121113
let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
11131114
let line_index = snap.file_line_index(file_id)?;
1114-
let range = from_proto::text_range(&line_index, params.code_action_params.range);
1115+
let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
11151116
let frange = FileRange { file_id, range };
11161117

11171118
let mut assists_config = snap.config.assist();

crates/rust-analyzer/src/lsp_utils.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ pub(crate) fn apply_document_changes(
151151
line_index.index = Arc::new(ide::LineIndex::new(old_text));
152152
}
153153
index_valid = IndexValid::UpToLineExclusive(range.start.line);
154-
let range = from_proto::text_range(&line_index, range);
155-
old_text.replace_range(Range::<usize>::from(range), &change.text);
154+
if let Ok(range) = from_proto::text_range(&line_index, range) {
155+
old_text.replace_range(Range::<usize>::from(range), &change.text);
156+
}
156157
}
157158
None => {
158159
*old_text = change.text;

0 commit comments

Comments
 (0)