2
2
//! `cargo check` json format to the LSP diagnostic format.
3
3
use std:: {
4
4
collections:: HashMap ,
5
- fmt:: Write ,
6
- path:: { Component , Path , PathBuf , Prefix } ,
5
+ path:: { Component , Path , Prefix } ,
7
6
str:: FromStr ,
8
7
} ;
9
8
@@ -12,17 +11,21 @@ use lsp_types::{
12
11
Location , NumberOrString , Position , Range , TextEdit , Url , WorkspaceEdit ,
13
12
} ;
14
13
use ra_flycheck:: { Applicability , DiagnosticLevel , DiagnosticSpan , DiagnosticSpanMacroExpansion } ;
14
+ use stdx:: format_to;
15
+
16
+ use crate :: Result ;
15
17
16
18
/// Converts a Rust level string to a LSP severity
17
19
fn map_level_to_severity ( val : DiagnosticLevel ) -> Option < DiagnosticSeverity > {
18
- match val {
19
- DiagnosticLevel :: Ice => Some ( DiagnosticSeverity :: Error ) ,
20
- DiagnosticLevel :: Error => Some ( DiagnosticSeverity :: Error ) ,
21
- DiagnosticLevel :: Warning => Some ( DiagnosticSeverity :: Warning ) ,
22
- DiagnosticLevel :: Note => Some ( DiagnosticSeverity :: Information ) ,
23
- DiagnosticLevel :: Help => Some ( DiagnosticSeverity :: Hint ) ,
24
- DiagnosticLevel :: Unknown => None ,
25
- }
20
+ let res = match val {
21
+ DiagnosticLevel :: Ice => DiagnosticSeverity :: Error ,
22
+ DiagnosticLevel :: Error => DiagnosticSeverity :: Error ,
23
+ DiagnosticLevel :: Warning => DiagnosticSeverity :: Warning ,
24
+ DiagnosticLevel :: Note => DiagnosticSeverity :: Information ,
25
+ DiagnosticLevel :: Help => DiagnosticSeverity :: Hint ,
26
+ DiagnosticLevel :: Unknown => return None ,
27
+ } ;
28
+ Some ( res)
26
29
}
27
30
28
31
/// Check whether a file name is from macro invocation
@@ -33,7 +36,7 @@ fn is_from_macro(file_name: &str) -> bool {
33
36
/// Converts a Rust macro span to a LSP location recursively
34
37
fn map_macro_span_to_location (
35
38
span_macro : & DiagnosticSpanMacroExpansion ,
36
- workspace_root : & PathBuf ,
39
+ workspace_root : & Path ,
37
40
) -> Option < Location > {
38
41
if !is_from_macro ( & span_macro. span . file_name ) {
39
42
return Some ( map_span_to_location ( & span_macro. span , workspace_root) ) ;
@@ -47,7 +50,7 @@ fn map_macro_span_to_location(
47
50
}
48
51
49
52
/// Converts a Rust span to a LSP location, resolving macro expansion site if neccesary
50
- fn map_span_to_location ( span : & DiagnosticSpan , workspace_root : & PathBuf ) -> Location {
53
+ fn map_span_to_location ( span : & DiagnosticSpan , workspace_root : & Path ) -> Location {
51
54
if span. expansion . is_some ( ) {
52
55
let expansion = span. expansion . as_ref ( ) . unwrap ( ) ;
53
56
if let Some ( macro_range) = map_macro_span_to_location ( & expansion, workspace_root) {
@@ -59,11 +62,12 @@ fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &PathBuf) -> Loca
59
62
}
60
63
61
64
/// Converts a Rust span to a LSP location
62
- fn map_span_to_location_naive ( span : & DiagnosticSpan , workspace_root : & PathBuf ) -> Location {
63
- let mut file_name = workspace_root. clone ( ) ;
65
+ fn map_span_to_location_naive ( span : & DiagnosticSpan , workspace_root : & Path ) -> Location {
66
+ let mut file_name = workspace_root. to_path_buf ( ) ;
64
67
file_name. push ( & span. file_name ) ;
65
68
let uri = url_from_path_with_drive_lowercasing ( file_name) . unwrap ( ) ;
66
69
70
+ // FIXME: this doesn't handle UTF16 offsets correctly
67
71
let range = Range :: new (
68
72
Position :: new ( span. line_start as u64 - 1 , span. column_start as u64 - 1 ) ,
69
73
Position :: new ( span. line_end as u64 - 1 , span. column_end as u64 - 1 ) ,
@@ -77,39 +81,30 @@ fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &PathBuf) -
77
81
/// If the span is unlabelled this will return `None`.
78
82
fn map_secondary_span_to_related (
79
83
span : & DiagnosticSpan ,
80
- workspace_root : & PathBuf ,
84
+ workspace_root : & Path ,
81
85
) -> Option < DiagnosticRelatedInformation > {
82
- if let Some ( label) = & span. label {
83
- let location = map_span_to_location ( span, workspace_root) ;
84
- Some ( DiagnosticRelatedInformation { location, message : label. clone ( ) } )
85
- } else {
86
- // Nothing to label this with
87
- None
88
- }
86
+ let message = span. label . clone ( ) ?;
87
+ let location = map_span_to_location ( span, workspace_root) ;
88
+ Some ( DiagnosticRelatedInformation { location, message } )
89
89
}
90
90
91
91
/// Determines if diagnostic is related to unused code
92
92
fn is_unused_or_unnecessary ( rd : & ra_flycheck:: Diagnostic ) -> bool {
93
- if let Some ( code ) = & rd. code {
94
- match code. code . as_str ( ) {
93
+ match & rd. code {
94
+ Some ( code ) => match code. code . as_str ( ) {
95
95
"dead_code" | "unknown_lints" | "unreachable_code" | "unused_attributes"
96
96
| "unused_imports" | "unused_macros" | "unused_variables" => true ,
97
97
_ => false ,
98
- }
99
- } else {
100
- false
98
+ } ,
99
+ None => false ,
101
100
}
102
101
}
103
102
104
103
/// Determines if diagnostic is related to deprecated code
105
- fn is_deprecated ( rd : & RustDiagnostic ) -> bool {
106
- if let Some ( code) = & rd. code {
107
- match code. code . as_str ( ) {
108
- "deprecated" => true ,
109
- _ => false ,
110
- }
111
- } else {
112
- false
104
+ fn is_deprecated ( rd : & ra_flycheck:: Diagnostic ) -> bool {
105
+ match & rd. code {
106
+ Some ( code) => code. code . as_str ( ) == "deprecated" ,
107
+ None => false ,
113
108
}
114
109
}
115
110
@@ -121,7 +116,7 @@ enum MappedRustChildDiagnostic {
121
116
122
117
fn map_rust_child_diagnostic (
123
118
rd : & ra_flycheck:: Diagnostic ,
124
- workspace_root : & PathBuf ,
119
+ workspace_root : & Path ,
125
120
) -> MappedRustChildDiagnostic {
126
121
let spans: Vec < & DiagnosticSpan > = rd. spans . iter ( ) . filter ( |s| s. is_primary ) . collect ( ) ;
127
122
if spans. is_empty ( ) {
@@ -142,7 +137,12 @@ fn map_rust_child_diagnostic(
142
137
}
143
138
}
144
139
145
- if !edit_map. is_empty ( ) {
140
+ if edit_map. is_empty ( ) {
141
+ MappedRustChildDiagnostic :: Related ( DiagnosticRelatedInformation {
142
+ location : map_span_to_location ( spans[ 0 ] , workspace_root) ,
143
+ message : rd. message . clone ( ) ,
144
+ } )
145
+ } else {
146
146
MappedRustChildDiagnostic :: SuggestedFix ( CodeAction {
147
147
title : rd. message . clone ( ) ,
148
148
kind : Some ( "quickfix" . to_string ( ) ) ,
@@ -151,11 +151,6 @@ fn map_rust_child_diagnostic(
151
151
command : None ,
152
152
is_preferred : None ,
153
153
} )
154
- } else {
155
- MappedRustChildDiagnostic :: Related ( DiagnosticRelatedInformation {
156
- location : map_span_to_location ( spans[ 0 ] , workspace_root) ,
157
- message : rd. message . clone ( ) ,
158
- } )
159
154
}
160
155
}
161
156
@@ -178,11 +173,11 @@ pub(crate) struct MappedRustDiagnostic {
178
173
/// If the diagnostic has no primary span this will return `None`
179
174
pub ( crate ) fn map_rust_diagnostic_to_lsp (
180
175
rd : & ra_flycheck:: Diagnostic ,
181
- workspace_root : & PathBuf ,
176
+ workspace_root : & Path ,
182
177
) -> Vec < MappedRustDiagnostic > {
183
178
let primary_spans: Vec < & DiagnosticSpan > = rd. spans . iter ( ) . filter ( |s| s. is_primary ) . collect ( ) ;
184
179
if primary_spans. is_empty ( ) {
185
- return vec ! [ ] ;
180
+ return Vec :: new ( ) ;
186
181
}
187
182
188
183
let severity = map_level_to_severity ( rd. level ) ;
@@ -199,8 +194,8 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
199
194
}
200
195
201
196
let mut needs_primary_span_label = true ;
202
- let mut related_information = vec ! [ ] ;
203
- let mut tags = vec ! [ ] ;
197
+ let mut related_information = Vec :: new ( ) ;
198
+ let mut tags = Vec :: new ( ) ;
204
199
205
200
for secondary_span in rd. spans . iter ( ) . filter ( |s| !s. is_primary ) {
206
201
let related = map_secondary_span_to_related ( secondary_span, workspace_root) ;
@@ -209,15 +204,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
209
204
}
210
205
}
211
206
212
- let mut fixes = vec ! [ ] ;
207
+ let mut fixes = Vec :: new ( ) ;
213
208
let mut message = rd. message . clone ( ) ;
214
209
for child in & rd. children {
215
210
let child = map_rust_child_diagnostic ( & child, workspace_root) ;
216
211
match child {
217
212
MappedRustChildDiagnostic :: Related ( related) => related_information. push ( related) ,
218
213
MappedRustChildDiagnostic :: SuggestedFix ( code_action) => fixes. push ( code_action) ,
219
214
MappedRustChildDiagnostic :: MessageLine ( message_line) => {
220
- write ! ( & mut message, "\n {}" , message_line) . unwrap ( ) ;
215
+ format_to ! ( message, "\n {}" , message_line) ;
221
216
222
217
// These secondary messages usually duplicate the content of the
223
218
// primary span label.
@@ -242,7 +237,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
242
237
let mut message = message. clone ( ) ;
243
238
if needs_primary_span_label {
244
239
if let Some ( primary_span_label) = & primary_span. label {
245
- write ! ( & mut message, "\n {}" , primary_span_label) . unwrap ( ) ;
240
+ format_to ! ( message, "\n {}" , primary_span_label) ;
246
241
}
247
242
}
248
243
@@ -262,12 +257,12 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
262
257
code : code. clone ( ) . map ( NumberOrString :: String ) ,
263
258
source : Some ( source. clone ( ) ) ,
264
259
message,
265
- related_information : if !related_information. is_empty ( ) {
266
- Some ( related_information. clone ( ) )
267
- } else {
260
+ related_information : if related_information. is_empty ( ) {
268
261
None
262
+ } else {
263
+ Some ( related_information. clone ( ) )
269
264
} ,
270
- tags : if ! tags. is_empty ( ) { Some ( tags. clone ( ) ) } else { None } ,
265
+ tags : if tags. is_empty ( ) { None } else { Some ( tags. clone ( ) ) } ,
271
266
} ;
272
267
273
268
MappedRustDiagnostic { location, diagnostic, fixes : fixes. clone ( ) }
@@ -279,21 +274,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
279
274
/// This will only happen when processing windows paths.
280
275
///
281
276
/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
282
- pub fn url_from_path_with_drive_lowercasing (
283
- path : impl AsRef < Path > ,
284
- ) -> Result < Url , Box < dyn std:: error:: Error + Send + Sync > > {
277
+ pub fn url_from_path_with_drive_lowercasing ( path : impl AsRef < Path > ) -> Result < Url > {
285
278
let component_has_windows_drive = path. as_ref ( ) . components ( ) . any ( |comp| {
286
279
if let Component :: Prefix ( c) = comp {
287
- match c. kind ( ) {
288
- Prefix :: Disk ( _) | Prefix :: VerbatimDisk ( _) => return true ,
289
- _ => return false ,
290
- }
280
+ return matches ! ( c. kind( ) , Prefix :: Disk ( _) | Prefix :: VerbatimDisk ( _) ) ;
291
281
}
292
282
false
293
283
} ) ;
294
284
295
285
// VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
296
- if component_has_windows_drive {
286
+ let res = if component_has_windows_drive {
297
287
let url_original = Url :: from_file_path ( & path)
298
288
. map_err ( |_| format ! ( "can't convert path to url: {}" , path. as_ref( ) . display( ) ) ) ?;
299
289
@@ -308,11 +298,12 @@ pub fn url_from_path_with_drive_lowercasing(
308
298
let joined = drive_partition[ 1 ] . to_ascii_lowercase ( ) + ":" + drive_partition[ 0 ] ;
309
299
let url = Url :: from_str ( & joined) . expect ( "This came from a valid `Url`" ) ;
310
300
311
- Ok ( url)
301
+ url
312
302
} else {
313
- Ok ( Url :: from_file_path ( & path)
314
- . map_err ( |_| format ! ( "can't convert path to url: {}" , path. as_ref( ) . display( ) ) ) ?)
315
- }
303
+ Url :: from_file_path ( & path)
304
+ . map_err ( |_| format ! ( "can't convert path to url: {}" , path. as_ref( ) . display( ) ) ) ?
305
+ } ;
306
+ Ok ( res)
316
307
}
317
308
318
309
#[ cfg( test) ]
@@ -337,8 +328,8 @@ mod tests {
337
328
}
338
329
339
330
#[ cfg( not( windows) ) ]
340
- fn parse_diagnostic ( val : & str ) -> cargo_metadata :: diagnostic :: Diagnostic {
341
- serde_json:: from_str :: < cargo_metadata :: diagnostic :: Diagnostic > ( val) . unwrap ( )
331
+ fn parse_diagnostic ( val : & str ) -> ra_flycheck :: Diagnostic {
332
+ serde_json:: from_str :: < ra_flycheck :: Diagnostic > ( val) . unwrap ( )
342
333
}
343
334
344
335
#[ test]
@@ -390,8 +381,8 @@ mod tests {
390
381
"## ,
391
382
) ;
392
383
393
- let workspace_root = PathBuf :: from ( "/test/" ) ;
394
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
384
+ let workspace_root = Path :: new ( "/test/" ) ;
385
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
395
386
insta:: assert_debug_snapshot!( diag) ;
396
387
}
397
388
@@ -473,8 +464,8 @@ mod tests {
473
464
}"## ,
474
465
) ;
475
466
476
- let workspace_root = PathBuf :: from ( "/test/" ) ;
477
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
467
+ let workspace_root = Path :: new ( "/test/" ) ;
468
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
478
469
insta:: assert_debug_snapshot!( diag) ;
479
470
}
480
471
@@ -598,8 +589,8 @@ mod tests {
598
589
}"## ,
599
590
) ;
600
591
601
- let workspace_root = PathBuf :: from ( "/test/" ) ;
602
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
592
+ let workspace_root = Path :: new ( "/test/" ) ;
593
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
603
594
insta:: assert_debug_snapshot!( diag) ;
604
595
}
605
596
@@ -719,8 +710,8 @@ mod tests {
719
710
}"## ,
720
711
) ;
721
712
722
- let workspace_root = PathBuf :: from ( "/test/" ) ;
723
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
713
+ let workspace_root = Path :: new ( "/test/" ) ;
714
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
724
715
insta:: assert_debug_snapshot!( diag) ;
725
716
}
726
717
@@ -763,8 +754,8 @@ mod tests {
763
754
}"## ,
764
755
) ;
765
756
766
- let workspace_root = PathBuf :: from ( "/test/" ) ;
767
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
757
+ let workspace_root = Path :: new ( "/test/" ) ;
758
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
768
759
insta:: assert_debug_snapshot!( diag) ;
769
760
}
770
761
@@ -1035,8 +1026,8 @@ mod tests {
1035
1026
}"## ,
1036
1027
) ;
1037
1028
1038
- let workspace_root = PathBuf :: from ( "/test/" ) ;
1039
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
1029
+ let workspace_root = Path :: new ( "/test/" ) ;
1030
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
1040
1031
insta:: assert_debug_snapshot!( diag) ;
1041
1032
}
1042
1033
@@ -1265,8 +1256,8 @@ mod tests {
1265
1256
"## ,
1266
1257
) ;
1267
1258
1268
- let workspace_root = PathBuf :: from ( "/test/" ) ;
1269
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
1259
+ let workspace_root = Path :: new ( "/test/" ) ;
1260
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
1270
1261
insta:: assert_debug_snapshot!( diag) ;
1271
1262
}
1272
1263
@@ -1399,8 +1390,8 @@ mod tests {
1399
1390
"## ,
1400
1391
) ;
1401
1392
1402
- let workspace_root = PathBuf :: from ( "/test/" ) ;
1403
- let diag = map_rust_diagnostic_to_lsp ( & diag, & workspace_root) ;
1393
+ let workspace_root = Path :: new ( "/test/" ) ;
1394
+ let diag = map_rust_diagnostic_to_lsp ( & diag, workspace_root) ;
1404
1395
insta:: assert_debug_snapshot!( diag) ;
1405
1396
}
1406
1397
}
0 commit comments