@@ -19,12 +19,12 @@ use std::env::consts::EXE_SUFFIX;
1919use std:: fmt:: { self , Write as _} ;
2020use std:: io:: { self , ErrorKind } ;
2121use std:: path:: { Path , PathBuf } ;
22- use std:: process:: Command ;
22+ use std:: process:: { Command , ExitStatus } ;
2323use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
2424use std:: time:: Duration ;
2525use std:: { env, fs, thread} ;
2626
27- use cargo_metadata:: diagnostic:: { Diagnostic , DiagnosticLevel } ;
27+ use cargo_metadata:: diagnostic:: Diagnostic ;
2828use cargo_metadata:: Message ;
2929use rayon:: prelude:: * ;
3030use serde:: { Deserialize , Serialize } ;
@@ -90,16 +90,43 @@ struct Crate {
9090 options : Option < Vec < String > > ,
9191}
9292
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+
93122/// A single warning that clippy issued while checking a `Crate`
94123#[ derive( Debug ) ]
95124struct ClippyWarning {
96- crate_name : String ,
97125 file : String ,
98126 line : usize ,
99127 column : usize ,
100128 lint_type : String ,
101129 message : String ,
102- is_ice : bool ,
103130}
104131
105132#[ allow( unused) ]
@@ -124,13 +151,11 @@ impl ClippyWarning {
124151 } ;
125152
126153 Some ( Self {
127- crate_name : crate_name. to_owned ( ) ,
128154 file,
129155 line : span. line_start ,
130156 column : span. column_start ,
131157 lint_type,
132158 message : diag. message ,
133- is_ice : diag. level == DiagnosticLevel :: Ice ,
134159 } )
135160 }
136161
@@ -311,7 +336,7 @@ impl Crate {
311336 config : & LintcheckConfig ,
312337 lint_filter : & [ String ] ,
313338 server : & Option < LintcheckServer > ,
314- ) -> Vec < ClippyWarning > {
339+ ) -> Vec < ClippyCheckOutput > {
315340 // advance the atomic index by one
316341 let index = target_dir_index. fetch_add ( 1 , Ordering :: SeqCst ) ;
317342 // "loop" the index within 0..thread_limit
@@ -335,9 +360,9 @@ impl Crate {
335360 let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir" ) ;
336361
337362 let mut cargo_clippy_args = if config. fix {
338- vec ! [ "--fix" , "--" ]
363+ vec ! [ "--quiet" , "-- fix", "--" ]
339364 } else {
340- vec ! [ "--" , "--message-format=json" , "--" ]
365+ vec ! [ "--quiet " , "--message-format=json" , "--" ]
341366 } ;
342367
343368 let mut clippy_args = Vec :: < & str > :: new ( ) ;
@@ -428,14 +453,21 @@ impl Crate {
428453 }
429454
430455 // 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 ( ) )
432457 . filter_map ( |msg| match msg {
433458 Ok ( Message :: CompilerMessage ( message) ) => ClippyWarning :: new ( message. message , & self . name , & self . version ) ,
434459 _ => None ,
435460 } )
461+ . map ( ClippyCheckOutput :: ClippyWarning )
436462 . collect ( ) ;
437463
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
439471 }
440472}
441473
@@ -635,7 +667,7 @@ fn main() {
635667 LintcheckServer :: spawn ( recursive_options)
636668 } ) ;
637669
638- let mut clippy_warnings : Vec < ClippyWarning > = crates
670+ let mut clippy_entries : Vec < ClippyCheckOutput > = crates
639671 . par_iter ( )
640672 . flat_map ( |krate| {
641673 krate. run_clippy_lints (
@@ -651,28 +683,31 @@ fn main() {
651683 . collect ( ) ;
652684
653685 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) ;
655689 }
656690
657691 // if we are in --fix mode, don't change the log files, terminate here
658692 if config. fix {
659693 return ;
660694 }
661695
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+ }
664706
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) ;
671709
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 ( ) ;
676711 all_msgs. sort ( ) ;
677712 all_msgs. push ( "\n \n ### Stats:\n \n " . into ( ) ) ;
678713 all_msgs. push ( stats_formatted) ;
@@ -686,11 +721,18 @@ fn main() {
686721 }
687722 write ! ( text, "{}" , all_msgs. join( "" ) ) . unwrap ( ) ;
688723 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 ! (
726+ text,
727+ "{}:\n {}\n ========================================\n \n " ,
728+ ice. crate_name, ice. ice_content
729+ ) ;
691730 }
692731
693732 println ! ( "Writing logs to {}" , config. lintcheck_results_path. display( ) ) ;
733+ if !raw_ices. is_empty ( ) {
734+ println ! ( "WARNING: at least one ICE reported, check log file" ) ;
735+ }
694736 fs:: create_dir_all ( config. lintcheck_results_path . parent ( ) . unwrap ( ) ) . unwrap ( ) ;
695737 fs:: write ( & config. lintcheck_results_path , text) . unwrap ( ) ;
696738
0 commit comments