aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/diagnostics
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-06-13 10:00:06 +0100
committerAleksey Kladov <[email protected]>2020-06-13 13:15:38 +0100
commit50bbf7233dcda8a27255f123622bf57651c9f51c (patch)
tree183d011ed6a2f5fc5917d7bcd2763e7896a47a4f /crates/rust-analyzer/src/diagnostics
parentb56ad148db0c69eb279c225f45d324b4e80e7367 (diff)
Cleanup URL handling
Diffstat (limited to 'crates/rust-analyzer/src/diagnostics')
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs73
1 files changed, 4 insertions, 69 deletions
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 04e286780..789c86a35 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -1,10 +1,6 @@
1//! This module provides the functionality needed to convert diagnostics from 1//! This module provides the functionality needed to convert diagnostics from
2//! `cargo check` json format to the LSP diagnostic format. 2//! `cargo check` json format to the LSP diagnostic format.
3use std::{ 3use std::{collections::HashMap, path::Path};
4 collections::HashMap,
5 path::{Component, Path, Prefix},
6 str::FromStr,
7};
8 4
9use lsp_types::{ 5use lsp_types::{
10 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location, 6 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
@@ -13,7 +9,7 @@ use lsp_types::{
13use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; 9use ra_flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion};
14use stdx::format_to; 10use stdx::format_to;
15 11
16use crate::{lsp_ext, Result}; 12use crate::{lsp_ext, to_proto::url_from_abs_path};
17 13
18/// Converts a Rust level string to a LSP severity 14/// Converts a Rust level string to a LSP severity
19fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> { 15fn map_level_to_severity(val: DiagnosticLevel) -> Option<DiagnosticSeverity> {
@@ -65,7 +61,7 @@ fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &Path) -> Locatio
65fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &Path) -> Location { 61fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &Path) -> Location {
66 let mut file_name = workspace_root.to_path_buf(); 62 let mut file_name = workspace_root.to_path_buf();
67 file_name.push(&span.file_name); 63 file_name.push(&span.file_name);
68 let uri = url_from_path_with_drive_lowercasing(file_name).unwrap(); 64 let uri = url_from_abs_path(&file_name);
69 65
70 // FIXME: this doesn't handle UTF16 offsets correctly 66 // FIXME: this doesn't handle UTF16 offsets correctly
71 let range = Range::new( 67 let range = Range::new(
@@ -275,70 +271,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
275 .collect() 271 .collect()
276} 272}
277 273
278/// Returns a `Url` object from a given path, will lowercase drive letters if present.
279/// This will only happen when processing windows paths.
280///
281/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
282pub fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
283 let component_has_windows_drive = path.as_ref().components().any(|comp| {
284 if let Component::Prefix(c) = comp {
285 return matches!(c.kind(), Prefix::Disk(_) | Prefix::VerbatimDisk(_));
286 }
287 false
288 });
289
290 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
291 let res = if component_has_windows_drive {
292 let url_original = Url::from_file_path(&path)
293 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
294
295 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
296
297 // There is a drive partition, but we never found a colon.
298 // This should not happen, but in this case we just pass it through.
299 if drive_partition.len() == 1 {
300 return Ok(url_original);
301 }
302
303 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
304 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
305
306 url
307 } else {
308 Url::from_file_path(&path)
309 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?
310 };
311 Ok(res)
312}
313
314#[cfg(test)] 274#[cfg(test)]
275#[cfg(not(windows))]
315mod tests { 276mod tests {
316 use super::*; 277 use super::*;
317 278
318 // `Url` is not able to parse windows paths on unix machines.
319 #[test]
320 #[cfg(target_os = "windows")]
321 fn test_lowercase_drive_letter_with_drive() {
322 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
323
324 assert_eq!(url.to_string(), "file:///c:/Test");
325 }
326
327 #[test]
328 #[cfg(target_os = "windows")]
329 fn test_drive_without_colon_passthrough() {
330 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
331
332 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
333 }
334
335 #[cfg(not(windows))]
336 fn parse_diagnostic(val: &str) -> ra_flycheck::Diagnostic { 279 fn parse_diagnostic(val: &str) -> ra_flycheck::Diagnostic {
337 serde_json::from_str::<ra_flycheck::Diagnostic>(val).unwrap() 280 serde_json::from_str::<ra_flycheck::Diagnostic>(val).unwrap()
338 } 281 }
339 282
340 #[test] 283 #[test]
341 #[cfg(not(windows))]
342 fn snap_rustc_incompatible_type_for_trait() { 284 fn snap_rustc_incompatible_type_for_trait() {
343 let diag = parse_diagnostic( 285 let diag = parse_diagnostic(
344 r##"{ 286 r##"{
@@ -392,7 +334,6 @@ mod tests {
392 } 334 }
393 335
394 #[test] 336 #[test]
395 #[cfg(not(windows))]
396 fn snap_rustc_unused_variable() { 337 fn snap_rustc_unused_variable() {
397 let diag = parse_diagnostic( 338 let diag = parse_diagnostic(
398 r##"{ 339 r##"{
@@ -475,7 +416,6 @@ mod tests {
475 } 416 }
476 417
477 #[test] 418 #[test]
478 #[cfg(not(windows))]
479 fn snap_rustc_wrong_number_of_parameters() { 419 fn snap_rustc_wrong_number_of_parameters() {
480 let diag = parse_diagnostic( 420 let diag = parse_diagnostic(
481 r##"{ 421 r##"{
@@ -600,7 +540,6 @@ mod tests {
600 } 540 }
601 541
602 #[test] 542 #[test]
603 #[cfg(not(windows))]
604 fn snap_clippy_pass_by_ref() { 543 fn snap_clippy_pass_by_ref() {
605 let diag = parse_diagnostic( 544 let diag = parse_diagnostic(
606 r##"{ 545 r##"{
@@ -721,7 +660,6 @@ mod tests {
721 } 660 }
722 661
723 #[test] 662 #[test]
724 #[cfg(not(windows))]
725 fn snap_rustc_mismatched_type() { 663 fn snap_rustc_mismatched_type() {
726 let diag = parse_diagnostic( 664 let diag = parse_diagnostic(
727 r##"{ 665 r##"{
@@ -765,7 +703,6 @@ mod tests {
765 } 703 }
766 704
767 #[test] 705 #[test]
768 #[cfg(not(windows))]
769 fn snap_handles_macro_location() { 706 fn snap_handles_macro_location() {
770 let diag = parse_diagnostic( 707 let diag = parse_diagnostic(
771 r##"{ 708 r##"{
@@ -1037,7 +974,6 @@ mod tests {
1037 } 974 }
1038 975
1039 #[test] 976 #[test]
1040 #[cfg(not(windows))]
1041 fn snap_macro_compiler_error() { 977 fn snap_macro_compiler_error() {
1042 let diag = parse_diagnostic( 978 let diag = parse_diagnostic(
1043 r##"{ 979 r##"{
@@ -1267,7 +1203,6 @@ mod tests {
1267 } 1203 }
1268 1204
1269 #[test] 1205 #[test]
1270 #[cfg(not(windows))]
1271 fn snap_multi_line_fix() { 1206 fn snap_multi_line_fix() {
1272 let diag = parse_diagnostic( 1207 let diag = parse_diagnostic(
1273 r##"{ 1208 r##"{