diff options
-rw-r--r-- | crates/rust-analyzer/src/diagnostics/to_proto.rs | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index ca18997e4..8b01a7e5d 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -1,6 +1,9 @@ | |||
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. |
3 | use std::{collections::HashMap, path::Path}; | 3 | use std::{ |
4 | collections::HashMap, | ||
5 | path::{Path, PathBuf}, | ||
6 | }; | ||
4 | 7 | ||
5 | use flycheck::{DiagnosticLevel, DiagnosticSpan}; | 8 | use flycheck::{DiagnosticLevel, DiagnosticSpan}; |
6 | use stdx::format_to; | 9 | use stdx::format_to; |
@@ -42,7 +45,7 @@ fn is_dummy_macro_file(file_name: &str) -> bool { | |||
42 | 45 | ||
43 | /// Converts a Rust span to a LSP location | 46 | /// Converts a Rust span to a LSP location |
44 | fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { | 47 | fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { |
45 | let file_name = workspace_root.join(&span.file_name); | 48 | let file_name = resolve_path(workspace_root, &span.file_name); |
46 | let uri = url_from_abs_path(&file_name); | 49 | let uri = url_from_abs_path(&file_name); |
47 | 50 | ||
48 | // FIXME: this doesn't handle UTF16 offsets correctly | 51 | // FIXME: this doesn't handle UTF16 offsets correctly |
@@ -61,7 +64,7 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location | |||
61 | fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { | 64 | fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { |
62 | let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span)); | 65 | let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span)); |
63 | for span in span_stack.clone() { | 66 | for span in span_stack.clone() { |
64 | let abs_path = workspace_root.join(&span.file_name); | 67 | let abs_path = resolve_path(workspace_root, &span.file_name); |
65 | if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) { | 68 | if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) { |
66 | return location(workspace_root, span); | 69 | return location(workspace_root, span); |
67 | } | 70 | } |
@@ -84,6 +87,30 @@ fn diagnostic_related_information( | |||
84 | Some(lsp_types::DiagnosticRelatedInformation { location, message }) | 87 | Some(lsp_types::DiagnosticRelatedInformation { location, message }) |
85 | } | 88 | } |
86 | 89 | ||
90 | /// Resolves paths mimicking VSCode's behavior when `file_name` starts | ||
91 | /// with the root directory component, which does not discard the base | ||
92 | /// path. If this relative path exists, use it, otherwise fall back | ||
93 | /// to the existing Rust behavior of path joining. | ||
94 | fn resolve_path(workspace_root: &Path, file_name: &str) -> PathBuf { | ||
95 | let file_name = Path::new(file_name); | ||
96 | |||
97 | // Test path with VSCode's path join behavior. | ||
98 | let vscode_path = { | ||
99 | let mut result = PathBuf::from(workspace_root); | ||
100 | result.extend(file_name.components().skip_while(|component| match component { | ||
101 | std::path::Component::RootDir => true, | ||
102 | _ => false, | ||
103 | })); | ||
104 | result | ||
105 | }; | ||
106 | if vscode_path.exists() { | ||
107 | return vscode_path; | ||
108 | } | ||
109 | |||
110 | // Default to Rust's path join behavior. | ||
111 | workspace_root.join(file_name) | ||
112 | } | ||
113 | |||
87 | struct SubDiagnostic { | 114 | struct SubDiagnostic { |
88 | related: lsp_types::DiagnosticRelatedInformation, | 115 | related: lsp_types::DiagnosticRelatedInformation, |
89 | suggested_fix: Option<lsp_ext::CodeAction>, | 116 | suggested_fix: Option<lsp_ext::CodeAction>, |