Skip to content

Commit 849e818

Browse files
refactor: update handling of parser errors
1 parent 532973c commit 849e818

File tree

3 files changed

+210
-39
lines changed

3 files changed

+210
-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
@@ -76,3 +76,7 @@ version = "610.0.0"
7676
package = "rustc-ap-syntax_pos"
7777
version = "610.0.0"
7878

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

src/syntux/session.rs

+205-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;
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 + sync::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 + 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+
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,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

Comments
 (0)