]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add -fdiagnostics-format={json-stderr|json-file}
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 2 Jun 2022 19:38:38 +0000 (15:38 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 2 Jun 2022 19:38:38 +0000 (15:38 -0400)
This commit adds -fdiagnostics-format=json-file, writing to
DUMP_BASE_NAME.gcc.json, and adds -fdiagnostics-format=json-stderr,
a synonym for the existing -fdiagnostics-format=json.

gcc/ChangeLog:
* common.opt (fdiagnostics-format=): Add json-stderr and json-file
to description.
(DIAGNOSTICS_OUTPUT_FORMAT_JSON): Rename to...
(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR): ...this.
(diagnostics_output_format): Add json-stderr and json-file.
* diagnostic-format-json.cc (json_flush_to_file): New.
(json_final_cb): Convert to...
(json_flush_to_file): ...this, ...
(json_stderr_final_cb): ...this, and...
(json_file_final_cb): ...this.
(diagnostic_output_format_init): Move to diagnostic.cc.
(json_output_base_file_name): New.
(diagnostic_output_format_init_json): New.
(diagnostic_output_format_init_json_stderr): New.
(diagnostic_output_format_init_json_file): New.
* diagnostic.cc (diagnostic_output_format_init): Move here from
diagnostic-format-json.cc; update for changes to enum.
* diagnostic.h (enum diagnostics_output_format): Rename
DIAGNOSTICS_OUTPUT_FORMAT_JSON to
DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, and add
DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE.
(diagnostic_output_format_init): Add base_file_name param.
(diagnostic_output_format_init_json_stderr): New decl.
(diagnostic_output_format_init_json_file): New dec.
* doc/invoke.texi (-fdiagnostics-format=): Add "json-stderr" and
"json-file".  Rewrite so that the existing "json" is a synonym of
"json-stderr".
* gcc.cc (driver_handle_option): Pass dump_base_name to
diagnostic_output_format_init.
* opts.cc (common_handle_option): Likewise.

gcc/testsuite/ChangeLog:
* c-c++-common/diagnostic-format-json-file-1.c: New test.
* c-c++-common/diagnostic-format-json-stderr-1.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/common.opt
gcc/diagnostic-format-json.cc
gcc/diagnostic.cc
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/gcc.cc
gcc/opts.cc
gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c [new file with mode: 0644]

index 8a0dafc522d12037416aa33e4d4c9e9ccf4a1213..3237ce9b5300b826b9f2daf299cb08cf5bb15d30 100644 (file)
@@ -1390,7 +1390,7 @@ Common Joined RejectNegative UInteger
 
 fdiagnostics-format=
 Common Joined RejectNegative Enum(diagnostics_output_format)
--fdiagnostics-format=[text|json]       Select output format.
+-fdiagnostics-format=[text|json|json-stderr|json-file] Select output format.
 
 fdiagnostics-escape-format=
 Common Joined RejectNegative Enum(diagnostics_escape_format)
@@ -1425,7 +1425,13 @@ EnumValue
 Enum(diagnostics_output_format) String(text) Value(DIAGNOSTICS_OUTPUT_FORMAT_TEXT)
 
 EnumValue
-Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON)
+Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR)
+
+EnumValue
+Enum(diagnostics_output_format) String(json-stderr) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR)
+
+EnumValue
+Enum(diagnostics_output_format) String(json-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE)
 
 fdiagnostics-parseable-fixits
 Common Var(flag_diagnostics_parseable_fixits)
index 62594ebb4d782aa4edab7d817225c318d42b908b..051fa6c2e487b482421017db442447b894bf5fe6 100644 (file)
@@ -285,57 +285,93 @@ json_end_group (diagnostic_context *)
   cur_children_array = NULL;
 }
 
-/* Callback for final cleanup for JSON output.  */
+/* Flush the top-level array to OUTF.  */
 
 static void
-json_final_cb (diagnostic_context *)
+json_flush_to_file (FILE *outf)
 {
-  /* Flush the top-level array.  */
-  toplevel_array->dump (stderr);
-  fprintf (stderr, "\n");
+  toplevel_array->dump (outf);
+  fprintf (outf, "\n");
   delete toplevel_array;
   toplevel_array = NULL;
 }
 
-/* Set the output format for CONTEXT to FORMAT.  */
+/* Callback for final cleanup for JSON output to stderr.  */
 
