From a98ffe4268a012e9f43e9667f8dcf0e0e70b3404 Mon Sep 17 00:00:00 2001 From: Felix Maurer Date: Thu, 31 Mar 2022 23:00:48 +0200 Subject: [PATCH 1/2] Prevent underflow when converting line numbers Previously, when line numbers of Rust spans were converted to LSP ranges, they could underflow resulting in very large line numbers. As an underflow is always wrong, prevent it and use 0 instead. --- crates/rust-analyzer/src/diagnostics/to_proto.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index dd59923cb34f..9d229c36f5a9 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -63,8 +63,14 @@ fn location( // FIXME: this doesn't handle UTF16 offsets correctly let range = lsp_types::Range::new( - lsp_types::Position::new(span.line_start as u32 - 1, span.column_start as u32 - 1), - lsp_types::Position::new(span.line_end as u32 - 1, span.column_end as u32 - 1), + lsp_types::Position::new( + (span.line_start as u32).saturating_sub(1), + (span.column_start as u32).saturating_sub(1), + ), + lsp_types::Position::new( + (span.line_end as u32).saturating_sub(1), + (span.column_end as u32).saturating_sub(1), + ), ); lsp_types::Location { uri, range } From feb8ccacba1d4e4ca01a5bd4aed80d4846724d08 Mon Sep 17 00:00:00 2001 From: Felix Maurer Date: Thu, 31 Mar 2022 23:37:23 +0200 Subject: [PATCH 2/2] Add test against line number underflow --- ...easonable_line_numbers_from_empty_file.txt | 64 +++++++++++++++++++ .../rust-analyzer/src/diagnostics/to_proto.rs | 43 +++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt diff --git a/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt b/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt new file mode 100644 index 000000000000..df00b330b6e9 --- /dev/null +++ b/crates/rust-analyzer/src/diagnostics/test_data/reasonable_line_numbers_from_empty_file.txt @@ -0,0 +1,64 @@ +[ + MappedRustDiagnostic { + url: Url { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/test/src/bin/current.rs", + query: None, + fragment: None, + }, + diagnostic: Diagnostic { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + severity: Some( + Error, + ), + code: Some( + String( + "E0601", + ), + ), + code_description: Some( + CodeDescription { + href: Url { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "doc.rust-lang.org", + ), + ), + port: None, + path: "/error-index.html", + query: None, + fragment: Some( + "E0601", + ), + }, + }, + ), + source: Some( + "rustc", + ), + message: "`main` function not found in crate `current`\nconsider adding a `main` function to `src/bin/current.rs`", + related_information: None, + tags: None, + data: None, + }, + fix: None, + }, +] diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 9d229c36f5a9..45e46c1a06be 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -1680,4 +1680,47 @@ mod tests { expect_file!["./test_data/snap_multi_line_fix.txt"], ); } + + #[test] + fn reasonable_line_numbers_from_empty_file() { + check( + r##"{ + "message": "`main` function not found in crate `current`", + "code": { + "code": "E0601", + "explanation": "No `main` function was found in a binary crate.\n\nTo fix this error, add a `main` function:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can look at the\n[Rust Book][rust-book] to get started.\n\n[rust-book]: https://doc.rust-lang.org/book/\n" + }, + "level": "error", + "spans": [ + { + "file_name": "src/bin/current.rs", + "byte_start": 0, + "byte_end": 0, + "line_start": 0, + "line_end": 0, + "column_start": 1, + "column_end": 1, + "is_primary": true, + "text": [], + "label": null, + "suggested_replacement": null, + "suggestion_applicability": null, + "expansion": null + } + ], + "children": [ + { + "message": "consider adding a `main` function to `src/bin/current.rs`", + "code": null, + "level": "note", + "spans": [], + "children": [], + "rendered": null + } + ], + "rendered": "error[E0601]: `main` function not found in crate `current`\n |\n = note: consider adding a `main` function to `src/bin/current.rs`\n\n" + }"##, + expect_file!["./test_data/reasonable_line_numbers_from_empty_file.txt"], + ); + } }