diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2018-02-28 16:17:44 +0100 |
|---|---|---|
| committer | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2018-03-14 00:52:17 +0100 |
| commit | 8c75e18e5d23ea88914a8e276037980e96866c76 (patch) | |
| tree | fcac2bc7c09146cebc73746ce915bb1319580ed8 | |
| parent | c29085761b0bf5b9add4bd008268651feae495bd (diff) | |
| download | rust-8c75e18e5d23ea88914a8e276037980e96866c76.tar.gz rust-8c75e18e5d23ea88914a8e276037980e96866c76.zip | |
test for putting back check on json
| -rw-r--r-- | src/librustc_errors/diagnostic_builder.rs | 3 | ||||
| -rw-r--r-- | src/librustc_errors/emitter.rs | 89 | ||||
| -rw-r--r-- | src/librustc_errors/lib.rs | 51 | ||||
| -rw-r--r-- | src/tools/compiletest/src/json.rs | 20 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest.rs | 43 |
5 files changed, 127 insertions, 79 deletions
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 2536fc648c7..945ecce7ab3 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -92,7 +92,8 @@ impl<'a> DiagnosticBuilder<'a> { Level::Bug | Level::Fatal | Level::PhaseFatal | - Level::Error => { + Level::Error | + Level::FailureNote => { true } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index f481b36daa3..3b6e6db7f46 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -21,7 +21,7 @@ use atty; use std::borrow::Cow; use std::io::prelude::*; use std::io; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::cmp::min; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter}; use termcolor::{WriteColor, Color, Buffer}; @@ -33,6 +33,11 @@ const ANONYMIZED_LINE_NUM: &str = "LL"; pub trait Emitter { /// Emit a structured diagnostic. fn emit(&mut self, db: &DiagnosticBuilder); + + /// Check if should show explanations about "rustc --explain" + fn should_show_explain(&self) -> bool { + true + } } impl Emitter for EmitterWriter { @@ -80,6 +85,10 @@ impl Emitter for EmitterWriter { &children, &suggestions); } + + fn should_show_explain(&self) -> bool { + !self.short_message + } } /// maximum number of lines we will print for each error; arbitrary. @@ -114,7 +123,6 @@ pub struct EmitterWriter { cm: Option<Lrc<CodeMapper>>, short_message: bool, teach: bool, - error_codes: HashSet<String>, ui_testing: bool, } @@ -124,34 +132,6 @@ struct FileWithAnnotatedLines { multiline_depth: usize, } -impl Drop for EmitterWriter { - fn drop(&mut self) { - if !self.short_message && !self.error_codes.is_empty() { - let mut error_codes = self.error_codes.clone().into_iter().collect::<Vec<_>>(); - let mut dst = self.dst.writable(); - error_codes.sort(); - if error_codes.len() > 1 { - let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - writeln!(dst, - "You've got a few errors: {}{}", - error_codes[..limit].join(", "), - if error_codes.len() > 9 { "..." } else { "" } - ).expect("failed to give tips..."); - writeln!(dst, - "If you want more information on an error, try using \ - \"rustc --explain {}\"", - &error_codes[0]).expect("failed to give tips..."); - } else { - writeln!(dst, - "If you want more information on this error, try using \ - \"rustc --explain {}\"", - &error_codes[0]).expect("failed to give tips..."); - } - dst.flush().expect("failed to emit errors"); - } - } -} - impl EmitterWriter { pub fn stderr(color_config: ColorConfig, code_map: Option<Lrc<CodeMapper>>, @@ -164,7 +144,6 @@ impl EmitterWriter { cm: code_map, short_message, teach, - error_codes: HashSet::new(), ui_testing: false, } } @@ -179,7 +158,6 @@ impl EmitterWriter { cm: code_map, short_message, teach, - error_codes: HashSet::new(), ui_testing: false, } } @@ -993,18 +971,26 @@ impl EmitterWriter { buffer.prepend(0, " ", Style::NoStyle); } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); - buffer.append(0, &level.to_string(), Style::HeaderMsg); - buffer.append(0, ": ", Style::NoStyle); + let level_str = level.to_string(); + if !level_str.is_empty() { + buffer.append(0, &level_str, Style::HeaderMsg); + buffer.append(0, ": ", Style::NoStyle); + } self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { - buffer.append(0, &level.to_string(), Style::Level(level.clone())); + let level_str = level.to_string(); + if !level_str.is_empty() { + buffer.append(0, &level_str, Style::Level(level.clone())); + } // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { buffer.append(0, "[", Style::Level(level.clone())); buffer.append(0, &code, Style::Level(level.clone())); buffer.append(0, "]", Style::Level(level.clone())); } - buffer.append(0, ": ", Style::HeaderMsg); + if !level_str.is_empty() { + buffer.append(0, ": ", Style::HeaderMsg); + } for &(ref text, _) in msg.iter() { buffer.append(0, text, Style::HeaderMsg); } @@ -1020,14 +1006,12 @@ impl EmitterWriter { if primary_span != &&DUMMY_SP { (cm.lookup_char_pos(primary_span.lo()), cm) } else { - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message, - &mut self.error_codes)?; + emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; return Ok(()); } } else { // If we don't have span information, emit and exit - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message, - &mut self.error_codes)?; + emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; return Ok(()); }; if let Ok(pos) = @@ -1200,8 +1184,7 @@ impl EmitterWriter { } // final step: take our styled buffer, render it, then output it - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message, - &mut self.error_codes)?; + emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) @@ -1218,8 +1201,11 @@ impl EmitterWriter { let mut buffer = StyledBuffer::new(); // Render the suggestion message - buffer.append(0, &level.to_string(), Style::Level(level.clone())); - buffer.append(0, ": ", Style::HeaderMsg); + let level_str = level.to_string(); + if !level_str.is_empty() { + buffer.append(0, &level_str, Style::Level(level.clone())); + buffer.append(0, ": ", Style::HeaderMsg); + } self.msg_to_buffer(&mut buffer, &[(suggestion.msg.to_owned(), Style::NoStyle)], max_line_num_len, @@ -1289,8 +1275,7 @@ impl EmitterWriter { let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS); buffer.puts(row_num, 0, &msg, Style::NoStyle); } - emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message, - &mut self.error_codes)?; + emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; } Ok(()) } @@ -1321,7 +1306,7 @@ impl EmitterWriter { draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1); } match emit_to_destination(&buffer.render(), level, &mut self.dst, - self.short_message, &mut self.error_codes) { + self.short_message) { Ok(()) => (), Err(e) => panic!("failed to emit error: {}", e) } @@ -1416,8 +1401,7 @@ fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>, lvl: &Level, dst: &mut Destination, - short_message: bool, - error_codes: &mut HashSet<String>) + short_message: bool) -> io::Result<()> { use lock; @@ -1436,16 +1420,13 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>, // same buffering approach. Instead, we use a global Windows mutex, which we acquire long // enough to output the full error message, then we release. let _buffer_lock = lock::acquire_global_lock("rustc_errors"); - for line in rendered_buffer { + for (pos, line) in rendered_buffer.iter().enumerate() { for part in line { dst.apply_style(lvl.clone(), part.style)?; write!(dst, "{}", part.text)?; - if !short_message && part.text.len() == 12 && part.text.starts_with("error[E") { - error_codes.insert(part.text[6..11].to_owned()); - } dst.reset()?; } - if !short_message { + if !short_message && (!lvl.is_failure_note() || pos != rendered_buffer.len() - 1) { write!(dst, "\n")?; } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 924ed71ef0d..7148969191f 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -509,12 +509,14 @@ impl Handler { pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); } + pub fn failure(&self, msg: &str) { + DiagnosticBuilder::new(self, FailureNote, msg).emit() + } pub fn fatal(&self, msg: &str) -> FatalError { if self.flags.treat_err_as_bug { self.bug(msg); } - let mut db = DiagnosticBuilder::new(self, Fatal, msg); - db.emit(); + DiagnosticBuilder::new(self, Fatal, msg).emit(); FatalError } pub fn err(&self, msg: &str) { @@ -567,8 +569,39 @@ impl Handler { s = format!("aborting due to {} previous errors", self.err_count()); } } + let err = self.fatal(&s); + + let can_show_explain = self.emitter.borrow().should_show_explain(); + let are_there_diagnostics = !self.tracked_diagnostic_codes.borrow().is_empty(); + if can_show_explain && are_there_diagnostics { + let mut error_codes = + self.tracked_diagnostic_codes.borrow() + .clone() + .into_iter() + .filter_map(|x| match x { + DiagnosticId::Error(ref s) => Some(s.clone()), + _ => None, + }) + .collect::<Vec<_>>(); + if !error_codes.is_empty() { + error_codes.sort(); + if error_codes.len() > 1 { + let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; + self.failure(&format!("Some errors occurred: {}{}", + error_codes[..limit].join(", "), + if error_codes.len() > 9 { "..." } else { "." })); + self.failure(&format!("For more information about an error, try \ + `rustc --explain {}`.", + &error_codes[0])); + } else { + self.failure(&format!("For more information about this error, try \ + `rustc --explain {}`.", + &error_codes[0])); + } + } + } - self.fatal(&s).raise(); + err.raise(); } pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.flags.can_emit_warnings { @@ -654,6 +687,7 @@ pub enum Level { Note, Help, Cancelled, + FailureNote, } impl fmt::Display for Level { @@ -682,9 +716,10 @@ impl Level { spec.set_fg(Some(Color::Cyan)) .set_intense(true); } + FailureNote => {} Cancelled => unreachable!(), } - return spec + spec } pub fn to_str(self) -> &'static str { @@ -694,7 +729,15 @@ impl Level { Warning => "warning", Note => "note", Help => "help", + FailureNote => "", Cancelled => panic!("Shouldn't call on cancelled error"), } } + + pub fn is_failure_note(&self) -> bool { + match *self { + FailureNote => true, + _ => false, + } + } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 08630628b71..761d1e511d5 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -24,6 +24,7 @@ struct Diagnostic { level: String, spans: Vec<DiagnosticSpan>, children: Vec<Diagnostic>, + rendered: Option<String>, } #[derive(Deserialize, Clone)] @@ -56,6 +57,25 @@ struct DiagnosticCode { explanation: Option<String>, } +pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String { + output.lines() + .filter_map(|line| if line.starts_with('{') { + match serde_json::from_str::<Diagnostic>(line) { + Ok(diagnostic) => diagnostic.rendered, + Err(error) => { + proc_res.fatal(Some(&format!("failed to decode compiler output as json: \ + `{}`\noutput: {}\nline: {}", + error, + line, + output))); + } + } + } else { + None + }) + .collect() +} + pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> { output.lines() .flat_map(|line| parse_line(file_name, line, output, proc_res)) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 6619838cce0..953a13a3f58 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -248,7 +248,7 @@ impl<'test> TestCx<'test> { } fn run_cfail_test(&self) { - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); self.check_no_compiler_crash(&proc_res); @@ -267,7 +267,7 @@ impl<'test> TestCx<'test> { } fn run_rfail_test(&self) { - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); @@ -309,7 +309,7 @@ impl<'test> TestCx<'test> { } fn run_rpass_test(&self) { - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); @@ -336,7 +336,7 @@ impl<'test> TestCx<'test> { return self.run_rpass_test(); } - let mut proc_res = self.compile_test(&[]); + let mut proc_res = self.compile_test(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); @@ -578,7 +578,7 @@ impl<'test> TestCx<'test> { let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) - let compiler_run_result = self.compile_test(&[]); + let compiler_run_result = self.compile_test(); if !compiler_run_result.status.success() { self.fatal_proc_rec("compilation failed!", &compiler_run_result); } @@ -835,7 +835,7 @@ impl<'test> TestCx<'test> { fn run_debuginfo_lldb_test_no_opt(&self) { // compile test file (it should have 'compile-flags:-g' in the header) - let compile_result = self.compile_test(&[]); + let compile_result = self.compile_test(); if !compile_result.status.success() { self.fatal_proc_rec("compilation failed!", &compile_result); } @@ -1272,15 +1272,12 @@ impl<'test> TestCx<'test> { } } - fn compile_test(&self, extra_args: &[&'static str]) -> ProcRes { + fn compile_test(&self) -> ProcRes { let mut rustc = self.make_compile_args( &self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name()), ); - if !extra_args.is_empty() { - rustc.args(extra_args); - } rustc.arg("-L").arg(&self.aux_output_dir_name()); match self.config.mode { @@ -1626,12 +1623,14 @@ impl<'test> TestCx<'test> { if self.props.error_patterns.is_empty() { rustc.args(&["--error-format", "json"]); } + if !self.props.disable_ui_testing_normalization { + rustc.arg("-Zui-testing"); + } } Ui => { - // In case no "--error-format" has been given in the test, we'll compile - // a first time to get the compiler's output then compile with - // "--error-format json" to check if all expected errors are actually there - // and that no new one appeared. + if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) { + rustc.args(&["--error-format", "json"]); + } if !self.props.disable_ui_testing_normalization { rustc.arg("-Zui-testing"); } @@ -2114,7 +2113,7 @@ impl<'test> TestCx<'test> { fn run_codegen_units_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); @@ -2505,7 +2504,7 @@ impl<'test> TestCx<'test> { .iter() .any(|s| s.contains("--error-format")); - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); let expected_stderr_path = self.expected_output_path(UI_STDERR); @@ -2517,8 +2516,13 @@ impl<'test> TestCx<'test> { let normalized_stdout = self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout); - let normalized_stderr = self.normalize_output(&proc_res.stderr, - &self.props.normalize_stderr); + let stderr = if explicit { + proc_res.stderr.clone() + } else { + json::extract_rendered(&proc_res.stderr, &proc_res) + }; + + let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr); let mut errors = 0; errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout); @@ -2551,7 +2555,6 @@ impl<'test> TestCx<'test> { } } if !explicit { - let proc_res = self.compile_test(&["--error-format", "json"]); if !expected_errors.is_empty() || !proc_res.status.success() { // "// error-pattern" comments self.check_expected_errors(expected_errors, &proc_res); @@ -2563,7 +2566,7 @@ impl<'test> TestCx<'test> { } fn run_mir_opt_test(&self) { - let proc_res = self.compile_test(&[]); + let proc_res = self.compile_test(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); |
