use codemap::{CodeMap, FilePathMapping};
use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
use errors::registry::Registry;
-use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
+use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, CodeMapper};
+use errors::DiagnosticId;
use errors::emitter::Emitter;
use std::rc::Rc;
use std::io::{self, Write};
use std::vec;
-use rustc_serialize::json::as_json;
+use rustc_serialize::json::{as_json, as_pretty_json};
pub struct JsonEmitter {
dst: Box<Write + Send>,
registry: Option<Registry>,
cm: Rc<CodeMapper + 'static>,
+ pretty: bool,
}
impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
- code_map: Rc<CodeMap>) -> JsonEmitter {
+ code_map: Rc<CodeMap>,
+ pretty: bool) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
cm: code_map,
+ pretty,
}
}
- pub fn basic() -> JsonEmitter {
+ pub fn basic(pretty: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
- JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)))
+ JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
}
pub fn new(dst: Box<Write + Send>,
registry: Option<Registry>,
- code_map: Rc<CodeMap>) -> JsonEmitter {
+ code_map: Rc<CodeMap>,
+ pretty: bool) -> JsonEmitter {
JsonEmitter {
dst,
registry,
cm: code_map,
+ pretty,
}
}
}
impl Emitter for JsonEmitter {
fn emit(&mut self, db: &DiagnosticBuilder) {
let data = Diagnostic::from_diagnostic_builder(db, self);
- if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
+ 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);
}
}
spans: Vec<DiagnosticSpan>,
/// Associated diagnostic messages.
children: Vec<Diagnostic>,
- /// The message as rustc would render it. Currently this is only
- /// `Some` for "suggestions", but eventually it will include all
- /// snippets.
+ /// The message as rustc would render it. Currently this is always `None`
rendered: Option<String>,
}
/// 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. You may prefer to
- /// load the fully rendered version from the parent `Diagnostic`,
- /// however.
+ /// that should be sliced in atop this span.
suggested_replacement: Option<String>,
/// Macro invocations that created the code at this span, if any.
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
fn from_diagnostic_builder(db: &DiagnosticBuilder,
je: &JsonEmitter)
-> Diagnostic {
- let sugg = db.suggestions.iter().flat_map(|sugg| {
- je.render(sugg).into_iter().map(move |rendered| {
- Diagnostic {
- message: sugg.msg.clone(),
- code: None,
- level: "help",
- spans: DiagnosticSpan::from_suggestion(sugg, je),
- children: vec![],
- rendered: Some(rendered),
- }
- })
+ let sugg = db.suggestions.iter().map(|sugg| {
+ Diagnostic {
+ message: sugg.msg.clone(),
+ code: None,
+ level: "help",
+ spans: DiagnosticSpan::from_suggestion(sugg, je),
+ children: vec![],
+ rendered: None,
+ }
});
Diagnostic {
message: db.message(),
code: None,
level: db.level.to_str(),
spans: db.render_span.as_ref()
- .map(|sp| DiagnosticSpan::from_render_span(sp, je))
+ .map(|sp| DiagnosticSpan::from_multispan(sp, je))
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
children: vec![],
rendered: None,
fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter)
-> Vec<DiagnosticSpan> {
- suggestion.substitution_parts
+ suggestion.substitutions
.iter()
.flat_map(|substitution| {
- substitution.substitutions.iter().map(move |suggestion| {
+ substitution.parts.iter().map(move |suggestion| {
let span_label = SpanLabel {
- span: substitution.span,
+ span: suggestion.span,
is_primary: true,
label: None,
};
DiagnosticSpan::from_span_label(span_label,
- Some(suggestion),
+ Some(&suggestion.snippet),
je)
})
})
.collect()
}
-
- fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
- match *rsp {
- RenderSpan::FullSpan(ref msp) =>
- DiagnosticSpan::from_multispan(msp, je),
- // regular diagnostics don't produce this anymore
- // FIXME(oli_obk): remove it entirely
- RenderSpan::Suggestion(_) => unreachable!(),
- }
- }
}
impl DiagnosticSpanLine {
}
impl DiagnosticCode {
- fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<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));
})
}
}
-
-impl JsonEmitter {
- fn render(&self, suggestion: &CodeSuggestion) -> Vec<String> {
- suggestion.splice_lines(&*self.cm).iter().map(|line| line.0.to_owned()).collect()
- }
-}