Skip to content

Commit d28b7e7

Browse files
committed
return non-zero exit code if there are errors
1 parent 09440b5 commit d28b7e7

File tree

3 files changed

+78
-13
lines changed

3 files changed

+78
-13
lines changed

src/bin/rustfmt.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extern crate toml;
1717
extern crate env_logger;
1818
extern crate getopts;
1919

20-
use rustfmt::{run, Input};
20+
use rustfmt::{run, Input, ErrorSummary};
2121
use rustfmt::config::{Config, WriteMode};
2222

2323
use std::env;
@@ -189,8 +189,11 @@ fn execute() -> i32 {
189189
// write_mode is always Plain for Stdin.
190190
config.write_mode = WriteMode::Plain;
191191

192-
run(Input::Text(input), &config);
193-
0
192+
if run(Input::Text(input), &config).has_errors() {
193+
1
194+
} else {
195+
0
196+
}
194197
}
195198
Operation::Format { files, config_path } => {
196199
let mut config = Config::default();
@@ -206,6 +209,8 @@ fn execute() -> i32 {
206209
if let Some(path) = path.as_ref() {
207210
println!("Using rustfmt config file {}", path.display());
208211
}
212+
213+
let mut error_summary = ErrorSummary::new();
209214
for file in files {
210215
// Check the file directory if the config-path could not be read or not provided
211216
if path.is_none() {
@@ -225,9 +230,14 @@ fn execute() -> i32 {
225230
print_usage(&opts, &e);
226231
return 1;
227232
}
228-
run(Input::File(file), &config);
233+
error_summary.add(run(Input::File(file), &config));
234+
}
235+
236+
if error_summary.has_errors() {
237+
1
238+
} else {
239+
0
229240
}
230-
0
231241
}
232242
}
233243
}

src/lib.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,30 @@ impl Sub<usize> for Indent {
190190
}
191191
}
192192

193+
194+
#[must_use]
195+
pub struct ErrorSummary {
196+
has_errors: bool,
197+
}
198+
199+
impl ErrorSummary {
200+
pub fn new() -> ErrorSummary {
201+
ErrorSummary { has_errors: false }
202+
}
203+
204+
pub fn add_error(&mut self) {
205+
self.has_errors = true;
206+
}
207+
208+
pub fn has_errors(&self) -> bool {
209+
self.has_errors
210+
}
211+
212+
pub fn add(&mut self, other: ErrorSummary) {
213+
self.has_errors |= other.has_errors;
214+
}
215+
}
216+
193217
pub enum ErrorKind {
194218
// Line has exceeded character limit
195219
LineOverflow,
@@ -239,9 +263,17 @@ pub struct FormatReport {
239263
}
240264

241265
impl FormatReport {
266+
fn new() -> FormatReport {
267+
FormatReport { file_error_map: HashMap::new() }
268+
}
269+
242270
pub fn warning_count(&self) -> usize {
243271
self.file_error_map.iter().map(|(_, ref errors)| errors.len()).fold(0, |acc, x| acc + x)
244272
}
273+
274+
pub fn has_warnings(&self) -> bool {
275+
self.warning_count() > 0
276+
}
245277
}
246278

247279
impl fmt::Display for FormatReport {
@@ -289,7 +321,7 @@ fn format_ast(krate: &ast::Crate,
289321
// TODO(#20) other stuff for parity with make tidy
290322
fn format_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
291323
let mut truncate_todo = Vec::new();
292-
let mut report = FormatReport { file_error_map: HashMap::new() };
324+
let mut report = FormatReport::new();
293325

294326
// Iterate over the chars in the file map.
295327
for (f, text) in file_map.iter() {
@@ -378,7 +410,8 @@ fn parse_input(input: Input, parse_session: &ParseSess) -> Result<ast::Crate, Di
378410
krate
379411
}
380412

381-
pub fn format_input(input: Input, config: &Config) -> (FileMap, FormatReport) {
413+
pub fn format_input(input: Input, config: &Config) -> (ErrorSummary, FileMap, FormatReport) {
414+
let mut error_summary = ErrorSummary::new();
382415
let codemap = Rc::new(CodeMap::new());
383416

384417
let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
@@ -397,10 +430,15 @@ pub fn format_input(input: Input, config: &Config) -> (FileMap, FormatReport) {
397430
Ok(krate) => krate,
398431
Err(mut diagnostic) => {
399432
diagnostic.emit();
400-
panic!("Unrecoverable parse error");
433+
error_summary.add_error();
434+
return (error_summary, FileMap::new(), FormatReport::new());
401435
}
402436
};
403437

438+
if parse_session.span_diagnostic.has_errors() {
439+
error_summary.add_error();
440+
}
441+
404442
// Suppress error output after parsing.
405443
let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
406444
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
@@ -412,16 +450,19 @@ pub fn format_input(input: Input, config: &Config) -> (FileMap, FormatReport) {
412450
filemap::append_newlines(&mut file_map);
413451

414452
let report = format_lines(&mut file_map, config);
415-
(file_map, report)
453+
if report.has_warnings() {
454+
error_summary.add_error();
455+
}
456+
(error_summary, file_map, report)
416457
}
417458

418459
pub enum Input {
419460
File(PathBuf),
420461
Text(String),
421462
}
422463

423-
pub fn run(input: Input, config: &Config) {
424-
let (file_map, report) = format_input(input, config);
464+
pub fn run(input: Input, config: &Config) -> ErrorSummary {
465+
let (mut error_summary, file_map, report) = format_input(input, config);
425466

426467
let ignore_errors = config.write_mode == WriteMode::Plain;
427468
if !ignore_errors {
@@ -433,5 +474,8 @@ pub fn run(input: Input, config: &Config) {
433474

434475
if let Err(msg) = write_result {
435476
msg!("Error writing files: {}", msg);
477+
error_summary.add_error();
436478
}
479+
480+
error_summary
437481
}

tests/system.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,20 @@ fn self_tests() {
143143
fn stdin_formatting_smoke_test() {
144144
let input = Input::Text("fn main () {}".to_owned());
145145
let config = Config::default();
146-
let (file_map, _report) = format_input(input, &config);
146+
let (error_summary, file_map, _report) = format_input(input, &config);
147+
assert!(!error_summary.has_errors());
147148
assert_eq!(file_map["stdin"].to_string(), "fn main() {}\n")
148149
}
149150

151+
#[test]
152+
fn format_lines_errors_are_reported() {
153+
let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
154+
let input = Input::Text(format!("fn {}() {{}}", long_identifier));
155+
let config = Config::default();
156+
let (error_summary, _file_map, _report) = format_input(input, &config);
157+
assert!(error_summary.has_errors());
158+
}
159+
150160
// For each file, run rustfmt and collect the output.
151161
// Returns the number of files checked and the number of failures.
152162
fn check_files<I>(files: I) -> (Vec<FormatReport>, u32, u32)
@@ -202,7 +212,8 @@ fn read_config(filename: &str) -> Config {
202212

203213
fn format_file<P: Into<PathBuf>>(filename: P, config: &Config) -> (FileMap, FormatReport) {
204214
let input = Input::File(filename.into());
205-
format_input(input, &config)
215+
let (_error_summary, file_map, report) = format_input(input, &config);
216+
return (file_map, report);
206217
}
207218

208219
pub fn idempotent_check(filename: String) -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {

0 commit comments

Comments
 (0)