Skip to content

Commit

Permalink
fix(handlers): source code propagation for JSON handler (#122)
Browse files Browse the repository at this point in the history
A part of fix of #99, follow up of #117
  • Loading branch information
tailhook authored Feb 23, 2022
1 parent 3252010 commit 50bcec9
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 11 deletions.
31 changes: 20 additions & 11 deletions src/handlers/json.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::{self, Write};

use crate::{protocol::Diagnostic, ReportHandler, Severity};
use crate::{protocol::Diagnostic, ReportHandler, Severity, SourceCode};

/**
[ReportHandler] that renders json output.
Expand Down Expand Up @@ -62,6 +62,15 @@ impl JSONReportHandler {
&self,
f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic),
) -> fmt::Result {
self._render_report(f, diagnostic, None)
}

fn _render_report(
&self,
f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic),
parent_src: Option<&dyn SourceCode>,
) -> fmt::Result {
write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?;
if let Some(code) = diagnostic.code() {
Expand All @@ -79,8 +88,9 @@ impl JSONReportHandler {
if let Some(help) = diagnostic.help() {
write!(f, r#""help": "{}","#, escape(&help.to_string()))?;
}
if diagnostic.source_code().is_some() {
self.render_snippets(f, diagnostic)?;
let src = diagnostic.source_code().or(parent_src);
if let Some(src) = src {
self.render_snippets(f, diagnostic, src)?;
}
if let Some(labels) = diagnostic.labels() {
write!(f, r#""labels": ["#)?;
Expand Down Expand Up @@ -114,7 +124,7 @@ impl JSONReportHandler {
} else {
add_comma = true;
}
self.render_report(f, related)?;
self._render_report(f, related, src)?;
}
write!(f, "]")?;
} else {
Expand All @@ -127,14 +137,13 @@ impl JSONReportHandler {
&self,
f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic),
source: &dyn SourceCode,
) -> fmt::Result {
if let Some(source) = diagnostic.source_code() {
if let Some(mut labels) = diagnostic.labels() {
if let Some(label) = labels.next() {
if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
let filename = span_content.name().unwrap_or_default();
return write!(f, r#""filename": "{}","#, escape(filename));
}
if let Some(mut labels) = diagnostic.labels() {
if let Some(label) = labels.next() {
if let Ok(span_content) = source.read_span(label.inner(), 0, 0) {
let filename = span_content.name().unwrap_or_default();
return write!(f, r#""filename": "{}","#, escape(filename));
}
}
}
Expand Down
95 changes: 95 additions & 0 deletions tests/test_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,4 +809,99 @@ mod json_report_handler {
assert_eq!(expected, out);
Ok(())
}

#[test]
fn related_source_code_propagation() -> Result<(), MietteError> {
#[derive(Debug, Diagnostic, Error)]
#[error("oops!")]
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
struct MyBad {
#[source_code]
src: NamedSource,
#[label("this bit here")]
highlight: SourceSpan,
#[related]
related: Vec<InnerError>,
}

#[derive(Debug, Diagnostic, Error)]
#[error("oops!")]
#[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
struct InnerError {
#[label("this bit here")]
highlight: SourceSpan,
}

let src = "source\n text\n here".to_string();
let err = MyBad {
src: NamedSource::new("bad_file.rs", src.clone()),
highlight: (9, 4).into(),
related: vec![
InnerError {
highlight: (0, 6).into(),
},
InnerError {
highlight: (0, 6).into(),
},
],
};
let out = fmt_report(err.into());
println!("Error: {}", out);
let expected: String = r#"
{
"message": "oops!",
"code": "oops::my::bad",
"severity": "error",
"help": "try doing it better next time?",
"filename": "bad_file.rs",
"labels": [
{
"label": "this bit here",
"span": {
"offset": 9,
"length": 4
}
}
],
"related": [{
"message": "oops!",
"code": "oops::my::bad",
"severity": "error",
"help": "try doing it better next time?",
"filename": "bad_file.rs",
"labels": [
{
"label": "this bit here",
"span": {
"offset": 0,
"length": 6
}
}
],
"related": []
},{
"message": "oops!",
"code": "oops::my::bad",
"severity": "error",
"help": "try doing it better next time?",
"filename": "bad_file.rs",
"labels": [
{
"label": "this bit here",
"span": {
"offset": 0,
"length": 6
}
}
],
"related": []
}]
}"#
.lines()
.into_iter()
.map(|s| s.trim_matches(|c| c == ' ' || c == '\n'))
.collect();
assert_eq!(expected, out);
Ok(())
}
}

0 comments on commit 50bcec9

Please sign in to comment.