@@ -44,8 +44,12 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
44
44
}
45
45
46
46
/// Converts a Rust span to a LSP location
47
- fn location ( workspace_root : & Path , span : & DiagnosticSpan ) -> lsp_types:: Location {
48
- let file_name = resolve_path ( workspace_root, & span. file_name ) ;
47
+ fn location (
48
+ config : & DiagnosticsMapConfig ,
49
+ workspace_root : & Path ,
50
+ span : & DiagnosticSpan ,
51
+ ) -> lsp_types:: Location {
52
+ let file_name = resolve_path ( config, workspace_root, & span. file_name ) ;
49
53
let uri = url_from_abs_path ( & file_name) ;
50
54
51
55
// FIXME: this doesn't handle UTF16 offsets correctly
@@ -61,54 +65,46 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location
61
65
///
62
66
/// This takes locations pointing into the standard library, or generally outside the current
63
67
/// workspace into account and tries to avoid those, in case macros are involved.
64
- fn primary_location ( workspace_root : & Path , span : & DiagnosticSpan ) -> lsp_types:: Location {
68
+ fn primary_location (
69
+ config : & DiagnosticsMapConfig ,
70
+ workspace_root : & Path ,
71
+ span : & DiagnosticSpan ,
72
+ ) -> lsp_types:: Location {
65
73
let span_stack = std:: iter:: successors ( Some ( span) , |span| Some ( & span. expansion . as_ref ( ) ?. span ) ) ;
66
74
for span in span_stack. clone ( ) {
67
- let abs_path = resolve_path ( workspace_root, & span. file_name ) ;
75
+ let abs_path = resolve_path ( config , workspace_root, & span. file_name ) ;
68
76
if !is_dummy_macro_file ( & span. file_name ) && abs_path. starts_with ( workspace_root) {
69
- return location ( workspace_root, span) ;
77
+ return location ( config , workspace_root, span) ;
70
78
}
71
79
}
72
80
73
81
// Fall back to the outermost macro invocation if no suitable span comes up.
74
82
let last_span = span_stack. last ( ) . unwrap ( ) ;
75
- location ( workspace_root, last_span)
83
+ location ( config , workspace_root, last_span)
76
84
}
77
85
78
86
/// Converts a secondary Rust span to a LSP related information
79
87
///
80
88
/// If the span is unlabelled this will return `None`.
81
89
fn diagnostic_related_information (
90
+ config : & DiagnosticsMapConfig ,
82
91
workspace_root : & Path ,
83
92
span : & DiagnosticSpan ,
84
93
) -> Option < lsp_types:: DiagnosticRelatedInformation > {
85
94
let message = span. label . clone ( ) ?;
86
- let location = location ( workspace_root, span) ;
95
+ let location = location ( config , workspace_root, span) ;
87
96
Some ( lsp_types:: DiagnosticRelatedInformation { location, message } )
88
97
}
89
98
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;
99
+ /// Resolves paths applying any matching path prefix remappings, and then
100
+ /// joining the path to the workspace root.
101
+ fn resolve_path ( config : & DiagnosticsMapConfig , workspace_root : & Path , file_name : & str ) -> PathBuf {
102
+ match config. remap_path_prefixes . iter ( ) . find ( |( from, _) | file_name. starts_with ( * from) ) {
103
+ Some ( ( from, to) ) => {
104
+ workspace_root. join ( format ! ( "{}{}" , to, file_name. strip_prefix( from) . unwrap( ) ) )
105
+ }
106
+ None => workspace_root. join ( file_name) ,
108
107
}
109
-
110
- // Default to Rust's path join behavior.
111
- workspace_root. join ( file_name)
112
108
}
113
109
114
110
struct SubDiagnostic {
@@ -122,6 +118,7 @@ enum MappedRustChildDiagnostic {
122
118
}
123
119
124
120
fn map_rust_child_diagnostic (
121
+ config : & DiagnosticsMapConfig ,
125
122
workspace_root : & Path ,
126
123
rd : & flycheck:: Diagnostic ,
127
124
) -> MappedRustChildDiagnostic {
@@ -135,7 +132,7 @@ fn map_rust_child_diagnostic(
135
132
let mut edit_map: HashMap < lsp_types:: Url , Vec < lsp_types:: TextEdit > > = HashMap :: new ( ) ;
136
133
for & span in & spans {
137
134
if let Some ( suggested_replacement) = & span. suggested_replacement {
138
- let location = location ( workspace_root, span) ;
135
+ let location = location ( config , workspace_root, span) ;
139
136
let edit = lsp_types:: TextEdit :: new ( location. range , suggested_replacement. clone ( ) ) ;
140
137
edit_map. entry ( location. uri ) . or_default ( ) . push ( edit) ;
141
138
}
@@ -144,15 +141,15 @@ fn map_rust_child_diagnostic(
144
141
if edit_map. is_empty ( ) {
145
142
MappedRustChildDiagnostic :: SubDiagnostic ( SubDiagnostic {
146
143
related : lsp_types:: DiagnosticRelatedInformation {
147
- location : location ( workspace_root, spans[ 0 ] ) ,
144
+ location : location ( config , workspace_root, spans[ 0 ] ) ,
148
145
message : rd. message . clone ( ) ,
149
146
} ,
150
147
suggested_fix : None ,
151
148
} )
152
149
} else {
153
150
MappedRustChildDiagnostic :: SubDiagnostic ( SubDiagnostic {
154
151
related : lsp_types:: DiagnosticRelatedInformation {
155
- location : location ( workspace_root, spans[ 0 ] ) ,
152
+ location : location ( config , workspace_root, spans[ 0 ] ) ,
156
153
message : rd. message . clone ( ) ,
157
154
} ,
158
155
suggested_fix : Some ( lsp_ext:: CodeAction {
@@ -217,15 +214,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
217
214
let mut tags = Vec :: new ( ) ;
218
215
219
216
for secondary_span in rd. spans . iter ( ) . filter ( |s| !s. is_primary ) {
220
- let related = diagnostic_related_information ( workspace_root, secondary_span) ;
217
+ let related = diagnostic_related_information ( config , workspace_root, secondary_span) ;
221
218
if let Some ( related) = related {
222
219
subdiagnostics. push ( SubDiagnostic { related, suggested_fix : None } ) ;
223
220
}
224
221
}
225
222
226
223
let mut message = rd. message . clone ( ) ;
227
224
for child in & rd. children {
228
- let child = map_rust_child_diagnostic ( workspace_root, & child) ;
225
+ let child = map_rust_child_diagnostic ( config , workspace_root, & child) ;
229
226
match child {
230
227
MappedRustChildDiagnostic :: SubDiagnostic ( sub) => {
231
228
subdiagnostics. push ( sub) ;
@@ -269,7 +266,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
269
266
primary_spans
270
267
. iter ( )
271
268
. flat_map ( |primary_span| {
272
- let primary_location = primary_location ( workspace_root, & primary_span) ;
269
+ let primary_location = primary_location ( config , workspace_root, & primary_span) ;
273
270
274
271
let mut message = message. clone ( ) ;
275
272
if needs_primary_span_label {
@@ -299,7 +296,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
299
296
// generated that code.
300
297
let is_in_macro_call = i != 0 ;
301
298
302
- let secondary_location = location ( workspace_root, & span) ;
299
+ let secondary_location = location ( config , workspace_root, & span) ;
303
300
if secondary_location == primary_location {
304
301
continue ;
305
302
}
0 commit comments