@@ -26,12 +26,12 @@ use std::env::consts::EXE_SUFFIX;
2626use std:: fmt:: { self , Write as _} ;
2727use std:: io:: { self , ErrorKind } ;
2828use std:: path:: { Path , PathBuf } ;
29- use std:: process:: Command ;
29+ use std:: process:: { Command , ExitStatus } ;
3030use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
3131use std:: time:: Duration ;
3232use std:: { env, fs, thread} ;
3333
34- use cargo_metadata:: diagnostic:: { Diagnostic , DiagnosticLevel } ;
34+ use cargo_metadata:: diagnostic:: Diagnostic ;
3535use cargo_metadata:: Message ;
3636use rayon:: prelude:: * ;
3737use serde:: { Deserialize , Serialize } ;
@@ -97,16 +97,43 @@ struct Crate {
9797 options : Option < Vec < String > > ,
9898}
9999
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+
100129/// A single warning that clippy issued while checking a `Crate`
101130#[ derive( Debug ) ]
102131struct ClippyWarning {
103- crate_name : String ,
104132 file : String ,
105133 line : usize ,
106134 column : usize ,
107135 lint_type : String ,
108136 message : String ,
109- is_ice : bool ,
110137}
111138
112139#[ allow( unused) ]
@@ -131,13 +158,11 @@ impl ClippyWarning {
131158 } ;
132159
133160 Some ( Self {
134- crate_name : crate_name. to_owned ( ) ,
135161 file,
136162 line : span. line_start ,
137163 column : span. column_start ,
138164 lint_type,
139165 message : diag. message ,
140- is_ice : diag. level == DiagnosticLevel :: Ice ,
141166 } )
142167 }
143168
@@ -318,7 +343,7 @@ impl Crate {
318343 config : & LintcheckConfig ,
319344 lint_filter : & [ String ] ,
320345 server : & Option < LintcheckServer > ,
321- ) -> Vec < ClippyWarning > {
346+ ) -> Vec < ClippyCheckOutput > {
322347 // advance the atomic index by one
323348 let index = target_dir_index. fetch_add ( 1 , Ordering :: SeqCst ) ;
324349 // "loop" the index within 0..thread_limit
@@ -342,9 +367,9 @@ impl Crate {
342367 let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir" ) ;
343368
344369 let mut cargo_clippy_args = if config. fix {
345- vec ! [ "--fix" , "--" ]
370+ vec ! [ "--quiet" , "-- fix", "--" ]
346371 } else {
347- vec ! [ "--" , "--message-format=json" , "--" ]
372+ vec ! [ "--quiet " , "--message-format=json" , "--" ]
348373 } ;
349374
350375 let mut clippy_args = Vec :: < & str > :: new ( ) ;
@@ -435,14 +460,21 @@ impl Crate {
435460 }
436461
437462 // 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 ( ) )
439464 . filter_map ( |msg| match msg {
440465 Ok ( Message :: CompilerMessage ( message) ) => ClippyWarning :: new ( message. message , & self . name , & self . version ) ,
441466 _ => None ,
442467 } )
468+ . map ( ClippyCheckOutput :: ClippyWarning )
443469 . collect ( ) ;
444470
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
446478 }
447479}
448480
@@ -642,7 +674,7 @@ fn main() {
642674 LintcheckServer :: spawn ( recursive_options)
643675 } ) ;
644676
645- let mut clippy_warnings : Vec < ClippyWarning > = crates
677+ let mut clippy_entries : Vec < ClippyCheckOutput > = crates
646678 . par_iter ( )
647679 . flat_map ( |krate| {
648680 krate. run_clippy_lints (
@@ -658,28 +690,31 @@ fn main() {
658690 . collect ( ) ;
659691
660692 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) ;
662696 }
663697
664698 // if we are in --fix mode, don't change the log files, terminate here
665699 if config. fix {
666700 return ;
667701 }
668702
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+ }
671713
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) ;
678716
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 ( ) ;
683718 all_msgs. sort ( ) ;
684719 all_msgs. push ( "\n \n ### Stats:\n \n " . into ( ) ) ;
685720 all_msgs. push ( stats_formatted) ;
@@ -693,11 +728,18 @@ fn main() {
693728 }
694729 write ! ( text, "{}" , all_msgs. join( "" ) ) . unwrap ( ) ;
695730 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+ ) ;
698737 }
699738
700739 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+ }
701743 fs:: create_dir_all ( config. lintcheck_results_path . parent ( ) . unwrap ( ) ) . unwrap ( ) ;
702744 fs:: write ( & config. lintcheck_results_path , text) . unwrap ( ) ;
703745
0 commit comments