@@ -26,12 +26,12 @@ use std::env::consts::EXE_SUFFIX;
26
26
use std:: fmt:: { self , Write as _} ;
27
27
use std:: io:: { self , ErrorKind } ;
28
28
use std:: path:: { Path , PathBuf } ;
29
- use std:: process:: Command ;
29
+ use std:: process:: { Command , ExitStatus } ;
30
30
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
31
31
use std:: time:: Duration ;
32
32
use std:: { env, fs, thread} ;
33
33
34
- use cargo_metadata:: diagnostic:: { Diagnostic , DiagnosticLevel } ;
34
+ use cargo_metadata:: diagnostic:: Diagnostic ;
35
35
use cargo_metadata:: Message ;
36
36
use rayon:: prelude:: * ;
37
37
use serde:: { Deserialize , Serialize } ;
@@ -97,16 +97,43 @@ struct Crate {
97
97
options : Option < Vec < String > > ,
98
98
}
99
99
100
+ /// A single emitted output from clippy being executed on a crate. It may either be a
101
+ /// `ClippyWarning`, or a `RustcIce` caused by a panic within clippy. A crate may have many
102
+ /// `ClippyWarning`s but a maximum of one `RustcIce` (at which point clippy halts execution).
103
+ #[ derive( Debug ) ]
104
+ enum ClippyCheckOutput {
105
+ ClippyWarning ( ClippyWarning ) ,
106
+ RustcIce ( RustcIce ) ,
107
+ }
108
+
109
+ #[ derive( Debug ) ]
110
+ struct RustcIce {
111
+ pub crate_name : String ,
112
+ pub ice_content : String ,
113
+ }
114
+ impl RustcIce {
115
+ pub fn from_stderr_and_status ( crate_name : & str , status : ExitStatus , stderr : & str ) -> Option < Self > {
116
+ if status. code ( ) . unwrap_or ( 0 ) == 101
117
+ /* ice exit status */
118
+ {
119
+ Some ( Self {
120
+ crate_name : crate_name. to_owned ( ) ,
121
+ ice_content : stderr. to_owned ( ) ,
122
+ } )
123
+ } else {
124
+ None
125
+ }
126
+ }
127
+ }
128
+
100
129
/// A single warning that clippy issued while checking a `Crate`
101
130
#[ derive( Debug ) ]
102
131
struct ClippyWarning {
103
- crate_name : String ,
104
132
file : String ,
105
133
line : usize ,
106
134
column : usize ,
107
135
lint_type : String ,
108
136
message : String ,
109
- is_ice : bool ,
110
137
}
111
138
112
139
#[ allow( unused) ]
@@ -131,13 +158,11 @@ impl ClippyWarning {
131
158
} ;
132
159
133
160
Some ( Self {
134
- crate_name : crate_name. to_owned ( ) ,
135
161
file,
136
162
line : span. line_start ,
137
163
column : span. column_start ,
138
164
lint_type,
139
165
message : diag. message ,
140
- is_ice : diag. level == DiagnosticLevel :: Ice ,
141
166
} )
142
167
}
143
168
@@ -318,7 +343,7 @@ impl Crate {
318
343
config : & LintcheckConfig ,
319
344
lint_filter : & [ String ] ,
320
345
server : & Option < LintcheckServer > ,
321
- ) -> Vec < ClippyWarning > {
346
+ ) -> Vec < ClippyCheckOutput > {
322
347
// advance the atomic index by one
323
348
let index = target_dir_index. fetch_add ( 1 , Ordering :: SeqCst ) ;
324
349
// "loop" the index within 0..thread_limit
@@ -342,9 +367,9 @@ impl Crate {
342
367
let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir" ) ;
343
368
344
369
let mut cargo_clippy_args = if config. fix {
345
- vec ! [ "--fix" , "--" ]
370
+ vec ! [ "--quiet" , "-- fix", "--" ]
346
371
} else {
347
- vec ! [ "--" , "--message-format=json" , "--" ]
372
+ vec ! [ "--quiet " , "--message-format=json" , "--" ]
348
373
} ;
349
374
350
375
let mut clippy_args = Vec :: < & str > :: new ( ) ;
@@ -435,14 +460,21 @@ impl Crate {
435
460
}
436
461
437
462
// get all clippy warnings and ICEs
438
- let warnings : Vec < ClippyWarning > = Message :: parse_stream ( stdout. as_bytes ( ) )
463
+ let mut entries : Vec < ClippyCheckOutput > = Message :: parse_stream ( stdout. as_bytes ( ) )
439
464
. filter_map ( |msg| match msg {
440
465
Ok ( Message :: CompilerMessage ( message) ) => ClippyWarning :: new ( message. message , & self . name , & self . version ) ,
441
466
_ => None ,
442
467
} )
468
+ . map ( ClippyCheckOutput :: ClippyWarning )
443
469
. collect ( ) ;
444
470
445
- warnings
471
+ if let Some ( ice) = RustcIce :: from_stderr_and_status ( & self . name , * status, & stderr) {
472
+ entries. push ( ClippyCheckOutput :: RustcIce ( ice) ) ;
473
+ } else if !status. success ( ) {
474
+ println ! ( "non-ICE bad exit status for {} {}: {}" , self . name, self . version, stderr) ;
475
+ }
476
+
477
+ entries
446
478
}
447
479
}
448
480
@@ -642,7 +674,7 @@ fn main() {
642
674
LintcheckServer :: spawn ( recursive_options)
643
675
} ) ;
644
676
645
- let mut clippy_warnings : Vec < ClippyWarning > = crates
677
+ let mut clippy_entries : Vec < ClippyCheckOutput > = crates
646
678
. par_iter ( )
647
679
. flat_map ( |krate| {
648
680
krate. run_clippy_lints (
@@ -658,28 +690,31 @@ fn main() {
658
690
. collect ( ) ;
659
691
660
692
if let Some ( server) = server {
661
- clippy_warnings. extend ( server. warnings ( ) ) ;
693
+ let server_clippy_entries = server. warnings ( ) . map ( ClippyCheckOutput :: ClippyWarning ) ;
694
+
695
+ clippy_entries. extend ( server_clippy_entries) ;
662
696
}
663
697
664
698
// if we are in --fix mode, don't change the log files, terminate here
665
699
if config. fix {
666
700
return ;
667
701
}
668
702
669
- // generate some stats
670
- let ( stats_formatted, new_stats) = gather_stats ( & clippy_warnings) ;
703
+ // split up warnings and ices
704
+ let mut warnings: Vec < ClippyWarning > = vec ! [ ] ;
705
+ let mut raw_ices: Vec < RustcIce > = vec ! [ ] ;
706
+ for entry in clippy_entries {
707
+ if let ClippyCheckOutput :: ClippyWarning ( x) = entry {
708
+ warnings. push ( x) ;
709
+ } else if let ClippyCheckOutput :: RustcIce ( x) = entry {
710
+ raw_ices. push ( x) ;
711
+ }
712
+ }
671
713
672
- // grab crashes/ICEs, save the crate name and the ice message
673
- let ices: Vec < ( & String , & String ) > = clippy_warnings
674
- . iter ( )
675
- . filter ( |warning| warning. is_ice )
676
- . map ( |w| ( & w. crate_name , & w. message ) )
677
- . collect ( ) ;
714
+ // generate some stats
715
+ let ( stats_formatted, new_stats) = gather_stats ( & warnings) ;
678
716
679
- let mut all_msgs: Vec < String > = clippy_warnings
680
- . iter ( )
681
- . map ( |warn| warn. to_output ( config. markdown ) )
682
- . collect ( ) ;
717
+ let mut all_msgs: Vec < String > = warnings. iter ( ) . map ( |warn| warn. to_output ( config. markdown ) ) . collect ( ) ;
683
718
all_msgs. sort ( ) ;
684
719
all_msgs. push ( "\n \n ### Stats:\n \n " . into ( ) ) ;
685
720
all_msgs. push ( stats_formatted) ;
@@ -693,11 +728,18 @@ fn main() {
693
728
}
694
729
write ! ( text, "{}" , all_msgs. join( "" ) ) . unwrap ( ) ;
695
730
text. push_str ( "\n \n ### ICEs:\n " ) ;
696
- for ( cratename, msg) in & ices {
697
- let _: fmt:: Result = write ! ( text, "{cratename}: '{msg}'" ) ;
731
+ for ice in & raw_ices {
732
+ let _: fmt:: Result = write ! (
733
+ text,
734
+ "{}:\n {}\n ========================================\n \n " ,
735
+ ice. crate_name, ice. ice_content
736
+ ) ;
698
737
}
699
738
700
739
println ! ( "Writing logs to {}" , config. lintcheck_results_path. display( ) ) ;
740
+ if !raw_ices. is_empty ( ) {
741
+ println ! ( "WARNING: at least one ICE reported, check log file" ) ;
742
+ }
701
743
fs:: create_dir_all ( config. lintcheck_results_path . parent ( ) . unwrap ( ) ) . unwrap ( ) ;
702
744
fs:: write ( & config. lintcheck_results_path , text) . unwrap ( ) ;
703
745
0 commit comments