From b7cabf1e443b2f9f944747c2124639abacedaf40 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Mon, 3 Jan 2022 14:49:47 +0000 Subject: [PATCH] fix: don't panic on seeing an unexpected offset --- crates/ide_db/src/line_index.rs | 6 +++-- crates/rust-analyzer/src/from_proto.rs | 24 +++++++++++-------- crates/rust-analyzer/src/handlers.rs | 33 +++++++++++++------------- crates/rust-analyzer/src/lsp_utils.rs | 5 ++-- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 816edfe6a8e2..35e1757eaec4 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs @@ -102,8 +102,10 @@ impl LineIndex { LineCol { line: line as u32, col: col.into() } } - pub fn offset(&self, line_col: LineCol) -> TextSize { - self.newlines[line_col.line as usize] + TextSize::from(line_col.col) + pub fn offset(&self, line_col: LineCol) -> Option { + self.newlines + .get(line_col.line as usize) + .map(|offset| offset + TextSize::from(line_col.col)) } pub fn to_utf16(&self, line_col: LineCol) -> LineColUtf16 { diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 4cbf2b1124be..1c67ecc22c80 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -1,4 +1,5 @@ //! Conversion lsp_types types to rust-analyzer specific ones. +use anyhow::format_err; use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16}; use ide_db::base_db::{FileId, FilePosition, FileRange}; use syntax::{TextRange, TextSize}; @@ -22,7 +23,7 @@ pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result { abs_path(url).map(vfs::VfsPath::from) } -pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize { +pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result { let line_col = match line_index.encoding { OffsetEncoding::Utf8 => { 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 line_index.index.to_utf8(line_col) } }; - line_index.index.offset(line_col) + let text_size = + line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?; + Ok(text_size) } -pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange { - let start = offset(line_index, range.start); - let end = offset(line_index, range.end); - TextRange::new(start, end) +pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result { + let start = offset(line_index, range.start)?; + let end = offset(line_index, range.end)?; + let text_range = TextRange::new(start, end); + Ok(text_range) } pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { @@ -52,7 +56,7 @@ pub(crate) fn file_position( ) -> Result { let file_id = file_id(snap, &tdpp.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let offset = offset(&line_index, tdpp.position); + let offset = offset(&line_index, tdpp.position)?; Ok(FilePosition { file_id, offset }) } @@ -63,7 +67,7 @@ pub(crate) fn file_range( ) -> Result { let file_id = file_id(snap, &text_document_identifier.uri)?; let line_index = snap.file_line_index(file_id)?; - let range = text_range(&line_index, range); + let range = text_range(&line_index, range)?; Ok(FileRange { file_id, range }) } @@ -96,7 +100,7 @@ pub(crate) fn annotation( let line_index = snap.file_line_index(file_id)?; Ok(Annotation { - range: text_range(&line_index, code_lens.range), + range: text_range(&line_index, code_lens.range)?, kind: AnnotationKind::HasImpls { position: file_position(snap, params.text_document_position_params)?, data: None, @@ -108,7 +112,7 @@ pub(crate) fn annotation( let line_index = snap.file_line_index(file_id)?; Ok(Annotation { - range: text_range(&line_index, code_lens.range), + range: text_range(&line_index, code_lens.range)?, kind: AnnotationKind::HasReferences { position: file_position(snap, params)?, data: None, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 66b66e024ce7..4160b3ecd1fb 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -108,7 +108,7 @@ pub(crate) fn handle_syntax_tree( let _p = profile::span("handle_syntax_tree"); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(id)?; - let text_range = params.range.map(|r| from_proto::text_range(&line_index, r)); + let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok()); let res = snap.analysis.syntax_tree(id, text_range)?; Ok(res) } @@ -149,7 +149,7 @@ pub(crate) fn handle_expand_macro( let _p = profile::span("handle_expand_macro"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let offset = from_proto::offset(&line_index, params.position); + let offset = from_proto::offset(&line_index, params.position)?; let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?; Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) @@ -166,7 +166,7 @@ pub(crate) fn handle_selection_range( .positions .into_iter() .map(|position| { - let offset = from_proto::offset(&line_index, position); + let offset = from_proto::offset(&line_index, position)?; let mut ranges = Vec::new(); { let mut range = TextRange::new(offset, offset); @@ -205,19 +205,20 @@ pub(crate) fn handle_matching_brace( let _p = profile::span("handle_matching_brace"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let res = params + params .positions .into_iter() .map(|position| { let offset = from_proto::offset(&line_index, position); - let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) { - Ok(Some(matching_brace_offset)) => matching_brace_offset, - Err(_) | Ok(None) => offset, - }; - to_proto::position(&line_index, offset) + offset.map(|offset| { + let offset = match snap.analysis.matching_brace(FilePosition { file_id, offset }) { + Ok(Some(matching_brace_offset)) => matching_brace_offset, + Err(_) | Ok(None) => offset, + }; + to_proto::position(&line_index, offset) + }) }) - .collect(); - Ok(res) + .collect() } pub(crate) fn handle_join_lines( @@ -232,7 +233,7 @@ pub(crate) fn handle_join_lines( let mut res = TextEdit::default(); for range in params.ranges { - let range = from_proto::text_range(&line_index, range); + let range = from_proto::text_range(&line_index, range)?; let edit = snap.analysis.join_lines(&config, FileRange { file_id, range })?; match res.union(edit) { Ok(()) => (), @@ -675,7 +676,7 @@ pub(crate) fn handle_runnables( let _p = profile::span("handle_runnables"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let offset = params.position.map(|it| from_proto::offset(&line_index, it)); + let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok()); let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; let expect_test = match offset { @@ -839,7 +840,7 @@ pub(crate) fn handle_completion_resolve( let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let offset = from_proto::offset(&line_index, resolve_data.position.position); + let offset = from_proto::offset(&line_index, resolve_data.position.position)?; let additional_edits = snap .analysis @@ -1089,7 +1090,7 @@ pub(crate) fn handle_code_action( .ranges .iter() .copied() - .map(|range| from_proto::text_range(&line_index, range)) + .filter_map(|range| from_proto::text_range(&line_index, range).ok()) .any(|fix_range| fix_range.intersect(frange.range).is_some()); if intersect_fix_range { res.push(fix.action.clone()); @@ -1111,7 +1112,7 @@ pub(crate) fn handle_code_action_resolve( let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let range = from_proto::text_range(&line_index, params.code_action_params.range); + let range = from_proto::text_range(&line_index, params.code_action_params.range)?; let frange = FileRange { file_id, range }; let mut assists_config = snap.config.assist(); diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 194d03032202..b09c411908af 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -151,8 +151,9 @@ pub(crate) fn apply_document_changes( line_index.index = Arc::new(ide::LineIndex::new(old_text)); } index_valid = IndexValid::UpToLineExclusive(range.start.line); - let range = from_proto::text_range(&line_index, range); - old_text.replace_range(Range::::from(range), &change.text); + if let Ok(range) = from_proto::text_range(&line_index, range) { + old_text.replace_range(Range::::from(range), &change.text); + } } None => { *old_text = change.text;