about summary refs log tree commit diff
path: root/compiler/rustc_errors/src/json.rs
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jsgf@fb.com>2023-09-08 18:47:59 -0700
committerJeremy Fitzhardinge <jsgf@fb.com>2023-09-19 14:17:02 -0700
commit5c8170656bb18995795124d4690f8f3ab503e184 (patch)
treedf7cc6adc980f06f231322457eb03703cfc302a2 /compiler/rustc_errors/src/json.rs
parentac5ac4754a4a837f7138a1fa5ab01475b63fc9fe (diff)
downloadrust-5c8170656bb18995795124d4690f8f3ab503e184.tar.gz
rust-5c8170656bb18995795124d4690f8f3ab503e184.zip
Add `type` field to json diagnostic outputs
Currently the json-formatted outputs have no way to unambiguously
determine which kind of message is being output. A consumer can look for
specific fields in the json object (eg "message"), but there's no
guarantee that in future some other kind of output will have a field of
the same name.

This PR adds a `"type"` field to add json outputs which can be used to
unambiguously determine which kind of output it is. The mapping is:

diagnostic: regular compiler diagnostics
artifact: artifact notifications
future_incompat: Report of future incompatibility
unused_extern: Unused crate warnings/errors

This matches the "internally tagged" representation for serde enums.
Diffstat (limited to 'compiler/rustc_errors/src/json.rs')
-rw-r--r--compiler/rustc_errors/src/json.rs46
1 files changed, 22 insertions, 24 deletions
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 0cb75c71b73..7b937bd1459 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -145,6 +145,24 @@ 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 {
+            writeln!(self.dst, "{}", serde_json::to_string_pretty(&val).unwrap())
+        } else {
+            writeln!(self.dst, "{}", serde_json::to_string(&val).unwrap())
+        }
+        .and_then(|_| self.dst.flush())
+    }
+}
+
+#[derive(Serialize)]
+#[serde(tag = "type", rename_all = "snake_case")]
+enum EmitTyped<'a> {
+    Diagnostic(Diagnostic),
+    Artifact(ArtifactNotification<'a>),
+    FutureIncompat(FutureIncompatReport),
+    UnusedExtern(UnusedExterns<'a, 'a, 'a>),
 }
 
 impl Translate for JsonEmitter {
@@ -160,12 +178,7 @@ 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:?}");
         }
@@ -173,12 +186,7 @@ impl Emitter for JsonEmitter {
 
     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:?}");
         }
@@ -195,12 +203,7 @@ impl Emitter for JsonEmitter {
             })
             .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:?}");
         }
@@ -209,12 +212,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:?}");
         }