1
1
//! This module provides the functionality needed to convert diagnostics from
2
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
8
use flycheck:: { DiagnosticLevel , DiagnosticSpan } ;
6
9
use stdx:: format_to;
@@ -42,7 +45,7 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
42
45
43
46
/// Converts a Rust span to a LSP location
44
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
49
let uri = url_from_abs_path ( & file_name) ;
47
50
48
51
// FIXME: this doesn't handle UTF16 offsets correctly
@@ -61,7 +64,7 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location
61
64
fn primary_location ( workspace_root : & Path , span : & DiagnosticSpan ) -> lsp_types:: Location {
62
65
let span_stack = std:: iter:: successors ( Some ( span) , |span| Some ( & span. expansion . as_ref ( ) ?. span ) ) ;
63
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
68
if !is_dummy_macro_file ( & span. file_name ) && abs_path. starts_with ( workspace_root) {
66
69
return location ( workspace_root, span) ;
67
70
}
@@ -84,6 +87,30 @@ fn diagnostic_related_information(
84
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
114
struct SubDiagnostic {
88
115
related : lsp_types:: DiagnosticRelatedInformation ,
89
116
suggested_fix : Option < lsp_ext:: CodeAction > ,
0 commit comments