Skip to content

Commit ba4bf03

Browse files
calebcartwrighttopecongiro
authored andcommitted
don't fail on recoverable parser errors in ignored files (rust-lang#3782)
1 parent 61f972b commit ba4bf03

File tree

7 files changed

+106
-5
lines changed

7 files changed

+106
-5
lines changed

src/formatting.rs

+78-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// High level formatting functions.
22

3+
use std::cell::RefCell;
34
use std::collections::HashMap;
45
use std::io::{self, Write};
56
use std::panic::{catch_unwind, AssertUnwindSafe};
67
use std::rc::Rc;
78
use std::time::{Duration, Instant};
89

910
use syntax::ast;
10-
use syntax::errors::emitter::{ColorConfig, Emitter};
11+
use syntax::errors::emitter::{ColorConfig, Emitter, EmitterWriter};
1112
use syntax::errors::{Diagnostic, DiagnosticBuilder, Handler};
1213
use syntax::parse::{self, ParseSess};
1314
use syntax::source_map::{FilePathMapping, SourceMap, Span, DUMMY_SP};
@@ -67,16 +68,22 @@ fn format_project<T: FormatHandler>(
6768
let input_is_stdin = main_file == FileName::Stdin;
6869

6970
let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) {
70-
Ok(set) => set,
71+
Ok(set) => Rc::new(set),
7172
Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)),
7273
};
7374
if config.skip_children() && ignore_path_set.is_match(&main_file) {
7475
return Ok(FormatReport::new());
7576
}
7677

