diff options
| author | Mark Rousskov <mark.simulacrum@gmail.com> | 2019-11-14 17:24:44 -0500 |
|---|---|---|
| committer | Mark Rousskov <mark.simulacrum@gmail.com> | 2019-11-15 08:45:49 -0500 |
| commit | c31a8754e3f3a9274759cb429aad4ae594d39e29 (patch) | |
| tree | 4c50d1f64384325c9f7d7635602149dddb86d7aa /src/libsyntax | |
| parent | 3f93ffc3334b77cc9025f68dfcea92098987abf3 (diff) | |
| download | rust-c31a8754e3f3a9274759cb429aad4ae594d39e29.tar.gz rust-c31a8754e3f3a9274759cb429aad4ae594d39e29.zip | |
Move JSON emitter to rustc_errors
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/json.rs | 434 | ||||
| -rw-r--r-- | src/libsyntax/json/tests.rs | 199 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 2 |
3 files changed, 0 insertions, 635 deletions
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs deleted file mode 100644 index 6096a930acf..00000000000 --- a/src/libsyntax/json.rs +++ /dev/null @@ -1,434 +0,0 @@ -//! A JSON emitter for errors. -//! -//! This works by converting errors to a simplified structural format (see the -//! structs at the start of the file) and then serializing them. These should -//! contain as much information about the error as possible. -//! -//! The format of the JSON output should be considered *unstable*. For now the -//! structs at the end of this file (Diagnostic*) specify the error format. - -// FIXME: spec the JSON output properly. - -use crate::source_map::{SourceMap, FilePathMapping}; - -use errors::registry::Registry; -use errors::{SubDiagnostic, CodeSuggestion}; -use errors::{DiagnosticId, Applicability}; -use errors::emitter::{Emitter, HumanReadableErrorType}; - -use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan}; -use rustc_data_structures::sync::{self, Lrc}; -use std::io::{self, Write}; -use std::path::Path; -use std::vec; -use std::sync::{Arc, Mutex}; - -use rustc_serialize::json::{as_json, as_pretty_json}; - -#[cfg(test)] -mod tests; - -pub struct JsonEmitter { - dst: Box<dyn Write + Send>, - registry: Option<Registry>, - sm: Lrc<SourceMap>, - pretty: bool, - ui_testing: bool, - json_rendered: HumanReadableErrorType, - external_macro_backtrace: bool, -} - -impl JsonEmitter { - pub fn stderr( - registry: Option<Registry>, - source_map: Lrc<SourceMap>, - pretty: bool, - json_rendered: HumanReadableErrorType, - external_macro_backtrace: bool, - ) -> JsonEmitter { - JsonEmitter { - dst: Box::new(io::stderr()), - registry, - sm: source_map, - pretty, - ui_testing: false, - json_rendered, - external_macro_backtrace, - } - } - - pub fn basic( - pretty: bool, - json_rendered: HumanReadableErrorType, - external_macro_backtrace: bool, - ) -> JsonEmitter { - let file_path_mapping = FilePathMapping::empty(); - JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)), - pretty, json_rendered, external_macro_backtrace) - } - - pub fn new( - dst: Box<dyn Write + Send>, - registry: Option<Registry>, - source_map: Lrc<SourceMap>, - pretty: bool, - json_rendered: HumanReadableErrorType, - external_macro_backtrace: bool, - ) -> JsonEmitter { - JsonEmitter { - dst, - registry, - sm: source_map, - pretty, - ui_testing: false, - json_rendered, - external_macro_backtrace, - } - } - - pub fn ui_testing(self, ui_testing: bool) -> Self { - Self { ui_testing, ..self } - } -} - -impl Emitter for JsonEmitter { - fn emit_diagnostic(&mut self, diag: &errors::Diagnostic) { - let data = Diagnostic::from_errors_diagnostic(diag, self); - let result = if self.pretty { - writeln!(&mut self.dst, "{}", as_pretty_json(&data)) - } else { - writeln!(&mut self.dst, "{}", as_json(&data)) - }; - if let Err(e) = result { - panic!("failed to print diagnostics: {:?}", e); - } - } - - fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { - let data = ArtifactNotification { artifact: path, emit: artifact_type }; - let result = if self.pretty { - writeln!(&mut self.dst, "{}", as_pretty_json(&data)) - } else { - writeln!(&mut self.dst, "{}", as_json(&data)) - }; - if let Err(e) = result { - panic!("failed to print notification: {:?}", e); - } - } - - fn source_map(&self) -> Option<&Lrc<SourceMap>> { - Some(&self.sm) - } - - fn should_show_explain(&self) -> bool { - match self.json_rendered { - HumanReadableErrorType::Short(_) => false, - _ => true, - } - } -} - -// The following data types are provided just for serialisation. - -#[derive(RustcEncodable)] -struct Diagnostic { - /// The primary error message. - message: String, - code: Option<DiagnosticCode>, - /// "error: internal compiler error", "error", "warning", "note", "help". - level: &'static str, - spans: Vec<DiagnosticSpan>, - /// Associated diagnostic messages. - children: Vec<Diagnostic>, - /// The message as rustc would render it. - rendered: Option<String>, -} - -#[derive(RustcEncodable)] -struct DiagnosticSpan { - file_name: String, - byte_start: u32, - byte_end: u32, - /// 1-based. - line_start: usize, - line_end: usize, - /// 1-based, character offset. - column_start: usize, - column_end: usize, - /// Is this a "primary" span -- meaning the point, or one of the points, - /// where the error occurred? - is_primary: bool, - /// Source text from the start of line_start to the end of line_end. - text: Vec<DiagnosticSpanLine>, - /// Label that should be placed at this location (if any) - label: Option<String>, - /// If we are suggesting a replacement, this will contain text - /// that should be sliced in atop this span. - suggested_replacement: Option<String>, - /// If the suggestion is approximate - suggestion_applicability: Option<Applicability>, - /// Macro invocations that created the code at this span, if any. - expansion: Option<Box<DiagnosticSpanMacroExpansion>>, -} - -#[derive(RustcEncodable)] -struct DiagnosticSpanLine { - text: String, - - /// 1-based, character offset in self.text. - highlight_start: usize, - - highlight_end: usize, -} - -#[derive(RustcEncodable)] -struct DiagnosticSpanMacroExpansion { - /// span where macro was applied to generate this code; note that - /// this may itself derive from a macro (if - /// `span.expansion.is_some()`) - span: DiagnosticSpan, - - /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") - macro_decl_name: String, - - /// span where macro was defined (if known) - def_site_span: DiagnosticSpan, -} - -#[derive(RustcEncodable)] -struct DiagnosticCode { - /// The code itself. - code: String, - /// An explanation for the code. - explanation: Option<&'static str>, -} - -#[derive(RustcEncodable)] -struct ArtifactNotification<'a> { - /// The path of the artifact. - artifact: &'a Path, - /// What kind of artifact we're emitting. - emit: &'a str, -} - -impl Diagnostic { - fn from_errors_diagnostic(diag: &errors::Diagnostic, - je: &JsonEmitter) - -> Diagnostic { - let sugg = diag.suggestions.iter().map(|sugg| { - Diagnostic { - message: sugg.msg.clone(), - code: None, - level: "help", - spans: DiagnosticSpan::from_suggestion(sugg, je), - children: vec![], - rendered: None, - } - }); - - // generate regular command line output and store it in the json - - // A threadsafe buffer for writing. - #[derive(Default, Clone)] - struct BufWriter(Arc<Mutex<Vec<u8>>>); - - impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.0.lock().unwrap().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.0.lock().unwrap().flush() - } - } - let buf = BufWriter::default(); - let output = buf.clone(); - je.json_rendered.new_emitter( - Box::new(buf), Some(je.sm.clone()), false, None, je.external_macro_backtrace - ).ui_testing(je.ui_testing).emit_diagnostic(diag); - let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); - let output = String::from_utf8(output).unwrap(); - - Diagnostic { - message: diag.message(), - code: DiagnosticCode::map_opt_string(diag.code.clone(), je), - level: diag.level.to_str(), - spans: DiagnosticSpan::from_multispan(&diag.span, je), - children: diag.children.iter().map(|c| { - Diagnostic::from_sub_diagnostic(c, je) - }).chain(sugg).collect(), - rendered: Some(output), - } - } - - fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic { - Diagnostic { - message: diag.message(), - code: None, - level: diag.level.to_str(), - spans: diag.render_span.as_ref() - .map(|sp| DiagnosticSpan::from_multispan(sp, je)) - .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)), - children: vec![], - rendered: None, - } - } -} - -impl DiagnosticSpan { - fn from_span_label(span: SpanLabel, - suggestion: Option<(&String, Applicability)>, - je: &JsonEmitter) - -> DiagnosticSpan { - Self::from_span_etc(span.span, - span.is_primary, - span.label, - suggestion, - je) - } - - fn from_span_etc(span: Span, - is_primary: bool, - label: Option<String>, - suggestion: Option<(&String, Applicability)>, - je: &JsonEmitter) - -> DiagnosticSpan { - // obtain the full backtrace from the `macro_backtrace` - // helper; in some ways, it'd be better to expand the - // backtrace ourselves, but the `macro_backtrace` helper makes - // some decision, such as dropping some frames, and I don't - // want to duplicate that logic here. - let backtrace = span.macro_backtrace().into_iter(); - DiagnosticSpan::from_span_full(span, - is_primary, - label, - suggestion, - backtrace, - je) - } - - fn from_span_full(span: Span, - is_primary: bool, - label: Option<String>, - suggestion: Option<(&String, Applicability)>, - mut backtrace: vec::IntoIter<MacroBacktrace>, - je: &JsonEmitter) - -> DiagnosticSpan { - let start = je.sm.lookup_char_pos(span.lo()); - let end = je.sm.lookup_char_pos(span.hi()); - let backtrace_step = backtrace.next().map(|bt| { - let call_site = - Self::from_span_full(bt.call_site, - false, - None, - None, - backtrace, - je); - let def_site_span = - Self::from_span_full(bt.def_site_span, - false, - None, - None, - vec![].into_iter(), - je); - Box::new(DiagnosticSpanMacroExpansion { - span: call_site, - macro_decl_name: bt.macro_decl_name, - def_site_span, - }) - }); - - DiagnosticSpan { - file_name: start.file.name.to_string(), - byte_start: start.file.original_relative_byte_pos(span.lo()).0, - byte_end: start.file.original_relative_byte_pos(span.hi()).0, - line_start: start.line, - line_end: end.line, - column_start: start.col.0 + 1, - column_end: end.col.0 + 1, - is_primary, - text: DiagnosticSpanLine::from_span(span, je), - suggested_replacement: suggestion.map(|x| x.0.clone()), - suggestion_applicability: suggestion.map(|x| x.1), - expansion: backtrace_step, - label, - } - } - - fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> { - msp.span_labels() - .into_iter() - .map(|span_str| Self::from_span_label(span_str, None, je)) - .collect() - } - - fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) - -> Vec<DiagnosticSpan> { - suggestion.substitutions - .iter() - .flat_map(|substitution| { - substitution.parts.iter().map(move |suggestion_inner| { - let span_label = SpanLabel { - span: suggestion_inner.span, - is_primary: true, - label: None, - }; - DiagnosticSpan::from_span_label(span_label, - Some((&suggestion_inner.snippet, - suggestion.applicability)), - je) - }) - }) - .collect() - } -} - -impl DiagnosticSpanLine { - fn line_from_source_file(fm: &syntax_pos::SourceFile, - index: usize, - h_start: usize, - h_end: usize) - -> DiagnosticSpanLine { - DiagnosticSpanLine { - text: fm.get_line(index).map_or(String::new(), |l| l.into_owned()), - highlight_start: h_start, - highlight_end: h_end, - } - } - - /// Creates a list of DiagnosticSpanLines from span - each line with any part - /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the - /// `span` within the line. - fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> { - je.sm.span_to_lines(span) - .map(|lines| { - let fm = &*lines.file; - lines.lines - .iter() - .map(|line| DiagnosticSpanLine::line_from_source_file( - fm, - line.line_index, - line.start_col.0 + 1, - line.end_col.0 + 1, - )).collect() - }).unwrap_or_else(|_| vec![]) - } -} - -impl DiagnosticCode { - fn map_opt_string(s: Option<DiagnosticId>, je: &JsonEmitter) -> Option<DiagnosticCode> { - s.map(|s| { - let s = match s { - DiagnosticId::Error(s) => s, - DiagnosticId::Lint(s) => s, - }; - let explanation = je.registry - .as_ref() - .and_then(|registry| registry.find_description(&s)); - - DiagnosticCode { - code: s, - explanation, - } - }) - } -} diff --git a/src/libsyntax/json/tests.rs b/src/libsyntax/json/tests.rs deleted file mode 100644 index 1edefd5bc4b..00000000000 --- a/src/libsyntax/json/tests.rs +++ /dev/null @@ -1,199 +0,0 @@ -use super::*; - -use crate::json::JsonEmitter; -use crate::source_map::{FilePathMapping, SourceMap}; -use crate::with_default_globals; - -use errors::emitter::{ColorConfig, HumanReadableErrorType}; -use errors::Handler; -use rustc_serialize::json::decode; -use syntax_pos::{BytePos, Span}; - -use std::str; - -#[derive(RustcDecodable, Debug, PartialEq, Eq)] -struct TestData { - spans: Vec<SpanTestData>, -} - -#[derive(RustcDecodable, Debug, PartialEq, Eq)] -struct SpanTestData { - pub byte_start: u32, - pub byte_end: u32, - pub line_start: u32, - pub column_start: u32, - pub line_end: u32, - pub column_end: u32, -} - -struct Shared<T> { - data: Arc<Mutex<T>>, -} - -impl<T: Write> Write for Shared<T> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.data.lock().unwrap().write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.data.lock().unwrap().flush() - } -} - -/// Test the span yields correct positions in JSON. -fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { - let expected_output = TestData { spans: vec![expected_output] }; - - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); - - let output = Arc::new(Mutex::new(Vec::new())); - let je = JsonEmitter::new( - Box::new(Shared { data: output.clone() }), - None, - sm, - true, - HumanReadableErrorType::Short(ColorConfig::Never), - false, - ); - - let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1)); - let handler = Handler::with_emitter(true, None, Box::new(je)); - handler.span_err(span, "foo"); - - let bytes = output.lock().unwrap(); - let actual_output = str::from_utf8(&bytes).unwrap(); - let actual_output: TestData = decode(actual_output).unwrap(); - - assert_eq!(expected_output, actual_output) - }) -} - -#[test] -fn empty() { - test_positions( - " ", - (0, 1), - SpanTestData { - byte_start: 0, - byte_end: 1, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }, - ) -} - -#[test] -fn bom() { - test_positions( - "\u{feff} ", - (0, 1), - SpanTestData { - byte_start: 3, - byte_end: 4, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }, - ) -} - -#[test] -fn lf_newlines() { - test_positions( - "\nmod foo;\nmod bar;\n", - (5, 12), - SpanTestData { - byte_start: 5, - byte_end: 12, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) -} - -#[test] -fn crlf_newlines() { - test_positions( - "\r\nmod foo;\r\nmod bar;\r\n", - (5, 12), - SpanTestData { - byte_start: 6, - byte_end: 14, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) -} - -#[test] -fn crlf_newlines_with_bom() { - test_positions( - "\u{feff}\r\nmod foo;\r\nmod bar;\r\n", - (5, 12), - SpanTestData { - byte_start: 9, - byte_end: 17, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }, - ) -} - -#[test] -fn span_before_crlf() { - test_positions( - "foo\r\nbar", - (2, 3), - SpanTestData { - byte_start: 2, - byte_end: 3, - line_start: 1, - column_start: 3, - line_end: 1, - column_end: 4, - }, - ) -} - -#[test] -fn span_on_crlf() { - test_positions( - "foo\r\nbar", - (3, 4), - SpanTestData { - byte_start: 3, - byte_end: 5, - line_start: 1, - column_start: 4, - line_end: 2, - column_end: 1, - }, - ) -} - -#[test] -fn span_after_crlf() { - test_positions( - "foo\r\nbar", - (4, 5), - SpanTestData { - byte_start: 5, - byte_end: 6, - line_start: 2, - column_start: 1, - line_end: 2, - column_end: 2, - }, - ) -} diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index a1de0a2c9e4..e3eca75dfe7 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -87,8 +87,6 @@ pub mod util { pub mod map_in_place; } -pub mod json; - pub mod ast; pub mod attr; pub mod expand; |
