Skip to content

Commit 2fe40b2

Browse files
calebcartwrighttopecongiro
authored andcommitted
update handling of parser errors (#3920)
1 parent 84ffc31 commit 2fe40b2

File tree

3 files changed

+220
-39
lines changed

3 files changed

+220
-39
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,7 @@ version = "610.0.0"
7575
package = "rustc-ap-syntax_pos"
7676
version = "610.0.0"
7777

78+
[dependencies.rustc_data_structures]
79+
package = "rustc-ap-rustc_data_structures"
80+
version = "610.0.0"
81+

src/syntux/session.rs

+215-39
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use std::cell::RefCell;
22
use std::path::Path;
33
use std::rc::Rc;
44

5+
use rustc_data_structures::sync::Send;
56
use syntax::ast;
67
use syntax::errors::emitter::{ColorConfig, Emitter, EmitterWriter};
7-
use syntax::errors::{Diagnostic, Handler};
8+
use syntax::errors::{Diagnostic, Handler, Level as DiagnosticLevel};
89
use syntax::parse::ParseSess as RawParseSess;
910
use syntax::source_map::{FilePathMapping, SourceMap};
1011
use 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`.
3839
struct 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+
4655
impl 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-
7678
fn 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

Comments
 (0)