@@ -2,9 +2,10 @@ use std::cell::RefCell;
22use std:: path:: Path ;
33use std:: rc:: Rc ;
44
5+ use rustc_data_structures:: sync;
56use syntax:: ast;
67use syntax:: errors:: emitter:: { ColorConfig , Emitter , EmitterWriter } ;
7- use syntax:: errors:: { Diagnostic , Handler } ;
8+ use syntax:: errors:: { Diagnostic , Handler , Level as DiagnosticLevel } ;
89use syntax:: parse:: ParseSess as RawParseSess ;
910use syntax:: source_map:: { FilePathMapping , SourceMap } ;
1011use syntax_pos:: { BytePos , Span } ;
@@ -30,53 +31,55 @@ impl Emitter for SilentEmitter {
3031 fn emit_diagnostic ( & mut self , _db : & Diagnostic ) { }
3132}
3233
33- fn silent_emitter ( ) -> Box < SilentEmitter > {
34+ fn silent_emitter ( ) -> Box < dyn Emitter + sync :: Send > {
3435 Box :: new ( SilentEmitter { } )
3536}
3637
3738/// Emit errors against every files expect ones specified in the `ignore_path_set`.
3839struct SilentOnIgnoredFilesEmitter {
3940 ignore_path_set : Rc < IgnorePathSet > ,
4041 source_map : Rc < SourceMap > ,
41- emitter : EmitterWriter ,
42+ emitter : Box < dyn Emitter + sync :: Send > ,
4243 has_non_ignorable_parser_errors : bool ,
4344 can_reset : Rc < RefCell < bool > > ,
4445}
4546
47+ impl SilentOnIgnoredFilesEmitter {
48+ fn handle_non_ignoreable_error ( & mut self , db : & Diagnostic ) {
49+ self . has_non_ignorable_parser_errors = true ;
50+ * self . can_reset . borrow_mut ( ) = false ;
51+ self . emitter . emit_diagnostic ( db) ;
52+ }
53+ }
54+
4655impl Emitter for SilentOnIgnoredFilesEmitter {
4756 fn emit_diagnostic ( & mut self , db : & Diagnostic ) {
57+ if db. level == DiagnosticLevel :: Fatal {
58+ return self . handle_non_ignoreable_error ( db) ;
59+ }
4860 if let Some ( primary_span) = & db. span . primary_span ( ) {
4961 let file_name = self . source_map . span_to_filename ( * primary_span) ;
50- match file_name {
51- syntax_pos:: FileName :: Real ( ref path) => {
52- if self
53- . ignore_path_set
54- . is_match ( & FileName :: Real ( path. to_path_buf ( ) ) )
55- {
56- if !self . has_non_ignorable_parser_errors {
57- * self . can_reset . borrow_mut ( ) = true ;
58- }
59- return ;
62+ if let syntax_pos:: FileName :: Real ( ref path) = file_name {
63+ if self
64+ . ignore_path_set
65+ . is_match ( & FileName :: Real ( path. to_path_buf ( ) ) )
66+ {
67+ if !self . has_non_ignorable_parser_errors {
68+ * self . can_reset . borrow_mut ( ) = true ;
6069 }
70+ return ;
6171 }
62- _ => ( ) ,
6372 } ;
6473 }
65-
66- self . has_non_ignorable_parser_errors = true ;
67- * self . can_reset . borrow_mut ( ) = false ;
68- self . emitter . emit_diagnostic ( db) ;
74+ self . handle_non_ignoreable_error ( db) ;
6975 }
7076}
7177
72- fn silent_handler ( ) -> Handler {
73- Handler :: with_emitter ( true , None , silent_emitter ( ) )
74- }
75-
7678fn default_handler (
7779 source_map : Rc < SourceMap > ,
7880 ignore_path_set : Rc < IgnorePathSet > ,
7981 can_reset : Rc < RefCell < bool > > ,
82+ hide_parse_errors : bool ,
8083) -> Handler {
8184 let supports_color = term:: stderr ( ) . map_or ( false , |term| term. supports_color ( ) ) ;
8285 let color_cfg = if supports_color {
@@ -85,14 +88,18 @@ fn default_handler(
8588 ColorConfig :: Never
8689 } ;
8790
88- let emitter = EmitterWriter :: stderr (
89- color_cfg,
90- Some ( source_map. clone ( ) ) ,
91- false ,
92- false ,
93- None ,
94- false ,
95- ) ;
91+ let emitter = if hide_parse_errors {
92+ silent_emitter ( )
93+ } else {
94+ Box :: new ( EmitterWriter :: stderr (
95+ color_cfg,
96+ Some ( source_map. clone ( ) ) ,
97+ false ,
98+ false ,
99+ None ,
100+ false ,
101+ ) )
102+ } ;
96103 Handler :: with_emitter (
97104 true ,
98105 None ,
@@ -115,15 +122,12 @@ impl ParseSess {
115122 let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
116123 let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
117124
118- let handler = if config. hide_parse_errors ( ) {
119- silent_handler ( )
120- } else {
121- default_handler (
122- Rc :: clone ( & source_map) ,
123- Rc :: clone ( & ignore_path_set) ,
124- Rc :: clone ( & can_reset_errors) ,
125- )
126- } ;
125+ let handler = default_handler (
126+ Rc :: clone ( & source_map) ,
127+ Rc :: clone ( & ignore_path_set) ,
128+ Rc :: clone ( & can_reset_errors) ,
129+ config. hide_parse_errors ( ) ,
130+ ) ;
127131 let parse_sess = RawParseSess :: with_span_handler ( handler, source_map) ;
128132
129133 Ok ( ParseSess {
@@ -257,3 +261,165 @@ impl LineRangeUtils for ParseSess {
257261 }
258262 }
259263}
264+
265+ #[ cfg( test) ]
266+ mod tests {
267+ use super :: * ;
268+
269+ mod emitter {
270+ use super :: * ;
271+ use crate :: config:: IgnoreList ;
272+ use crate :: utils:: mk_sp;
273+ use std:: path:: PathBuf ;
274+ use syntax:: source_map:: FileName as SourceMapFileName ;
275+ use syntax_pos:: MultiSpan ;
276+
277+ struct TestEmitter {
278+ num_emitted_errors : Rc < RefCell < u32 > > ,
279+ }
280+
281+ impl Emitter for TestEmitter {
282+ fn emit_diagnostic ( & mut self , _db : & Diagnostic ) {
283+ * self . num_emitted_errors . borrow_mut ( ) += 1 ;
284+ }
285+ }
286+
287+ fn build_diagnostic ( level : DiagnosticLevel , span : Option < MultiSpan > ) -> Diagnostic {
288+ Diagnostic {
289+ level,
290+ code : None ,
291+ message : vec ! [ ] ,
292+ children : vec ! [ ] ,
293+ suggestions : vec ! [ ] ,
294+ span : span. unwrap_or_else ( || MultiSpan :: new ( ) ) ,
295+ }
296+ }
297+
298+ fn build_emitter (
299+ num_emitted_errors : Rc < RefCell < u32 > > ,
300+ can_reset : Rc < RefCell < bool > > ,
301+ source_map : Option < Rc < SourceMap > > ,
302+ ignore_list : Option < IgnoreList > ,
303+ ) -> SilentOnIgnoredFilesEmitter {
304+ let emitter_writer = TestEmitter { num_emitted_errors } ;
305+ let source_map =
306+ source_map. unwrap_or_else ( || Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ) ;
307+ let ignore_path_set = Rc :: new (
308+ IgnorePathSet :: from_ignore_list (
309+ & ignore_list. unwrap_or_else ( || IgnoreList :: default ( ) ) ,
310+ )
311+ . unwrap ( ) ,
312+ ) ;
313+ SilentOnIgnoredFilesEmitter {
314+ has_non_ignorable_parser_errors : false ,
315+ source_map,
316+ emitter : Box :: new ( emitter_writer) ,
317+ ignore_path_set,
318+ can_reset,
319+ }
320+ }
321+
322+ fn get_ignore_list ( config : & str ) -> IgnoreList {
323+ Config :: from_toml ( config, Path :: new ( "" ) ) . unwrap ( ) . ignore ( )
324+ }
325+
326+ #[ test]
327+ fn handles_fatal_parse_error_in_ignored_file ( ) {
328+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
329+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
330+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
331+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
332+ let source =
333+ String :: from ( r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "# ) ;
334+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
335+ let mut emitter = build_emitter (
336+ Rc :: clone ( & num_emitted_errors) ,
337+ Rc :: clone ( & can_reset_errors) ,
338+ Some ( Rc :: clone ( & source_map) ) ,
339+ Some ( ignore_list) ,
340+ ) ;
341+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
342+ let fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Fatal , Some ( span) ) ;
343+ emitter. emit_diagnostic ( & fatal_diagnostic) ;
344+ assert_eq ! ( * num_emitted_errors. borrow( ) , 1 ) ;
345+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
346+ }
347+
348+ #[ test]
349+ fn handles_recoverable_parse_error_in_ignored_file ( ) {
350+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
351+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
352+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
353+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
354+ let source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
355+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
356+ let mut emitter = build_emitter (
357+ Rc :: clone ( & num_emitted_errors) ,
358+ Rc :: clone ( & can_reset_errors) ,
359+ Some ( Rc :: clone ( & source_map) ) ,
360+ Some ( ignore_list) ,
361+ ) ;
362+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
363+ let non_fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( span) ) ;
364+ emitter. emit_diagnostic ( & non_fatal_diagnostic) ;
365+ assert_eq ! ( * num_emitted_errors. borrow( ) , 0 ) ;
366+ assert_eq ! ( * can_reset_errors. borrow( ) , true ) ;
367+ }
368+
369+ #[ test]
370+ fn handles_recoverable_parse_error_in_non_ignored_file ( ) {
371+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
372+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
373+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
374+ let source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
375+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
376+ let mut emitter = build_emitter (
377+ Rc :: clone ( & num_emitted_errors) ,
378+ Rc :: clone ( & can_reset_errors) ,
379+ Some ( Rc :: clone ( & source_map) ) ,
380+ None ,
381+ ) ;
382+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
383+ let non_fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( span) ) ;
384+ emitter. emit_diagnostic ( & non_fatal_diagnostic) ;
385+ assert_eq ! ( * num_emitted_errors. borrow( ) , 1 ) ;
386+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
387+ }
388+
389+ #[ test]
390+ fn handles_mix_of_recoverable_parse_error ( ) {
391+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
392+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
393+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
394+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
395+ let bar_source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
396+ let foo_source = String :: from ( r#"pub fn foo() { 1x; }"# ) ;
397+ let fatal_source =
398+ String :: from ( r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "# ) ;
399+ source_map
400+ . new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "bar.rs" ) ) , bar_source) ;
401+ source_map
402+ . new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , foo_source) ;
403+ source_map. new_source_file (
404+ SourceMapFileName :: Real ( PathBuf :: from ( "fatal.rs" ) ) ,
405+ fatal_source,
406+ ) ;
407+ let mut emitter = build_emitter (
408+ Rc :: clone ( & num_emitted_errors) ,
409+ Rc :: clone ( & can_reset_errors) ,
410+ Some ( Rc :: clone ( & source_map) ) ,
411+ Some ( ignore_list) ,
412+ ) ;
413+ let bar_span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
414+ let foo_span = MultiSpan :: from_span ( mk_sp ( BytePos ( 21 ) , BytePos ( 22 ) ) ) ;
415+ let bar_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( bar_span) ) ;
416+ let foo_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( foo_span) ) ;
417+ let fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Fatal , None ) ;
418+ emitter. emit_diagnostic ( & bar_diagnostic) ;
419+ emitter. emit_diagnostic ( & foo_diagnostic) ;
420+ emitter. emit_diagnostic ( & fatal_diagnostic) ;
421+ assert_eq ! ( * num_emitted_errors. borrow( ) , 2 ) ;
422+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
423+ }
424+ }
425+ }
0 commit comments