1
1
// High level formatting functions.
2
2
3
+ use std:: cell:: Cell ;
3
4
use std:: collections:: HashMap ;
4
5
use std:: io:: { self , Write } ;
5
6
use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
@@ -27,6 +28,8 @@ mod newline_style;
27
28
pub ( crate ) type SourceFile = Vec < FileRecord > ;
28
29
pub ( crate ) type FileRecord = ( FileName , String ) ;
29
30
31
+ thread_local ! ( static CAN_RESET_CRATE_PARSE_ERRORS : Cell <bool > = Cell :: new( false ) ) ;
32
+
30
33
impl < ' b , T : Write + ' b > Session < ' b , T > {
31
34
pub ( crate ) fn format_input_inner ( & mut self , input : Input ) -> Result < FormatReport , ErrorKind > {
32
35
if !self . config . version_meets_requirement ( ) {
@@ -70,17 +73,16 @@ fn format_project<T: FormatHandler>(
70
73
Ok ( set) => set,
71
74
Err ( e) => return Err ( ErrorKind :: InvalidGlobPattern ( e) ) ,
72
75
} ;
73
- let is_ignore_match = ignore_path_set. is_match ( & main_file) ;
74
- if config. skip_children ( ) && is_ignore_match {
76
+ if config. skip_children ( ) && ignore_path_set. is_match ( & main_file) {
75
77
return Ok ( FormatReport :: new ( ) ) ;
76
78
}
79
+ let _ = CAN_RESET_CRATE_PARSE_ERRORS . try_with ( |r| {
80
+ r. set ( false ) ;
81
+ } ) ;
77
82
78
83
// Parse the crate.
79
84
let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
80
85
let mut parse_session = make_parse_sess ( source_map. clone ( ) , config, & ignore_path_set) ;
81
- if is_ignore_match {
82
- parse_session. span_diagnostic = Handler :: with_emitter ( true , None , silent_emitter ( ) ) ;
83
- }
84
86
let mut report = FormatReport :: new ( ) ;
85
87
let directory_ownership = input. to_directory_ownership ( ) ;
86
88
let krate = match parse_crate (
@@ -92,13 +94,7 @@ fn format_project<T: FormatHandler>(
92
94
) {
93
95
Ok ( krate) => krate,
94
96
// Surface parse error via Session (errors are merged there from report)
95
- Err ( ErrorKind :: ParseError ) => {
96
- // https://github.com/rust-lang/rustfmt/issues/3779
97
- if is_ignore_match {
98
- return Ok ( FormatReport :: new ( ) ) ;
99
- }
100
- return Ok ( report) ;
101
- }
97
+ Err ( ErrorKind :: ParseError ) => return Ok ( report) ,
102
98
Err ( e) => return Err ( e) ,
103
99
} ;
104
100
timer = timer. done_parsing ( ) ;
@@ -677,6 +673,19 @@ fn parse_crate(
677
673
if !parse_session. span_diagnostic . has_errors ( ) {
678
674
return Ok ( c) ;
679
675
}
676
+ // This scenario occurs when the parser encountered errors
677
+ // but was still able to recover. If all of the parser errors
678
+ // occurred in files that are ignored, then reset
679
+ // the error count and continue.
680
+ // https://github.com/rust-lang/rustfmt/issues/3779
681
+ let mut can_reset = false ;
682
+ let _ = CAN_RESET_CRATE_PARSE_ERRORS . try_with ( |r| {
683
+ can_reset = r. get ( ) ;
684
+ } ) ;
685
+ if can_reset {
686
+ parse_session. span_diagnostic . reset_err_count ( ) ;
687
+ return Ok ( c) ;
688
+ }
680
689
}
681
690
Ok ( Err ( mut diagnostics) ) => diagnostics. iter_mut ( ) . for_each ( DiagnosticBuilder :: emit) ,
682
691
Err ( _) => {
@@ -697,6 +706,8 @@ struct SilentOnIgnoredFilesEmitter {
697
706
ignore_path_set : IgnorePathSet ,
698
707
source_map : Rc < SourceMap > ,
699
708
emitter : EmitterWriter ,
709
+ can_reset : bool ,
710
+ has_non_ignorable_parser_errors : bool ,
700
711
}
701
712
702
713
impl Emitter for SilentOnIgnoredFilesEmitter {
@@ -709,13 +720,26 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
709
720
. ignore_path_set
710
721
. is_match ( & FileName :: Real ( path. to_path_buf ( ) ) )
711
722
{
712
- db. handler . reset_err_count ( ) ;
723
+ if !self . has_non_ignorable_parser_errors && !self . can_reset {
724
+ let _ = CAN_RESET_CRATE_PARSE_ERRORS . try_with ( |r| {
725
+ r. set ( true ) ;
726
+ } ) ;
727
+ self . can_reset = true ;
728
+ }
713
729
return ;
714
730
}
715
731
}
716
732
_ => ( ) ,
717
733
} ;
718
734
}
735
+
736
+ self . has_non_ignorable_parser_errors = true ;
737
+ if self . can_reset {
738
+ let _ = CAN_RESET_CRATE_PARSE_ERRORS . try_with ( |r| {
739
+ r. set ( false ) ;
740
+ } ) ;
741
+ }
742
+ self . can_reset = false ;
719
743
self . emitter . emit_diagnostic ( db) ;
720
744
}
721
745
}
@@ -746,9 +770,12 @@ fn make_parse_sess(
746
770
} else {
747
771
ColorConfig :: Never
748
772
} ;
773
+
749
774
let emitter_writer =
750
- EmitterWriter :: stderr ( color_cfg, Some ( source_map. clone ( ) ) , false , false ) ;
775
+ EmitterWriter :: stderr ( color_cfg, Some ( source_map. clone ( ) ) , false , false , None ) ;
751
776
let emitter = Box :: new ( SilentOnIgnoredFilesEmitter {
777
+ has_non_ignorable_parser_errors : false ,
778
+ can_reset : false ,
752
779
ignore_path_set : ignore_path_set. clone ( ) ,
753
780
source_map : source_map. clone ( ) ,
754
781
emitter : emitter_writer,
0 commit comments