22//! `cargo check` json format to the LSP diagnostic format.
33use std:: {
44 collections:: HashMap ,
5- fmt:: Write ,
6- path:: { Component , Path , PathBuf , Prefix } ,
5+ path:: { Component , Path , Prefix } ,
76 str:: FromStr ,
87} ;
98
@@ -12,17 +11,21 @@ use lsp_types::{
1211 Location , NumberOrString , Position , Range , TextEdit , Url , WorkspaceEdit ,
1312} ;
1413use ra_flycheck:: { Applicability , DiagnosticLevel , DiagnosticSpan , DiagnosticSpanMacroExpansion } ;
14+ use stdx:: format_to;
15+
16+ use crate :: Result ;
1517
1618/// Converts a Rust level string to a LSP severity
1719fn 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)
2629}
2730
2831/// Check whether a file name is from macro invocation
@@ -33,7 +36,7 @@ fn is_from_macro(file_name: &str) -> bool {
3336/// Converts a Rust macro span to a LSP location recursively
3437fn map_macro_span_to_location (
3538 span_macro : & DiagnosticSpanMacroExpansion ,
36- workspace_root : & PathBuf ,
39+ workspace_root : & Path ,
3740) -> Option < Location > {
3841 if !is_from_macro ( & span_macro. span . file_name ) {
3942 return Some ( map_span_to_location ( & span_macro. span , workspace_root) ) ;
@@ -47,7 +50,7 @@ fn map_macro_span_to_location(
4750}
4851
4952/// 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 {
5154 if span. expansion . is_some ( ) {
5255 let expansion = span. expansion . as_ref ( ) . unwrap ( ) ;
5356 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
5962}
6063
6164/// 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 ( ) ;
6467 file_name. push ( & span. file_name ) ;
6568 let uri = url_from_path_with_drive_lowercasing ( file_name) . unwrap ( ) ;
6669
70+ // FIXME: this doesn't handle UTF16 offsets correctly
6771 let range = Range :: new (
6872 Position :: new ( span. line_start as u64 - 1 , span. column_start as u64 - 1 ) ,
6973 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) -
7781/// If the span is unlabelled this will return `None`.
7882fn map_secondary_span_to_related (
7983 span : & DiagnosticSpan ,
80- workspace_root : & PathBuf ,
84+ workspace_root : & Path ,
8185) -> 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 } )
8989}
9090
9191/// Determines if diagnostic is related to unused code
9292fn 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 ( ) {
9595 "dead_code" | "unknown_lints" | "unreachable_code" | "unused_attributes"
9696 | "unused_imports" | "unused_macros" | "unused_variables" => true ,
9797 _ => false ,
98- }
99- } else {
100- false
98+ } ,
99+ None => false ,
101100 }
102101}
103102
104103/// 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 ,
113108 }
114109}
115110
@@ -121,7 +116,7 @@ enum MappedRustChildDiagnostic {
121116
122117fn map_rust_child_diagnostic (
123118 rd : & ra_flycheck:: Diagnostic ,
124- workspace_root : & PathBuf ,
119+ workspace_root : & Path ,
125120) -> MappedRustChildDiagnostic {
126121 let spans: Vec < & DiagnosticSpan > = rd. spans . iter ( ) . filter ( |s| s. is_primary ) . collect ( ) ;
127122 if spans. is_empty ( ) {
@@ -142,7 +137,12 @@ fn map_rust_child_diagnostic(
142137 }
143138 }
144139
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 {
146146 MappedRustChildDiagnostic :: SuggestedFix ( CodeAction {
147147 title : rd. message . clone ( ) ,
148148 kind : Some ( "quickfix" . to_string ( ) ) ,
@@ -151,11 +151,6 @@ fn map_rust_child_diagnostic(
151151 command : None ,
152152 is_preferred : None ,
153153 } )
154- } else {
155- MappedRustChildDiagnostic :: Related ( DiagnosticRelatedInformation {
156- location : map_span_to_location ( spans[ 0 ] , workspace_root) ,
157- message : rd. message . clone ( ) ,
158- } )
159154 }
160155}
161156
@@ -178,11 +173,11 @@ pub(crate) struct MappedRustDiagnostic {
178173/// If the diagnostic has no primary span this will return `None`
179174pub ( crate ) fn map_rust_diagnostic_to_lsp (
180175 rd : & ra_flycheck:: Diagnostic ,
181- workspace_root : & PathBuf ,
176+ workspace_root : & Path ,
182177) -> Vec < MappedRustDiagnostic > {
183178 let primary_spans: Vec < & DiagnosticSpan > = rd. spans . iter ( ) . filter ( |s| s. is_primary ) . collect ( ) ;
184179 if primary_spans. is_empty ( ) {
185- return vec ! [ ] ;
180+ return Vec :: new ( ) ;
186181 }
187182
188183 let severity = map_level_to_severity ( rd. level ) ;
@@ -199,8 +194,8 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
199194 }
200195
201196 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 ( ) ;
204199
205200 for secondary_span in rd. spans . iter ( ) . filter ( |s| !s. is_primary ) {
206201 let related = map_secondary_span_to_related ( secondary_span, workspace_root) ;
@@ -209,15 +204,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
209204 }
210205 }
211206
212- let mut fixes = vec ! [ ] ;
207+ let mut fixes = Vec :: new ( ) ;
213208 let mut message = rd. message . clone ( ) ;
214209 for child in & rd. children {
215210 let child = map_rust_child_diagnostic ( & child, workspace_root) ;
216211 match child {
217212 MappedRustChildDiagnostic :: Related ( related) => related_information. push ( related) ,
218213 MappedRustChildDiagnostic :: SuggestedFix ( code_action) => fixes. push ( code_action) ,
219214 MappedRustChildDiagnostic :: MessageLine ( message_line) => {
220- write ! ( & mut message, "\n {}" , message_line) . unwrap ( ) ;
215+ format_to ! ( message, "\n {}" , message_line) ;
221216
222217 // These secondary messages usually duplicate the content of the
223218 // primary span label.
@@ -242,7 +237,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
242237 let mut message = message. clone ( ) ;
243238 if needs_primary_span_label {
244239 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) ;
246241 }
247242 }
248243
@@ -262,12 +257,12 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
262257 code : code. clone ( ) . map ( NumberOrString :: String ) ,
263258 source : Some ( source. clone ( ) ) ,
264259 message,
265- related_information : if !related_information. is_empty ( ) {
266- Some ( related_information. clone ( ) )
267- } else {
260+ related_information : if related_information. is_empty ( ) {
268261 None
262+ } else {
263+ Some ( related_information. clone ( ) )
269264 } ,
270- tags : if ! tags. is_empty ( ) { Some ( tags. clone ( ) ) } else { None } ,
265+ tags : if tags. is_empty ( ) { None } else { Some ( tags. clone ( ) ) } ,
271266 } ;
272267
273268 MappedRustDiagnostic { location, diagnostic, fixes : fixes. clone ( ) }
@@ -279,21 +274,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
279274/// This will only happen when processing windows paths.
280275///
281276/// 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 > {
285278 let component_has_windows_drive = path. as_ref ( ) . components ( ) . any ( |comp| {
286279 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 ( _) ) ;
291281 }
292282 false
293283 } ) ;
294284
295285 // 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 {
297287 let url_original = Url :: from_file_path ( & path)
298288 . map_err ( |_| format ! ( "can't convert path to url: {}" , path. as_ref( ) . display( ) ) ) ?;
299289
@@ -308,11 +298,12 @@ pub fn url_from_path_with_drive_lowercasing(
308298 let joined = drive_partition[ 1 ] . to_ascii_lowercase ( ) + ":" + drive_partition[ 0 ] ;
309299 let url = Url :: from_str ( & joined) . expect ( "This came from a valid `Url`" ) ;
310300
311- Ok ( url)
301+ url
312302 } 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)
316307}
317308
318309#[ cfg( test) ]
@@ -337,8 +328,8 @@ mod tests {
337328 }
338329
339330 #[ 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 ( )
342333 }
343334
344335 #[ test]
@@ -390,8 +381,8 @@ mod tests {
390381 "## ,
391382 ) ;
392383
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) ;
395386 insta:: assert_debug_snapshot!( diag) ;
396387 }
397388
@@ -473,8 +464,8 @@ mod tests {
473464 }"## ,
474465 ) ;
475466
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) ;
478469 insta:: assert_debug_snapshot!( diag) ;
479470 }
480471
@@ -598,8 +589,8 @@ mod tests {
598589 }"## ,
599590 ) ;
600591
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) ;
603594 insta:: assert_debug_snapshot!( diag) ;
604595 }
605596
@@ -719,8 +710,8 @@ mod tests {
719710 }"## ,
720711 ) ;
721712
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) ;
724715 insta:: assert_debug_snapshot!( diag) ;
725716 }
726717
@@ -763,8 +754,8 @@ mod tests {
763754 }"## ,
764755 ) ;
765756
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) ;
768759 insta:: assert_debug_snapshot!( diag) ;
769760 }
770761
@@ -1035,8 +1026,8 @@ mod tests {
10351026 }"## ,
10361027 ) ;
10371028
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) ;
10401031 insta:: assert_debug_snapshot!( diag) ;
10411032 }
10421033
@@ -1265,8 +1256,8 @@ mod tests {
12651256 "## ,
12661257 ) ;
12671258
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) ;
12701261 insta:: assert_debug_snapshot!( diag) ;
12711262 }
12721263
@@ -1399,8 +1390,8 @@ mod tests {
13991390 "## ,
14001391 ) ;
14011392
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) ;
14041395 insta:: assert_debug_snapshot!( diag) ;
14051396 }
14061397}
0 commit comments