-void
-diagnostic_output_format_init (diagnostic_context *context,
-                              enum diagnostics_output_format format)
+static void
+json_stderr_final_cb (diagnostic_context *)
+{
+  json_flush_to_file (stderr);
+}
+
+static char *json_output_base_file_name;
+
+/* Callback for final cleanup for JSON output to a file.  */
+
+static void
+json_file_final_cb (diagnostic_context *)
 {
-  switch (format)
+  char *filename = concat (json_output_base_file_name, ".gcc.json", NULL);
+  FILE *outf = fopen (filename, "w");
+  if (!outf)
     {
-    default:
-      gcc_unreachable ();
-    case DIAGNOSTICS_OUTPUT_FORMAT_TEXT:
-      /* The default; do nothing.  */
-      break;
-
-    case DIAGNOSTICS_OUTPUT_FORMAT_JSON:
-      {
-       /* Set up top-level JSON array.  */
-       if (toplevel_array == NULL)
-         toplevel_array = new json::array ();
-
-       /* Override callbacks.  */
-       context->begin_diagnostic = json_begin_diagnostic;
-       context->end_diagnostic = json_end_diagnostic;
-       context->begin_group_cb = json_begin_group;
-       context->end_group_cb =  json_end_group;
-       context->final_cb =  json_final_cb;
-       context->print_path = NULL; /* handled in json_end_diagnostic.  */
-
-       /* The metadata is handled in JSON format, rather than as text.  */
-       context->show_cwe = false;
-
-       /* The option is handled in JSON format, rather than as text.  */
-       context->show_option_requested = false;
-
-       /* Don't colorize the text.  */
-       pp_show_color (context->printer) = false;
-      }
-      break;
+      const char *errstr = xstrerror (errno);
+      fnotice (stderr, "error: unable to open '%s' for writing: %s\n",
+              filename, errstr);
+      free (filename);
+      return;
     }
+  json_flush_to_file (outf);
+  fclose (outf);
+  free (filename);
+}
+
+/* Populate CONTEXT in preparation for JSON output (either to stderr, or
+   to a file).  */
+
+static void
+diagnostic_output_format_init_json (diagnostic_context *context)
+{
+  /* Set up top-level JSON array.  */
+  if (toplevel_array == NULL)
+    toplevel_array = new json::array ();
+
+  /* Override callbacks.  */
+  context->begin_diagnostic = json_begin_diagnostic;
+  context->end_diagnostic = json_end_diagnostic;
+  context->begin_group_cb = json_begin_group;
+  context->end_group_cb =  json_end_group;
+  context->print_path = NULL; /* handled in json_end_diagnostic.  */
+
+  /* The metadata is handled in JSON format, rather than as text.  */
+  context->show_cwe = false;
+
+  /* The option is handled in JSON format, rather than as text.  */
+  context->show_option_requested = false;
+
+  /* Don't colorize the text.  */
+  pp_show_color (context->printer) = false;
+}
+
+/* Populate CONTEXT in preparation for JSON output to stderr.  */
+
+void
+diagnostic_output_format_init_json_stderr (diagnostic_context *context)
+{
+  diagnostic_output_format_init_json (context);
+  context->final_cb = json_stderr_final_cb;
+}
+
+/* Populate CONTEXT in preparation for JSON output to a file named
+   BASE_FILE_NAME.gcc.json.  */
+
+void
+diagnostic_output_format_init_json_file (diagnostic_context *context,
+                                        const char *base_file_name)
+{
+  diagnostic_output_format_init_json (context);
+  context->final_cb = json_file_final_cb;
+  json_output_base_file_name = xstrdup (base_file_name);
 }
 
 #if CHECKING_P
index fef11467b6fb2955584d8b4b3fdc4cdc5be61420..25504834484ff4f11656e7c4f9e196db67290999 100644 (file)
@@ -2072,6 +2072,32 @@ auto_diagnostic_group::~auto_diagnostic_group ()
     }
 }
 
+/* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for
+   file-based output formats.  */
+
+void
+diagnostic_output_format_init (diagnostic_context *context,
+                              const char *base_file_name,
+                              enum diagnostics_output_format format)
+{
+  switch (format)
+    {
+    default:
+      gcc_unreachable ();
+    case DIAGNOSTICS_OUTPUT_FORMAT_TEXT:
+      /* The default; do nothing.  */
+      break;
+
+    case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR:
+      diagnostic_output_format_init_json_stderr (context);
+      break;
+
+    case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE:
+      diagnostic_output_format_init_json_file (context, base_file_name);
+      break;
+    }
+}
+
 /* Implementation of diagnostic_path::num_events vfunc for
    simple_diagnostic_path: simply get the number of events in the vec.  */
 
index 3ca32979dde5d4e52951f7fe49b67db11cfbc8c2..dd3af033ae4ac558430009d37f660e1becefb14d 100644 (file)
@@ -59,8 +59,11 @@ enum diagnostics_output_format
   /* The default: textual output.  */
   DIAGNOSTICS_OUTPUT_FORMAT_TEXT,
 
-  /* JSON-based output.  */
-  DIAGNOSTICS_OUTPUT_FORMAT_JSON
+  /* JSON-based output, to stderr.  */
+  DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR,
+
+  /* JSON-based output, to a file.  */
+  DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE
 };
 
 /* An enum for controlling how diagnostic_paths should be printed.  */
@@ -577,7 +580,11 @@ extern char *file_name_as_prefix (diagnostic_context *, const char *);
 extern char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1;
 
 extern void diagnostic_output_format_init (diagnostic_context *,
+                                          const char *base_file_name,
                                           enum diagnostics_output_format);
+extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context);
+extern void diagnostic_output_format_init_json_file (diagnostic_context *context,
+                                                    const char *base_file_name);
 
 /* Compute the number of digits in the decimal representation of an integer.  */
 extern int num_digits (int);
index 71098d8631381272c31e4a45bf6dc4d110cc2c49..d85b66f60f03d81e7338c30cafa8a405f57fef5d 100644 (file)
@@ -301,7 +301,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
 -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
 -fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
--fdiagnostics-format=@r{[}text@r{|}json@r{]}  @gol
+-fdiagnostics-format=@r{[}text@r{|}json@r{|}json-stderr@r{|}json-file@r{]}  @gol
 -fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
 -fno-diagnostics-show-labels  -fno-diagnostics-show-line-numbers @gol
 -fno-diagnostics-show-cwe  @gol
@@ -5305,14 +5305,19 @@ Unicode characters.  For the example above, the following will be printed:
 @item -fdiagnostics-format=@var{FORMAT}
 @opindex fdiagnostics-format
 Select a different format for printing diagnostics.
-@var{FORMAT} is @samp{text} or @samp{json}.
+@var{FORMAT} is @samp{text}, @samp{json}, @samp{json-stderr},
+or @samp{json-file}.
+
 The default is @samp{text}.
 
-The @samp{json} format consists of a top-level JSON array containing JSON
-objects representing the diagnostics.
+The @samp{json} format is a synonym for @samp{json-stderr}.
+The @samp{json-stderr} and @samp{json-file} formats are identical, apart from
+where the JSON is emitted to - with the former, the JSON is emitted to stderr,
+whereas with @samp{json-file} it is written to @file{@var{source}.gcc.json}.
 
-The JSON is emitted as one line, without formatting; the examples below
-have been formatted for clarity.
+The emitted JSON consists of a top-level JSON array containing JSON objects
+representing the diagnostics.  The JSON is emitted as one line, without
+formatting; the examples below have been formatted for clarity.
 
 Diagnostics can have child diagnostics.  For example, this error and note:
 
index 299e09c4f545feb3b4e15d0eec806fd9a2050de9..563f535d5640436c26404e1352b7ff841f27e677 100644 (file)
@@ -4335,7 +4335,7 @@ driver_handle_option (struct gcc_options *opts,
       break;
 
     case OPT_fdiagnostics_format_:
-      diagnostic_output_format_init (dc,
+      diagnostic_output_format_init (dc, opts->x_dump_base_name,
                                     (enum diagnostics_output_format)value);
       break;
 
index f0c5c4db95571b46a09096734c29164bdf69a10b..bf06a55456ac5499f3066823a9cb3f84374346bc 100644 (file)
@@ -2800,7 +2800,7 @@ common_handle_option (struct gcc_options *opts,
       break;
 
     case OPT_fdiagnostics_format_:
-      diagnostic_output_format_init (dc,
+      diagnostic_output_format_init (dc, opts->x_dump_base_name,
                                     (enum diagnostics_output_format)value);
       break;
 
diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c
new file mode 100644 (file)
index 0000000..ddac780
--- /dev/null
@@ -0,0 +1,8 @@
+/* Check that -fdiagnostics-format=json-file works.  */
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=json-file" } */
+
+#warning message
+
+/* Verify that some JSON was written to a file with the expected name.  */
+/* { dg-final { scan-file "diagnostic-format-json-file-1.c.gcc.json" "\"message\": \"#warning message\"" } } */
diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c
new file mode 100644 (file)
index 0000000..02f780b
--- /dev/null
@@ -0,0 +1,33 @@
+/* Check that "json" and "json-stderr" are synonymous when used as
+   arguments to "-fdiagnostics-format=".  */
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=json-stderr" } */
+
+#error message
+
+/* Use dg-regexp to consume the JSON output starting with
+   the innermost values, and working outwards.
+   We can't rely on any ordering of the keys.  */
+
+/* { dg-regexp "\"kind\": \"error\"" } */
+/* { dg-regexp "\"column-origin\": 1" } */
+/* { dg-regexp "\"escape-source\": false" } */
+/* { dg-regexp "\"message\": \"#error message\"" } */
+
+/* { dg-regexp "\"caret\": \{" } */
+/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */
+/* { dg-regexp "\"line\": 6" } */
+/* { dg-regexp "\"column\": 2" } */
+/* { dg-regexp "\"display-column\": 2" } */
+/* { dg-regexp "\"byte-column\": 2" } */
+
+/* { dg-regexp "\"finish\": \{" } */
+/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */
+/* { dg-regexp "\"line\": 6" } */
+/* { dg-regexp "\"column\": 6" } */
+/* { dg-regexp "\"display-column\": 6" } */
+/* { dg-regexp "\"byte-column\": 6" } */
+
+/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
+/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
+/* { dg-regexp "\[\[\{\}, \]*\]" } */