aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/diagnostics
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-06-13 13:35:44 +0100
committerGitHub <[email protected]>2020-06-13 13:35:44 +0100
commit246c66a7f7fd3f85d7d6e47a36f17bafb0ccb08a (patch)
tree106b31324ba619413a055a36bd61621b4ac1531a /crates/rust-analyzer/src/diagnostics
parentd64b583e5a67e15db7151a7877871174655729a4 (diff)
parent50bbf7233dcda8a27255f123622bf57651c9f51c (diff)
Merge #4867
4867: Cleanup URL handling r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
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 257910e09..24ff9b280 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(
@@ -274,70 +270,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
274 .collect() 270 .collect()
275} 271}
276 272
277/// Returns a `Url` object from a given path, will lowercase drive letters if present.
278/// This will only happen when processing windows paths.
279///
280/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
281pub fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
282 let component_has_windows_drive = path.as_ref().components().any(|comp| {
283 if let Component::Prefix(c) = comp {
284 return matches!(c.kind(), Prefix::Disk(_) | Prefix::VerbatimDisk(_));
285 }
286 false
287 });
288
289 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
290 let res = if component_has_windows_drive {
291 let url_original = Url::from_file_path(&path)
292 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
293
294 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
295
296 // There is a drive partition, but we never found a colon.
297 // This should not happen, but in this case we just pass it through.
298 if drive_partition.len() == 1 {
299 return Ok(url_original);
300 }
301
302 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
303 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
304
305 url
306 } else {
307 Url::from_file_path(&path)
308 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?
309 };
310 Ok(res)
311}
312
313#[cfg(test)] 273#[cfg(test)]
274#[cfg(not(windows))]
314mod tests { 275mod tests {
315 use super::*; 276 use super::*;
316 277
317 // `Url` is not able to parse windows paths on unix machines.
318 #[test]
319 #[cfg(target_os = "windows")]
320 fn test_lowercase_drive_letter_with_drive() {
321 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
322
323 assert_eq!(url.to_string(), "file:///c:/Test");
324 }
325
326 #[test]
327 #[cfg(target_os = "windows")]
328 fn test_drive_without_colon_passthrough() {
329 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
330
331 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
332 }
333
334 #[cfg(not(windows))]
335 fn parse_diagnostic(val: &str) -> ra_flycheck::Diagnostic { 278 fn parse_diagnostic(val: &str) -> ra_flycheck::Diagnostic {
336 serde_json::from_str::<ra_flycheck::Diagnostic>(val).unwrap() 279 serde_json::from_str::<ra_flycheck::Diagnostic>(val).unwrap()
337 } 280 }
338 281
339 #[test] 282 #[test]
340 #[cfg(not(windows))]
341 fn snap_rustc_incompatible_type_for_trait() { 283 fn snap_rustc_incompatible_type_for_trait() {
342 let diag = parse_diagnostic( 284 let diag = parse_diagnostic(
343 r##"{ 285 r##"{
@@ -391,7 +333,6 @@ mod tests {
391 } 333 }
392 334
393 #[test] 335 #[test]
394 #[cfg(not(windows))]
395 fn snap_rustc_unused_variable() { 336 fn snap_rustc_unused_variable() {
396 let diag = parse_diagnostic( 337 let diag = parse_diagnostic(
397 r##"{ 338 r##"{
@@ -474,7 +415,6 @@ mod tests {
474 } 415 }
475 416
476 #[test] 417 #[test]
477 #[cfg(not(windows))]
478 fn snap_rustc_wrong_number_of_parameters() { 418 fn snap_rustc_wrong_number_of_parameters() {
479 let diag = parse_diagnostic( 419 let diag = parse_diagnostic(
480 r##"{ 420 r##"{
@@ -599,7 +539,6 @@ mod tests {
599 } 539 }
600 540
601 #[test] 541 #[test]
602 #[cfg(not(windows))]
603 fn snap_clippy_pass_by_ref() { 542 fn snap_clippy_pass_by_ref() {
604 let diag = parse_diagnostic( 543 let diag = parse_diagnostic(
605 r##"{ 544 r##"{
@@ -720,7 +659,6 @@ mod tests {
720 } 659 }
721 660
722 #[test] 661 #[test]
723 #[cfg(not(windows))]
724 fn snap_rustc_mismatched_type() { 662 fn snap_rustc_mismatched_type() {
725 let diag = parse_diagnostic( 663 let diag = parse_diagnostic(
726 r##"{ 664 r##"{
@@ -764,7 +702,6 @@ mod tests {
764 } 702 }
765 703
766 #[test] 704 #[test]
767 #[cfg(not(windows))]
768 fn snap_handles_macro_location() { 705 fn snap_handles_macro_location() {
769 let diag = parse_diagnostic( 706 let diag = parse_diagnostic(
770 r##"{ 707 r##"{
@@ -1036,7 +973,6 @@ mod tests {
1036 } 973 }
1037 974
1038 #[test] 975 #[test]
1039 #[cfg(not(windows))]
1040 fn snap_macro_compiler_error() { 976 fn snap_macro_compiler_error() {
1041 let diag = parse_diagnostic( 977 let diag = parse_diagnostic(
1042 r##"{ 978 r##"{
@@ -1266,7 +1202,6 @@ mod tests {
1266 } 1202 }
1267 1203
1268 #[test] 1204 #[test]
1269 #[cfg(not(windows))]
1270 fn snap_multi_line_fix() { 1205 fn snap_multi_line_fix() {
1271 let diag = parse_diagnostic( 1206 let diag = parse_diagnostic(
1272 r##"{ 1207 r##"{