@@ -2,9 +2,10 @@ use std::cell::RefCell;
22use std:: path:: Path ;
33use std:: rc:: Rc ;
44
5+ use rustc_data_structures:: sync:: Send ;
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 + 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 + 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,175 @@ 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 :: is_nightly_channel;
273+ use crate :: utils:: mk_sp;
274+ use std:: path:: PathBuf ;
275+ use syntax:: source_map:: FileName as SourceMapFileName ;
276+ use syntax_pos:: MultiSpan ;
277+
278+ struct TestEmitter {
279+ num_emitted_errors : Rc < RefCell < u32 > > ,
280+ }
281+
282+ impl Emitter for TestEmitter {
283+ fn emit_diagnostic ( & mut self , _db : & Diagnostic ) {
284+ * self . num_emitted_errors . borrow_mut ( ) += 1 ;
285+ }
286+ }
287+
288+ fn build_diagnostic ( level : DiagnosticLevel , span : Option < MultiSpan > ) -> Diagnostic {
289+ Diagnostic {
290+ level,
291+ code : None ,
292+ message : vec ! [ ] ,
293+ children : vec ! [ ] ,
294+ suggestions : vec ! [ ] ,
295+ span : span. unwrap_or_else ( || MultiSpan :: new ( ) ) ,
296+ }
297+ }
298+
299+ fn build_emitter (
300+ num_emitted_errors : Rc < RefCell < u32 > > ,
301+ can_reset : Rc < RefCell < bool > > ,
302+ source_map : Option < Rc < SourceMap > > ,
303+ ignore_list : Option < IgnoreList > ,
304+ ) -> SilentOnIgnoredFilesEmitter {
305+ let emitter_writer = TestEmitter { num_emitted_errors } ;
306+ let source_map =
307+ source_map. unwrap_or_else ( || Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ) ;
308+ let ignore_path_set = Rc :: new (
309+ IgnorePathSet :: from_ignore_list (
310+ & ignore_list. unwrap_or_else ( || IgnoreList :: default ( ) ) ,
311+ )
312+ . unwrap ( ) ,
313+ ) ;
314+ SilentOnIgnoredFilesEmitter {
315+ has_non_ignorable_parser_errors : false ,
316+ source_map,
317+ emitter : Box :: new ( emitter_writer) ,
318+ ignore_path_set,
319+ can_reset,
320+ }
321+ }
322+
323+ fn get_ignore_list ( config : & str ) -> IgnoreList {
324+ Config :: from_toml ( config, Path :: new ( "" ) ) . unwrap ( ) . ignore ( )
325+ }
326+
327+ #[ test]
328+ fn handles_fatal_parse_error_in_ignored_file ( ) {
329+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
330+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
331+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
332+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
333+ let source =
334+ String :: from ( r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "# ) ;
335+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
336+ let mut emitter = build_emitter (
337+ Rc :: clone ( & num_emitted_errors) ,
338+ Rc :: clone ( & can_reset_errors) ,
339+ Some ( Rc :: clone ( & source_map) ) ,
340+ Some ( ignore_list) ,
341+ ) ;
342+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
343+ let fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Fatal , Some ( span) ) ;
344+ emitter. emit_diagnostic ( & fatal_diagnostic) ;
345+ assert_eq ! ( * num_emitted_errors. borrow( ) , 1 ) ;
346+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
347+ }
348+
349+ #[ test]
350+ fn handles_recoverable_parse_error_in_ignored_file ( ) {
351+ if !is_nightly_channel ! ( ) {
352+ return ;
353+ }
354+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
355+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
356+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
357+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
358+ let source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
359+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
360+ let mut emitter = build_emitter (
361+ Rc :: clone ( & num_emitted_errors) ,
362+ Rc :: clone ( & can_reset_errors) ,
363+ Some ( Rc :: clone ( & source_map) ) ,
364+ Some ( ignore_list) ,
365+ ) ;
366+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
367+ let non_fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( span) ) ;
368+ emitter. emit_diagnostic ( & non_fatal_diagnostic) ;
369+ assert_eq ! ( * num_emitted_errors. borrow( ) , 0 ) ;
370+ assert_eq ! ( * can_reset_errors. borrow( ) , true ) ;
371+ }
372+
373+ #[ test]
374+ fn handles_recoverable_parse_error_in_non_ignored_file ( ) {
375+ if !is_nightly_channel ! ( ) {
376+ return ;
377+ }
378+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
379+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
380+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
381+ let source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
382+ source_map. new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , source) ;
383+ let mut emitter = build_emitter (
384+ Rc :: clone ( & num_emitted_errors) ,
385+ Rc :: clone ( & can_reset_errors) ,
386+ Some ( Rc :: clone ( & source_map) ) ,
387+ None ,
388+ ) ;
389+ let span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
390+ let non_fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( span) ) ;
391+ emitter. emit_diagnostic ( & non_fatal_diagnostic) ;
392+ assert_eq ! ( * num_emitted_errors. borrow( ) , 1 ) ;
393+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
394+ }
395+
396+ #[ test]
397+ fn handles_mix_of_recoverable_parse_error ( ) {
398+ if !is_nightly_channel ! ( ) {
399+ return ;
400+ }
401+ let num_emitted_errors = Rc :: new ( RefCell :: new ( 0 ) ) ;
402+ let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
403+ let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
404+ let ignore_list = get_ignore_list ( r#"ignore = ["foo.rs"]"# ) ;
405+ let bar_source = String :: from ( r#"pub fn bar() { 1x; }"# ) ;
406+ let foo_source = String :: from ( r#"pub fn foo() { 1x; }"# ) ;
407+ let fatal_source =
408+ String :: from ( r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "# ) ;
409+ source_map
410+ . new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "bar.rs" ) ) , bar_source) ;
411+ source_map
412+ . new_source_file ( SourceMapFileName :: Real ( PathBuf :: from ( "foo.rs" ) ) , foo_source) ;
413+ source_map. new_source_file (
414+ SourceMapFileName :: Real ( PathBuf :: from ( "fatal.rs" ) ) ,
415+ fatal_source,
416+ ) ;
417+ let mut emitter = build_emitter (
418+ Rc :: clone ( & num_emitted_errors) ,
419+ Rc :: clone ( & can_reset_errors) ,
420+ Some ( Rc :: clone ( & source_map) ) ,
421+ Some ( ignore_list) ,
422+ ) ;
423+ let bar_span = MultiSpan :: from_span ( mk_sp ( BytePos ( 0 ) , BytePos ( 1 ) ) ) ;
424+ let foo_span = MultiSpan :: from_span ( mk_sp ( BytePos ( 21 ) , BytePos ( 22 ) ) ) ;
425+ let bar_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( bar_span) ) ;
426+ let foo_diagnostic = build_diagnostic ( DiagnosticLevel :: Warning , Some ( foo_span) ) ;
427+ let fatal_diagnostic = build_diagnostic ( DiagnosticLevel :: Fatal , None ) ;
428+ emitter. emit_diagnostic ( & bar_diagnostic) ;
429+ emitter. emit_diagnostic ( & foo_diagnostic) ;
430+ emitter. emit_diagnostic ( & fatal_diagnostic) ;
431+ assert_eq ! ( * num_emitted_errors. borrow( ) , 2 ) ;
432+ assert_eq ! ( * can_reset_errors. borrow( ) , false ) ;
433+ }
434+ }
435+ }
0 commit comments