Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add $message_type field to distinguish json diagnostic outputs #115691

Merged
merged 8 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 35 additions & 30 deletions compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,25 @@ impl JsonEmitter {
pub fn ignored_directories_in_source_blocks(self, value: Vec<String>) -> Self {
Self { ignored_directories_in_source_blocks: value, ..self }
}

fn emit(&mut self, val: EmitTyped<'_>) -> io::Result<()> {
if self.pretty {
serde_json::to_writer_pretty(&mut *self.dst, &val)?
} else {
serde_json::to_writer(&mut *self.dst, &val)?
};
self.dst.write_all(b"\n")?;
self.dst.flush()
}
}

#[derive(Serialize)]
#[serde(tag = "$message_type", rename_all = "snake_case")]
enum EmitTyped<'a> {
Diagnostic(Diagnostic),
Artifact(ArtifactNotification<'a>),
FutureIncompat(FutureIncompatReport<'a>),
jsgf marked this conversation as resolved.
Show resolved Hide resolved
UnusedExtern(UnusedExterns<'a, 'a, 'a>),
}

impl Translate for JsonEmitter {
Expand All @@ -160,47 +179,36 @@ impl Translate for JsonEmitter {
impl Emitter for JsonEmitter {
fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
let data = Diagnostic::from_errors_diagnostic(diag, self);
let result = if self.pretty {
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
let result = self.emit(EmitTyped::Diagnostic(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, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
let result = self.emit(EmitTyped::Artifact(data));
if let Err(e) = result {
panic!("failed to print notification: {e:?}");
}
}

fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
let data: Vec<FutureBreakageItem> = diags
let data: Vec<FutureBreakageItem<'_>> = diags
.into_iter()
.map(|mut diag| {
if diag.level == crate::Level::Allow {
diag.level = crate::Level::Warning(None);
}
FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) }
FutureBreakageItem {
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
&diag, self,
)),
}
})
.collect();
let report = FutureIncompatReport { future_incompat_report: data };
let result = if self.pretty {
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&report).unwrap())
} else {
writeln!(&mut self.dst, "{}", serde_json::to_string(&report).unwrap())
}
.and_then(|_| self.dst.flush());
let result = self.emit(EmitTyped::FutureIncompat(report));
if let Err(e) = result {
panic!("failed to print future breakage report: {e:?}");
}
Expand All @@ -209,12 +217,7 @@ impl Emitter for JsonEmitter {
fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
let lint_level = lint_level.as_str();
let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
let result = if self.pretty {
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
let result = self.emit(EmitTyped::UnusedExtern(data));
if let Err(e) = result {
panic!("failed to print unused externs: {e:?}");
}
Expand Down Expand Up @@ -313,13 +316,15 @@ struct ArtifactNotification<'a> {
}

#[derive(Serialize)]
struct FutureBreakageItem {
diagnostic: Diagnostic,
struct FutureBreakageItem<'a> {
// Always EmitTyped::Diagnostic, but we want to make sure it gets serialized
// with "$message_type".
diagnostic: EmitTyped<'a>,
}

#[derive(Serialize)]
struct FutureIncompatReport {
future_incompat_report: Vec<FutureBreakageItem>,
struct FutureIncompatReport<'a> {
future_incompat_report: Vec<FutureBreakageItem<'a>>,
}

// NOTE: Keep this in sync with the equivalent structs in rustdoc's
Expand Down
14 changes: 11 additions & 3 deletions src/doc/rustc/src/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ If parsing the output with Rust, the
[`cargo_metadata`](https://crates.io/crates/cargo_metadata) crate provides
some support for parsing the messages.

When parsing, care should be taken to be forwards-compatible with future changes
to the format. Optional values may be `null`. New fields may be added. Enumerated
fields like "level" or "suggestion_applicability" may add new values.
Each type of message has a `$message_type` field which can be used to
distinguish the different formats. When parsing, care should be taken
to be forwards-compatible with future changes to the format. Optional
values may be `null`. New fields may be added. Enumerated fields like
"level" or "suggestion_applicability" may add new values.

## Diagnostics

Expand All @@ -29,6 +31,8 @@ Diagnostics have the following format:

```javascript
{
/* Type of this message */
"$message_type": "diagnostic",
/* The primary message. */
"message": "unused variable: `x`",
/* The diagnostic code.
Expand Down Expand Up @@ -217,6 +221,8 @@ flag][option-emit] documentation.

```javascript
{
/* Type of this message */
"$message_type": "artifact",
/* The filename that was generated. */
"artifact": "libfoo.rlib",
/* The kind of artifact that was generated. Possible values:
Expand All @@ -239,6 +245,8 @@ information, even if the diagnostics have been suppressed (such as with an

```javascript
{
/* Type of this message */
"$message_type": "future_incompat",
/* An array of objects describing a warning that will become a hard error
in the future.
*/
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/diagnostic-width/flag-json.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
{"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.

Erroneous code examples:

Expand Down Expand Up @@ -33,8 +33,8 @@ LL | ..._: () = 42;
| expected due to this

"}
{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
{"$message_type":"diagnostic","message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error

"}
{"message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`.
{"$message_type":"diagnostic","message":"For more information about this error, try `rustc --explain E0308`.","code":null,"level":"failure-note","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0308`.
"}
10 changes: 5 additions & 5 deletions tests/ui/json/json-bom-plus-crlf-multifile.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
{"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.

Erroneous code examples:

Expand Down Expand Up @@ -26,7 +26,7 @@ most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":622,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
{"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.

Erroneous code examples:

Expand Down Expand Up @@ -54,7 +54,7 @@ most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":682,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
{"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.

Erroneous code examples:

Expand Down Expand Up @@ -82,7 +82,7 @@ most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":746,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
"}
{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
{"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.

Erroneous code examples:

Expand Down Expand Up @@ -110,5 +110,5 @@ most common being when calling a function and passing an argument which has a
different type than the matching type in the function declaration.
"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
"}
{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
{"$message_type":"diagnostic","message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
"}
Loading
Loading