@@ -2,9 +2,10 @@ use std::cell::RefCell;
2
2
use std:: path:: Path ;
3
3
use std:: rc:: Rc ;
4
4
5
+ use rustc_data_structures:: sync;
5
6
use syntax:: ast;
6
7
use syntax:: errors:: emitter:: { ColorConfig , Emitter , EmitterWriter } ;
7
- use syntax:: errors:: { Diagnostic , Handler } ;
8
+ use syntax:: errors:: { Diagnostic , Handler , Level as DiagnosticLevel } ;
8
9
use syntax:: parse:: ParseSess as RawParseSess ;
9
10
use syntax:: source_map:: { FilePathMapping , SourceMap } ;
10
11
use syntax_pos:: { BytePos , Span } ;
@@ -30,53 +31,55 @@ impl Emitter for SilentEmitter {
30
31
fn emit_diagnostic ( & mut self , _db : & Diagnostic ) { }
31
32
}
32
33
33
- fn silent_emitter ( ) -> Box < SilentEmitter > {
34
+ fn silent_emitter ( ) -> Box < dyn Emitter + sync :: Send > {
34
35
Box :: new ( SilentEmitter { } )
35
36
}
36
37
37
38
/// Emit errors against every files expect ones specified in the `ignore_path_set`.
38
39
struct SilentOnIgnoredFilesEmitter {
39
40
ignore_path_set : Rc < IgnorePathSet > ,
40
41
source_map : Rc < SourceMap > ,
41
- emitter : EmitterWriter ,
42
+ emitter : Box < dyn Emitter + sync :: Send > ,
42
43
has_non_ignorable_parser_errors : bool ,
43
44
can_reset : Rc < RefCell < bool > > ,
44
45
}
45
46
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
+
46
55
impl Emitter for SilentOnIgnoredFilesEmitter {
47
56
fn emit_diagnostic ( & mut self , db : & Diagnostic ) {
57
+ if db. level == DiagnosticLevel :: Fatal {
58
+ return self . handle_non_ignoreable_error ( db) ;
59
+ }
48
60
if let Some ( primary_span) = & db. span . primary_span ( ) {
49
61
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 ;
60
69
}
70
+ return ;
61
71
}
62
- _ => ( ) ,
63
72
} ;
64
73
}
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) ;
69
75
}
70
76
}
71
77
72
- fn silent_handler ( ) -> Handler {
73
- Handler :: with_emitter ( true , None , silent_emitter ( ) )
74
- }
75
-
76
78
fn default_handler (
77
79
source_map : Rc < SourceMap > ,
78
80
ignore_path_set : Rc < IgnorePathSet > ,
79
81
can_reset : Rc < RefCell < bool > > ,
82
+ hide_parse_errors : bool ,
80
83
) -> Handler {
81
84
let supports_color = term:: stderr ( ) . map_or ( false , |term| term. supports_color ( ) ) ;
82
85
let color_cfg = if supports_color {
@@ -85,14 +88,18 @@ fn default_handler(
85
88
ColorConfig :: Never
86
89
} ;
87
90
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
+ } ;
96
103
Handler :: with_emitter (
97
104
true ,
98
105
None ,
@@ -115,15 +122,12 @@ impl ParseSess {
115
122
let source_map = Rc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
116
123
let can_reset_errors = Rc :: new ( RefCell :: new ( false ) ) ;
117
124
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
+ ) ;
127
131
let parse_sess = RawParseSess :: with_span_handler ( handler, source_map) ;
128
132
129
133
Ok ( ParseSess {
@@ -257,3 +261,165 @@ impl LineRangeUtils for ParseSess {
257
261
}
258
262
}
259
263
}
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