7778
// Parse the crate.
79+
let can_reset_parser_errors = Rc::new(RefCell::new(false));
7880
let source_map = Rc::new(SourceMap::new(FilePathMapping::empty()));
79-
let mut parse_session = make_parse_sess(source_map.clone(), config);
81+
let mut parse_session = make_parse_sess(
82+
source_map.clone(),
83+
config,
84+
Rc::clone(&ignore_path_set),
85+
can_reset_parser_errors.clone(),
86+
);
8087
let mut report = FormatReport::new();
8188
let directory_ownership = input.to_directory_ownership();
8289
let krate = match parse_crate(
@@ -85,6 +92,7 @@ fn format_project<T: FormatHandler>(
8592
config,
8693
&mut report,
8794
directory_ownership,
95+
can_reset_parser_errors.clone(),
8896
) {
8997
Ok(krate) => krate,
9098
// Surface parse error via Session (errors are merged there from report)
@@ -620,6 +628,7 @@ fn parse_crate(
620628
config: &Config,
621629
report: &mut FormatReport,
622630
directory_ownership: Option<parse::DirectoryOwnership>,
631+
can_reset_parser_errors: Rc<RefCell<bool>>,
623632
) -> Result<ast::Crate, ErrorKind> {
624633
let input_is_stdin = input.is_text();
625634

@@ -667,6 +676,15 @@ fn parse_crate(
667676
if !parse_session.span_diagnostic.has_errors() {
668677
return Ok(c);
669678
}
679+
// This scenario occurs when the parser encountered errors
680+
// but was still able to recover. If all of the parser errors
681+
// occurred in files that are ignored, then reset
682+
// the error count and continue.
683+
// https://github.com/rust-lang/rustfmt/issues/3779
684+
if *can_reset_parser_errors.borrow() {
685+
parse_session.span_diagnostic.reset_err_count();
686+
return Ok(c);
687+
}
670688
}
671689
Ok(Err(mut diagnostics)) => diagnostics.iter_mut().for_each(DiagnosticBuilder::emit),
672690
Err(_) => {
@@ -683,6 +701,40 @@ fn parse_crate(
683701
Err(ErrorKind::ParseError)
684702
}
685703

704+
struct SilentOnIgnoredFilesEmitter {
705+
ignore_path_set: Rc<IgnorePathSet>,
706+
source_map: Rc<SourceMap>,
707+
emitter: EmitterWriter,
708+
has_non_ignorable_parser_errors: bool,
709+
can_reset: Rc<RefCell<bool>>,
710+
}
711+
712+
impl Emitter for SilentOnIgnoredFilesEmitter {
713+
fn emit_diagnostic(&mut self, db: &Diagnostic) {
714+
if let Some(primary_span) = &db.span.primary_span() {
715+
let file_name = self.source_map.span_to_filename(*primary_span);
716+
match file_name {
717+
syntax_pos::FileName::Real(ref path) => {
718+
if self
719+
.ignore_path_set
720+
.is_match(&FileName::Real(path.to_path_buf()))
721+
{
722+
if !self.has_non_ignorable_parser_errors {
723+
*self.can_reset.borrow_mut() = true;
724+
}
725+
return;
726+
}
727+
}
728+
_ => (),
729+
};
730+
}
731+
732+
self.has_non_ignorable_parser_errors = true;
733+
*self.can_reset.borrow_mut() = false;
734+
self.emitter.emit_diagnostic(db);
735+
}
736+
}
737+
686738
/// Emitter which discards every error.
687739
struct SilentEmitter;
688740

@@ -694,7 +746,12 @@ fn silent_emitter() -> Box<SilentEmitter> {
694746
Box::new(SilentEmitter {})
695747
}
696748

697-
fn make_parse_sess(source_map: Rc<SourceMap>, config: &Config) -> ParseSess {
749+
fn make_parse_sess(
750+
source_map: Rc<SourceMap>,
751+
config: &Config,
752+
ignore_path_set: Rc<IgnorePathSet>,
753+
can_reset: Rc<RefCell<bool>>,
754+
) -> ParseSess {
698755
let tty_handler = if config.hide_parse_errors() {
699756
let silent_emitter = silent_emitter();
700757
Handler::with_emitter(true, None, silent_emitter)
@@ -705,7 +762,23 @@ fn make_parse_sess(source_map: Rc<SourceMap>, config: &Config) -> ParseSess {
705762
} else {
706763
ColorConfig::Never
707764
};
708-
Handler::with_tty_emitter(color_cfg, true, None, Some(source_map.clone()))
765+
766+
let emitter_writer = EmitterWriter::stderr(
767+
color_cfg,
768+
Some(source_map.clone()),
769+
false,
770+
false,
771+
None,
772+
false,
773+
);
774+
let emitter = Box::new(SilentOnIgnoredFilesEmitter {
775+
has_non_ignorable_parser_errors: false,
776+
ignore_path_set: ignore_path_set,
777+
source_map: Rc::clone(&source_map),
778+
emitter: emitter_writer,
779+
can_reset,
780+
});
781+
Handler::with_emitter(true, None, emitter)
709782
};
710783

711784
ParseSess::with_span_handler(tty_handler, source_map)

src/test/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const SKIP_FILE_WHITE_LIST: &[&str] = &[
2727
"configs/skip_children/foo/mod.rs",
2828
"issue-3434/no_entry.rs",
2929
"issue-3665/sub_mod.rs",
30+
// Testing for issue-3779
31+
"issue-3779/ice.rs",
3032
// These files and directory are a part of modules defined inside `cfg_if!`.
3133
"cfg_if/mod.rs",
3234
"cfg_if/detect",

tests/config/issue-3779.toml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
unstable_features = true
2+
ignore = [
3+
"tests/**/issue-3779/ice.rs"
4+
]

tests/source/issue-3779/ice.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn bar() {
2+
1x;
3+
}

tests/source/issue-3779/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// rustfmt-config: issue-3779.toml
2+
3+
#[path = "ice.rs"]
4+
mod ice;
5+
6+
fn foo() {
7+
println!("abc") ;
8+
}

tests/target/issue-3779/ice.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn bar() {
2+
1x;
3+
}

tests/target/issue-3779/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// rustfmt-config: issue-3779.toml
2+
3+
#[path = "ice.rs"]
4+
mod ice;
5+
6+
fn foo() {
7+
println!("abc");
8+
}

0 commit comments

Comments
 (0)