aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-06-02 15:38:38 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2022-06-02 15:38:38 -0400
commit5ab73173cca4610e59df8a3fe9cb5b30ded75aec (patch)
tree4a87b670311228c8d5c16ad9af7d0c70fcd10061 /gcc
parent4f9ad0b4b0a8c780b85a06096b9926ca85d7a9a6 (diff)
downloadgcc-5ab73173cca4610e59df8a3fe9cb5b30ded75aec.zip
gcc-5ab73173cca4610e59df8a3fe9cb5b30ded75aec.tar.gz
gcc-5ab73173cca4610e59df8a3fe9cb5b30ded75aec.tar.bz2
Add -fdiagnostics-format={json-stderr|json-file}
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>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/common.opt10
-rw-r--r--gcc/diagnostic-format-json.cc116
-rw-r--r--gcc/diagnostic.cc26
-rw-r--r--gcc/diagnostic.h11
-rw-r--r--gcc/doc/invoke.texi17
-rw-r--r--gcc/gcc.cc2
-rw-r--r--gcc/opts.cc2
-rw-r--r--gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c8
-rw-r--r--gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c33
9 files changed, 173 insertions, 52 deletions
diff --git a/gcc/common.opt b/gcc/common.opt
index 8a0dafc..3237ce9 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -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)
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 62594eb..051fa6c 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -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
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index fef1146..2550483 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -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. */
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 3ca3297..dd3af03 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -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);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 71098d8..d85b66f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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:
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 299e09c..563f535 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -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;
diff --git a/gcc/opts.cc b/gcc/opts.cc
index f0c5c4d..bf06a55 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -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
index 0000000..ddac780
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c
@@ -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
index 0000000..02f780b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c
@@ -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 "\[\[\{\}, \]*\]" } */