@@ -19,12 +19,12 @@ use std::env::consts::EXE_SUFFIX;
19
19
use std:: fmt:: { self , Write as _} ;
20
20
use std:: io:: { self , ErrorKind } ;
21
21
use std:: path:: { Path , PathBuf } ;
22
- use std:: process:: Command ;
22
+ use std:: process:: { Command , ExitStatus } ;
23
23
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
24
24
use std:: time:: Duration ;
25
25
use std:: { env, fs, thread} ;
26
26
27
- use cargo_metadata:: diagnostic:: { Diagnostic , DiagnosticLevel } ;
27
+ use cargo_metadata:: diagnostic:: Diagnostic ;
28
28
use cargo_metadata:: Message ;
29
29
use rayon:: prelude:: * ;
30
30
use serde:: { Deserialize , Serialize } ;
@@ -90,16 +90,43 @@ struct Crate {
90
90
options : Option < Vec < String > > ,
91
91
}
92
92
93
+ /// A single emitted output from clippy being executed on a crate. It may either be a
94
+ /// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
95
+ /// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
96
+ #[ derive( Debug ) ]
97
+ enum ClippyCheckOutput {
98
+ ClippyWarning ( ClippyWarning ) ,
99
+ RustcIce ( RustcIce ) ,
100
+ }
101
+
102
+ #[ derive( Debug ) ]
103
+ struct RustcIce {
104
+ pub crate_name : String ,
105
+ pub ice_content : String ,
106
+ }
107
+ impl RustcIce {
108
+ pub fn from_stderr_and_status ( crate_name : & str , status : ExitStatus , stderr : & str ) -> Option < Self > {
109
+ if status. code ( ) . unwrap_or ( 0 ) == 101
110
+ /* ice exit status */
111
+ {
112
+ Some ( Self {
113
+ crate_name : crate_name. to_owned ( ) ,
114
+ ice_content : stderr. to_owned ( ) ,
115
+ } )
116
+ } else {
117
+ None
118
+ }
119
+ }
120
+ }
121
+
93
122
/// A single warning that clippy issued while checking a `Crate`
94
123
#[ derive( Debug ) ]
95
124
struct ClippyWarning {
96
- crate_name : String ,
97
125
file : String ,
98
126
line : usize ,
99
127
column : usize ,
100
128
lint_type : String ,
101
129
message : String ,
102
- is_ice : bool ,
103
130
}
104
131
105
132
#[ allow( unused) ]
@@ -124,13 +151,11 @@ impl ClippyWarning {
124
151
} ;
125
152
126
153
Some ( Self {
127
- crate_name : crate_name. to_owned ( ) ,
128
154
file,
129
155
line : span. line_start ,
130
156
column : span. column_start ,
131
157
lint_type,
132
158
message : diag. message ,
133
- is_ice : diag. level == DiagnosticLevel :: Ice ,
134
159
} )
135
160
}
136
161
@@ -311,7 +336,7 @@ impl Crate {
311
336
config : & LintcheckConfig ,
312
337
lint_filter : & [ String ] ,
313
338
server : & Option < LintcheckServer > ,
314
- ) -> Vec < ClippyWarning > {
339
+ ) -> Vec < ClippyCheckOutput > {
315
340
// advance the atomic index by one
316
341
let index = target_dir_index. fetch_add ( 1 , Ordering :: SeqCst ) ;
317
342
// "loop" the index within 0..thread_limit
@@ -335,9 +360,9 @@ impl Crate {
335
360
let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir" ) ;
336
361
337
362
let mut cargo_clippy_args = if config. fix {
338
- vec ! [ "--fix" , "--" ]
363
+ vec ! [ "--quiet" , "-- fix", "--" ]
339
364
} else {
340
- vec ! [ "--" , "--message-format=json" , "--" ]
365
+ vec ! [ "--quiet " , "--message-format=json" , "--" ]
341
366
} ;
342
367
343
368
let mut clippy_args = Vec :: < & str > :: new ( ) ;
@@ -428,14 +453,21 @@ impl Crate {
428
453
}
429
454
430
455
// get all clippy warnings and ICEs
431
- let warnings : Vec < ClippyWarning > = Message :: parse_stream ( stdout. as_bytes ( ) )
456
+ let mut entries : Vec < ClippyCheckOutput > = Message :: parse_stream ( stdout. as_bytes ( ) )
432
457
. filter_map ( |msg| match msg {
433
458
Ok ( Message :: CompilerMessage ( message) ) => ClippyWarning :: new ( message. message , & self . name , & self . version ) ,
434
459
_ => None ,
435
460
} )
461
+ . map ( ClippyCheckOutput :: ClippyWarning )
436
462
. collect ( ) ;
437
463
438
- warnings
464
+ if let Some ( ice) = RustcIce :: from_stderr_and_status ( & self . name , * status, & stderr) {
465
+ entries. push ( ClippyCheckOutput :: RustcIce ( ice) ) ;
466
+ } else if !status. success ( ) {
467
+ println ! ( "non-ICE bad exit status for {} {}: {}" , self . name, self . version, stderr) ;
468
+ }
469
+
470
+ entries
439
471
}
440
472
}
441
473
@@ -635,7 +667,7 @@ fn main() {
635
667
LintcheckServer :: spawn ( recursive_options)
636
668
} ) ;
637
669
638
- let mut clippy_warnings : Vec < ClippyWarning > = crates
670
+ let mut clippy_entries : Vec < ClippyCheckOutput > = crates
639
671
. par_iter ( )
640
672
. flat_map ( |krate| {
641
673
krate. run_clippy_lints (
@@ -651,28 +683,31 @@ fn main() {
651
683
. collect ( ) ;
652
684
653
685
if let Some ( server) = server {
654
- clippy_warnings. extend ( server. warnings ( ) ) ;
686
+ let server_clippy_entries = server. warnings ( ) . map ( ClippyCheckOutput :: ClippyWarning ) ;
687
+
688
+ clippy_entries. extend ( server_clippy_entries) ;
655
689
}
656
690
657
691
// if we are in --fix mode, don't change the log files, terminate here
658
692
if config. fix {
659
693
return ;
660
694
}
661
695
662
- // generate some stats
663
- let ( stats_formatted, new_stats) = gather_stats ( & clippy_warnings) ;
696
+ // split up warnings and ices
697
+ let mut warnings: Vec < ClippyWarning > = vec ! [ ] ;
698
+ let mut raw_ices: Vec < RustcIce > = vec ! [ ] ;
699
+ for entry in clippy_entries {
700
+ if let ClippyCheckOutput :: ClippyWarning ( x) = entry {
701
+ warnings. push ( x) ;
702
+ } else if let ClippyCheckOutput :: RustcIce ( x) = entry {
703
+ raw_ices. push ( x) ;
704
+ }
705
+ }
664
706
665
- // grab crashes/ICEs, save the crate name and the ice message
666
- let ices: Vec < ( & String , & String ) > = clippy_warnings
667
- . iter ( )
668
- . filter ( |warning| warning. is_ice )
669
- . map ( |w| ( & w. crate_name , & w. message ) )
670
- . collect ( ) ;
707
+ // generate some stats
708
+ let ( stats_formatted, new_stats) = gather_stats ( & warnings) ;
671
709
672
- let mut all_msgs: Vec < String > = clippy_warnings
673
- . iter ( )
674
- . map ( |warn| warn. to_output ( config. markdown ) )
675
- . collect ( ) ;
710
+ let mut all_msgs: Vec < String > = warnings. iter ( ) . map ( |warn| warn. to_output ( config. markdown ) ) . collect ( ) ;
676
711
all_msgs. sort ( ) ;
677
712
all_msgs. push ( "\n \n ### Stats:\n \n " . into ( ) ) ;
678
713
all_msgs. push ( stats_formatted) ;
@@ -686,11 +721,14 @@ fn main() {
686
721
}
687
722
write ! ( text, "{}" , all_msgs. join( "" ) ) . unwrap ( ) ;
688
723
text. push_str ( "\n \n ### ICEs:\n " ) ;
689
- for ( cratename , msg ) in & ices {
690
- let _: fmt:: Result = write ! ( text, "{cratename}: '{msg}'" ) ;
724
+ for ice in & raw_ices {
725
+ let _: fmt:: Result = write ! ( text, "{}: \n {} \n ======================================== \n \n " , ice . crate_name , ice . ice_content ) ;
691
726
}
692
727
693
728
println ! ( "Writing logs to {}" , config. lintcheck_results_path. display( ) ) ;
729
+ if !raw_ices. is_empty ( ) {
730
+ println ! ( "WARNING: at least one ICE reported, check log file" ) ;
731
+ }
694
732
fs:: create_dir_all ( config. lintcheck_results_path . parent ( ) . unwrap ( ) ) . unwrap ( ) ;
695
733
fs:: write ( & config. lintcheck_results_path , text) . unwrap ( ) ;
696
734
0 commit comments