]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
diagnostics: prettify JSON output formats
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 6 Dec 2023 17:35:44 +0000 (12:35 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 6 Dec 2023 17:35:44 +0000 (12:35 -0500)
Previously our JSON output emitted the JSON all on one line, with
no indentation to show the structure of the values.

Although it's easy to reformat such output (e.g. with
"python -m json.tool"), I've found it's a pain to need to do so
e.g. my text editor sometimes hangs when opening a multimegabyte
json file all on one line.  Similarly diff-ing is easier if the
json is already formatted.

This patch add whitespace to json output to show the structure.
It turned out to be fairly easy to implement using pretty_printer's
existing indentation machinery.

The patch uses this formatting for the various JSON-based diagnostic
output formats.

For example, with this patch, the output from
fdiagnostics-format=json-stderr looks like:

[{"kind": "warning",
  "message": "stack-based buffer overflow",
  "option": "-Wanalyzer-out-of-bounds",
  "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-out-of-bounds",
  "children": [{"kind": "note",
                "message": "write of 350 bytes to beyond the end of ‘buf’",
                "locations": [{"caret": {"file": "../../src/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c",
                                         "line": 20,
                                         "display-column": 3,
                                         "byte-column": 3,
                                         "column": 3},
                               "finish": {"file": "../../src/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c",
                                          "line": 20,
                                          "display-column": 27,
                                          "byte-column": 27,
                                          "column": 27}}],
                "escape-source": false},
               {"kind": "note",
                "message": "valid subscripts for ‘buf’ are ‘[0]’ to ‘[99]’",
                "locations": [{"caret": {"file": "../../src/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c",
                                         "line": 20,
                                         "display-column": 3,
                                         "byte-column": 3,
                                         "column": 3},
                               "finish": {"file": "../../src/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-19.c",
                                          "line": 20,
                                          "display-column": 27,
                                          "byte-column": 27,
                                          "column": 27}}],
                "escape-source": false}],
  "column-origin": 1,
...snip...]

I was able to update almost all of our DejaGnu test cases for JSON to
handle this format tweak, and IMHO it improved the readability of these
test cases, but a couple were more awkward.  Hence I added
-fno-diagnostics-json-formatting as an option to disable this
formatting.

The formatting does not affect the output of -fsave-optimization-record
or the JSON output from gcov (but this could be enabled if desirable).

gcc/analyzer/ChangeLog:
* engine.cc (dump_analyzer_json): Use
flag_diagnostics_json_formatting.

gcc/ChangeLog:
* common.opt (fdiagnostics-json-formatting): New.
* diagnostic-format-json.cc: Add "formatted" boolean
to json_output_format and subclasses, and to the
diagnostic_output_format_init_json_* functions.  Use it when
printing JSON.
* diagnostic-format-sarif.cc: Likewise for sarif_builder,
sarif_output_format, and the various
diagnostic_output_format_init_sarif_* functions.
* diagnostic.cc (diagnostic_output_format_init): Add
"json_formatting" boolean and pass on to the various cases.
* diagnostic.h (diagnostic_output_format_init): Add
"json_formatted" param.
(diagnostic_output_format_init_json_stderr): Add "formatted" param
(diagnostic_output_format_init_json_file): Likewise.
(diagnostic_output_format_init_sarif_stderr): Likewise.
(diagnostic_output_format_init_sarif_file): Likewise.
(diagnostic_output_format_init_sarif_stream): Likewise.
* doc/invoke.texi (-fdiagnostics-format=json): Remove discussion
about JSON output needing formatting.
(-fno-diagnostics-json-formatting): Add.
* gcc.cc (driver_handle_option): Use
opts->x_flag_diagnostics_json_formatting.
* gcov.cc (generate_results): Pass "false" for new formatting
option when printing json.
* json.cc (value::dump): Add new "formatted" param.
(object::print): Likewise, using it to add whitespace to format
the JSON output.
(array::print): Likewise.
(float_number::print): Add new "formatted" param.
(integer_number::print): Likewise.
(string::print): Likewise.
(literal::print): Likewise.
(selftest::assert_print_eq): Add "formatted" param.
(ASSERT_PRINT_EQ): Add "FORMATTED" param.
(selftest::test_writing_objects): Test both formatted and
unformatted printing.
(selftest::test_writing_arrays): Likewise.
(selftest::test_writing_float_numbers): Update for new param of
ASSERT_PRINT_EQ.
(selftest::test_writing_integer_numbers): Likewise.
(selftest::test_writing_strings): Likewise.
(selftest::test_writing_literals): Likewise.
(selftest::test_formatting): New.
(selftest::json_cc_tests): Call it.
* json.h (value::print): Add "formatted" param.
(value::dump): Likewise.
(object::print): Likewise.
(array::print): Likewise.
(float_number::print): Likewise.
(integer_number::print): Likewise.
(string::print): Likewise.
(literal::print): Likewise.
* optinfo-emit-json.cc (optrecord_json_writer::write): Pass
"false" for new formatting option when printing json.
(selftest::test_building_json_from_dump_calls): Likewise.
* opts.cc (common_handle_option): Use
opts->x_flag_diagnostics_json_formatting.

gcc/testsuite/ChangeLog:
* c-c++-common/diagnostic-format-json-1.c: Update expected JSON
output to reflect whitespace.
* c-c++-common/diagnostic-format-json-2.c: Likewise.
* c-c++-common/diagnostic-format-json-3.c: Likewise.
* c-c++-common/diagnostic-format-json-4.c: Likewise.
* c-c++-common/diagnostic-format-json-5.c: Likewise.
* c-c++-common/diagnostic-format-json-stderr-1.c: Likewise.
* g++.dg/pr90462.C: Add -fno-diagnostics-json-formatting.
* gcc.dg/analyzer/malloc-sarif-1.c: Likewise.
* gcc.dg/plugin/diagnostic-test-paths-3.c: Update expected JSON
output to reflect whitespace.
* gfortran.dg/diagnostic-format-json-1.F90: Likewise.
* gfortran.dg/diagnostic-format-json-2.F90: Likewise.
* gfortran.dg/diagnostic-format-json-3.F90: Likewise.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
25 files changed:
gcc/analyzer/engine.cc
gcc/common.opt
gcc/diagnostic-format-json.cc
gcc/diagnostic-format-sarif.cc
gcc/diagnostic.cc
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/gcc.cc
gcc/gcov.cc
gcc/json.cc
gcc/json.h
gcc/optinfo-emit-json.cc
gcc/opts.cc
gcc/testsuite/c-c++-common/diagnostic-format-json-1.c
gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
gcc/testsuite/c-c++-common/diagnostic-format-json-5.c
gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c
gcc/testsuite/g++.dg/pr90462.C
gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c
gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90
gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90

index 1f930a21eb378cf792a629076d3bf13127c23ec1..825b3af43fce6b8ca66ff3d9391304755eca674f 100644 (file)
@@ -6068,7 +6068,7 @@ dump_analyzer_json (const supergraph &sg,
   toplev_obj->set ("egraph", eg.to_json ());
 
   pretty_printer pp;
-  toplev_obj->print (&pp);
+  toplev_obj->print (&pp, flag_diagnostics_json_formatting);
   pp_formatted_text (&pp);
 
   delete toplev_obj;
index f070aff8cbc1b6a70454759239c1508b387c84e4..5eb5ecff04bd692372d26ea9777a00b252bd349f 100644 (file)
@@ -1391,6 +1391,10 @@ Enum(diagnostic_color_rule) String(always) Value(DIAGNOSTICS_COLOR_YES)
 EnumValue
 Enum(diagnostic_color_rule) String(auto) Value(DIAGNOSTICS_COLOR_AUTO)
 
+fdiagnostics-json-formatting
+Common Var(flag_diagnostics_json_formatting) Init(1)
+Enable formatting of JSON output.
+
 fdiagnostics-urls=
 Driver Common Joined RejectNegative Var(flag_diagnostics_show_urls) Enum(diagnostic_url_rule) Init(DIAGNOSTICS_URL_AUTO)
 -fdiagnostics-urls=[never|always|auto] Embed URLs in diagnostics.
index 418db74522d82b44e6b47e400e71ac0264134da5..c013192de06e3ac5041cbd3ce8ddd31c9013bf8d 100644 (file)
@@ -56,11 +56,13 @@ public:
   }
 
 protected:
-  json_output_format (diagnostic_context &context)
+  json_output_format (diagnostic_context &context,
+                     bool formatted)
   : diagnostic_output_format (context),
     m_toplevel_array (new json::array ()),
     m_cur_group (nullptr),
-    m_cur_children_array (nullptr)
+    m_cur_children_array (nullptr),
+    m_formatted (formatted)
   {
   }
 
@@ -68,7 +70,7 @@ protected:
   void
   flush_to_file (FILE *outf)
   {
-    m_toplevel_array->dump (outf);
+    m_toplevel_array->dump (outf, m_formatted);
     fprintf (outf, "\n");
     delete m_toplevel_array;
     m_toplevel_array = nullptr;
@@ -84,6 +86,8 @@ private:
   /* The JSON array for the "children" array within the current diagnostic
      group.  */
   json::array *m_cur_children_array;
+
+  bool m_formatted;
 };
 
 /* Generate a JSON object for LOC.  */
@@ -301,8 +305,9 @@ json_output_format::on_end_diagnostic (const diagnostic_info &diagnostic,
 class json_stderr_output_format : public json_output_format
 {
 public:
-  json_stderr_output_format (diagnostic_context &context)
-  : json_output_format (context)
+  json_stderr_output_format (diagnostic_context &context,
+                            bool formatted)
+    : json_output_format (context, formatted)
   {
   }
   ~json_stderr_output_format ()
@@ -315,8 +320,9 @@ class json_file_output_format : public json_output_format
 {
 public:
   json_file_output_format (diagnostic_context &context,
+                          bool formatted,
                           const char *base_file_name)
-  : json_output_format (context),
+  : json_output_format (context, formatted),
     m_base_file_name (xstrdup (base_file_name))
   {
   }
@@ -367,10 +373,12 @@ diagnostic_output_format_init_json (diagnostic_context *context)
 /* Populate CONTEXT in preparation for JSON output to stderr.  */
 
 void
-diagnostic_output_format_init_json_stderr (diagnostic_context *context)
+diagnostic_output_format_init_json_stderr (diagnostic_context *context,
+                                          bool formatted)
 {
   diagnostic_output_format_init_json (context);
-  context->set_output_format (new json_stderr_output_format (*context));
+  context->set_output_format (new json_stderr_output_format (*context,
+                                                            formatted));
 }
 
 /* Populate CONTEXT in preparation for JSON output to a file named
@@ -378,10 +386,12 @@ diagnostic_output_format_init_json_stderr (diagnostic_context *context)
 
 void
 diagnostic_output_format_init_json_file (diagnostic_context *context,
+                                        bool formatted,
                                         const char *base_file_name)
 {
   diagnostic_output_format_init_json (context);
   context->set_output_format (new json_file_output_format (*context,
+                                                          formatted,
                                                           base_file_name));
 }
 
index 941fd0f5f747604640b18a0cb14a4997542b6ba6..05b2c6df2e27c3cacd4e80f860b044165b7d04a8 100644 (file)
@@ -157,7 +157,8 @@ private:
 class sarif_builder
 {
 public:
-  sarif_builder (diagnostic_context *context);
+  sarif_builder (diagnostic_context *context,
+                bool formatted);
 
   void end_diagnostic (diagnostic_context *context,
                       const diagnostic_info &diagnostic,
@@ -250,6 +251,8 @@ private:
   hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
 
   int m_tabstop;
+
+  bool m_formatted;
 };
 
 /* class sarif_object : public json::object.  */
@@ -401,7 +404,8 @@ sarif_thread_flow::sarif_thread_flow (const diagnostic_thread &thread)
 
 /* sarif_builder's ctor.  */
 
-sarif_builder::sarif_builder (diagnostic_context *context)
+sarif_builder::sarif_builder (diagnostic_context *context,
+                             bool formatted)
 : m_context (context),
   m_invocation_obj (new sarif_invocation ()),
   m_results_array (new json::array ()),
@@ -409,7 +413,8 @@ sarif_builder::sarif_builder (diagnostic_context *context)
   m_seen_any_relative_paths (false),
   m_rule_id_set (),
   m_rules_arr (new json::array ()),
-  m_tabstop (context->m_tabstop)
+  m_tabstop (context->m_tabstop),
+  m_formatted (formatted)
 {
 }
 
@@ -472,7 +477,7 @@ sarif_builder::flush_to_file (FILE *outf)
 {
   m_invocation_obj->prepare_to_flush (m_context);
   json::object *top = make_top_level_object (m_invocation_obj, m_results_array);
-  top->dump (outf);
+  top->dump (outf, m_formatted);
   m_invocation_obj = NULL;
   m_results_array = NULL;
   fprintf (outf, "\n");
@@ -1721,9 +1726,10 @@ public:
   }
 
 protected:
-  sarif_output_format (diagnostic_context &context)
+  sarif_output_format (diagnostic_context &context,
+                      bool formatted)
   : diagnostic_output_format (context),
-    m_builder (&context)
+    m_builder (&context, formatted)
   {}
 
   sarif_builder m_builder;
@@ -1732,8 +1738,10 @@ protected:
 class sarif_stream_output_format : public sarif_output_format
 {
 public:
-  sarif_stream_output_format (diagnostic_context &context, FILE *stream)
-  : sarif_output_format (context),
+  sarif_stream_output_format (diagnostic_context &context,
+                             bool formatted,
+                             FILE *stream)
+  : sarif_output_format (context, formatted),
     m_stream (stream)
   {
   }
@@ -1749,8 +1757,9 @@ class sarif_file_output_format : public sarif_output_format
 {
 public:
   sarif_file_output_format (diagnostic_context &context,
-                          const char *base_file_name)
-  : sarif_output_format (context),
+                           bool formatted,
+                           const char *base_file_name)
+  : sarif_output_format (context, formatted),
     m_base_file_name (xstrdup (base_file_name))
   {
   }
@@ -1801,10 +1810,12 @@ diagnostic_output_format_init_sarif (diagnostic_context *context)
 /* Populate CONTEXT in preparation for SARIF output to stderr.  */
 
 void
-diagnostic_output_format_init_sarif_stderr (diagnostic_context *context)
+diagnostic_output_format_init_sarif_stderr (diagnostic_context *context,
+                                           bool formatted)
 {
   diagnostic_output_format_init_sarif (context);
   context->set_output_format (new sarif_stream_output_format (*context,
+                                                             formatted,
                                                              stderr));
 }
 
@@ -1813,10 +1824,12 @@ diagnostic_output_format_init_sarif_stderr (diagnostic_context *context)
 
 void
 diagnostic_output_format_init_sarif_file (diagnostic_context *context,
+                                         bool formatted,
                                          const char *base_file_name)
 {
   diagnostic_output_format_init_sarif (context);
   context->set_output_format (new sarif_file_output_format (*context,
+                                                           formatted,
                                                            base_file_name));
 }
 
@@ -1824,9 +1837,11 @@ diagnostic_output_format_init_sarif_file (diagnostic_context *context,
 
 void
 diagnostic_output_format_init_sarif_stream (diagnostic_context *context,
+                                           bool formatted,
                                            FILE *stream)
 {
   diagnostic_output_format_init_sarif (context);
   context->set_output_format (new sarif_stream_output_format (*context,
+                                                             formatted,
                                                              stream));
 }
index 5854c89a387f5987c5c578c1cc506b3c3c9b9229..b5b6a760ccf902c317c50db6d747569a9d943cb9 100644 (file)
@@ -2429,7 +2429,8 @@ diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
 void
 diagnostic_output_format_init (diagnostic_context *context,
                               const char *base_file_name,
-                              enum diagnostics_output_format format)
+                              enum diagnostics_output_format format,
+                              bool json_formatting)
 {
   switch (format)
     {
@@ -2440,19 +2441,25 @@ diagnostic_output_format_init (diagnostic_context *context,
       break;
 
     case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR:
-      diagnostic_output_format_init_json_stderr (context);
+      diagnostic_output_format_init_json_stderr (context,
+                                                json_formatting);
       break;
 
     case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE:
-      diagnostic_output_format_init_json_file (context, base_file_name);
+      diagnostic_output_format_init_json_file (context,
+                                              json_formatting,
+                                              base_file_name);
       break;
 
     case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR:
-      diagnostic_output_format_init_sarif_stderr (context);
+      diagnostic_output_format_init_sarif_stderr (context,
+                                                 json_formatting);
       break;
 
     case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
-      diagnostic_output_format_init_sarif_file (context, base_file_name);
+      diagnostic_output_format_init_sarif_file (context,
+                                               json_formatting,
+                                               base_file_name);
       break;
     }
 }
index 4fc31438b165cf51eaa5c64e8a58a06ed31922d5..80e53ec92b06a8caeb250e0d6b0298b97c2d2e4e 100644 (file)
@@ -1062,14 +1062,20 @@ 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);
+                                          enum diagnostics_output_format,
+                                          bool json_formatting);
+extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context,
+                                                      bool formatted);
 extern void diagnostic_output_format_init_json_file (diagnostic_context *context,
+                                                    bool formatted,
                                                     const char *base_file_name);
-extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context *context);
+extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context *context,
+                                                       bool formatted);
 extern void diagnostic_output_format_init_sarif_file (diagnostic_context *context,
+                                                     bool formatted,
                                                      const char *base_file_name);
 extern void diagnostic_output_format_init_sarif_stream (diagnostic_context *context,
+                                                       bool formatted,
                                                        FILE *stream);
 
 /* Compute the number of digits in the decimal representation of an integer.  */
index 32f535e1ed463d3b3a5c9511c5167b9960b19929..8e9204302d19f044807cb5d9094f4a3431063c6f 100644 (file)
@@ -306,6 +306,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}
 -fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]}
 -fdiagnostics-format=@r{[}text@r{|}sarif-stderr@r{|}sarif-file@r{|}json@r{|}json-stderr@r{|}json-file@r{]}
+-fno-diagnostics-json-formatting
 -fno-diagnostics-show-option  -fno-diagnostics-show-caret
 -fno-diagnostics-show-labels  -fno-diagnostics-show-line-numbers
 -fno-diagnostics-show-cwe
@@ -5754,8 +5755,7 @@ 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 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.
+representing the diagnostics.
 
 Diagnostics can have child diagnostics.  For example, this error and note:
 
@@ -6018,6 +6018,24 @@ Diagnostics have a boolean attribute @code{escape-source}, hinting whether
 non-ASCII bytes should be escaped when printing the pertinent lines of
 source code (@code{true} for diagnostics involving source encoding issues).
 
+@opindex fno-diagnostics-json-formatting
+@opindex fdiagnostics-json-formatting
+@item -fno-diagnostics-json-formatting
+By default, when JSON is emitted for diagnostics (via
+@option{-fdiagnostics-format=sarif-stderr},
+@option{-fdiagnostics-format=sarif-file},
+@option{-fdiagnostics-format=json},
+@option{-fdiagnostics-format=json-stderr},
+@option{-fdiagnostics-format=json-file}),
+GCC will add newlines and indentation to visually emphasize the
+hierarchical structure of the JSON.
+
+Use @option{-fno-diagnostics-json-formatting} to suppress this whitespace.
+It must be passed before the option it is to affect.
+
+This is intended for compatibility with tools that do not expect the output
+to contain newlines, such as that emitted by older GCC releases.
+
 @end table
 
 @node Warning Options
index 03ec6e1cb2faadd7920ad842b24181fca676a1f4..d73fb0414e985816a798b2bdf943aba9e5af6f1a 100644 (file)
@@ -4357,7 +4357,8 @@ driver_handle_option (struct gcc_options *opts,
          const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name
                                  : opts->x_main_input_basename);
          diagnostic_output_format_init (dc, basename,
-                                        (enum diagnostics_output_format)value);
+                                        (enum diagnostics_output_format)value,
+                                        opts->x_flag_diagnostics_json_formatting);
          break;
        }
 
index 8b4748d3a1a816dc232ad1772f854a626627319c..6d4a7bde53ab8d711a94365485b9cfb15283ae9f 100644 (file)
@@ -1600,13 +1600,13 @@ generate_results (const char *file_name)
     {
       if (flag_use_stdout)
        {
-         root->dump (stdout);
+         root->dump (stdout, false);
          printf ("\n");
        }
       else
        {
          pretty_printer pp;
-         root->print (&pp);
+         root->print (&pp, false);
          pp_formatted_text (&pp);
 
          fnotice (stdout, "Creating '%s'\n",
index d0f157f0dfe741ed98475d9314b31201ec0b5126..90ddd7ab3b156d3ccbb2e36de19af01a17b41131 100644 (file)
@@ -32,17 +32,15 @@ using namespace json;
 
 /* Dump this json::value tree to OUTF.
 
-   No formatting is done.
-
    The key/value pairs of json::objects are printed in the order
    in which the keys were originally inserted.  */
 
 void
-value::dump (FILE *outf) const
+value::dump (FILE *outf, bool formatted) const
 {
   pretty_printer pp;
   pp_buffer (&pp)->stream = outf;
-  print (&pp);
+  print (&pp, formatted);
   pp_flush (&pp);
 }
 
@@ -63,9 +61,11 @@ object::~object ()
 /* Implementation of json::value::print for json::object.  */
 
 void
-object::print (pretty_printer *pp) const
+object::print (pretty_printer *pp, bool formatted) const
 {
   pp_character (pp, '{');
+  if (formatted)
+    pp_indentation (pp) += 1;
 
   /* Iterate in the order that the keys were inserted.  */
   unsigned i;
@@ -73,15 +73,31 @@ object::print (pretty_printer *pp) const
   FOR_EACH_VEC_ELT (m_keys, i, key)
     {
       if (i > 0)
-       pp_string (pp, ", ");
+       {
+         pp_string (pp, ",");
+         if (formatted)
+           {
+             pp_newline (pp);
+             pp_indent (pp);
+           }
+         else
+           pp_space (pp);
+       }
       map_t &mut_map = const_cast<map_t &> (m_map);
       value *value = *mut_map.get (key);
       pp_doublequote (pp);
       pp_string (pp, key); // FIXME: escaping?
       pp_doublequote (pp);
       pp_string (pp, ": ");
-      value->print (pp);
+      const int indent = strlen (key) + 4;
+      if (formatted)
+       pp_indentation (pp) += indent;
+      value->print (pp, formatted);
+      if (formatted)
+       pp_indentation (pp) -= indent;
     }
+  if (formatted)
+    pp_indentation (pp) -= 1;
   pp_character (pp, '}');
 }
 
@@ -180,17 +196,30 @@ array::~array ()
 /* Implementation of json::value::print for json::array.  */
 
 void
-array::print (pretty_printer *pp) const
+array::print (pretty_printer *pp, bool formatted) const
 {
   pp_character (pp, '[');
+  if (formatted)
+    pp_indentation (pp) += 1;
   unsigned i;
   value *v;
   FOR_EACH_VEC_ELT (m_elements, i, v)
     {
       if (i)
-       pp_string (pp, ", ");
-      v->print (pp);
+       {
+         pp_string (pp, ",");
+         if (formatted)
+           {
+             pp_newline (pp);
+             pp_indent (pp);
+           }
+         else
+           pp_space (pp);
+       }
+      v->print (pp, formatted);
     }
+  if (formatted)
+    pp_indentation (pp) -= 1;
   pp_character (pp, ']');
 }
 
@@ -208,7 +237,8 @@ array::append (value *v)
 /* Implementation of json::value::print for json::float_number.  */
 
 void
-float_number::print (pretty_printer *pp) const
+float_number::print (pretty_printer *pp,
+                    bool formatted ATTRIBUTE_UNUSED) const
 {
   char tmp[1024];
   snprintf (tmp, sizeof (tmp), "%g", m_value);
@@ -220,7 +250,8 @@ float_number::print (pretty_printer *pp) const
 /* Implementation of json::value::print for json::integer_number.  */
 
 void
-integer_number::print (pretty_printer *pp) const
+integer_number::print (pretty_printer *pp,
+                      bool formatted ATTRIBUTE_UNUSED) const
 {
   char tmp[1024];
   snprintf (tmp, sizeof (tmp), "%ld", m_value);
@@ -250,7 +281,8 @@ string::string (const char *utf8, size_t len)
 /* Implementation of json::value::print for json::string.  */
 
 void
-string::print (pretty_printer *pp) const
+string::print (pretty_printer *pp,
+              bool formatted ATTRIBUTE_UNUSED) const
 {
   pp_character (pp, '"');
   for (size_t i = 0; i != m_len; ++i)
@@ -294,7 +326,8 @@ string::print (pretty_printer *pp) const
 /* Implementation of json::value::print for json::literal.  */
 
 void
-literal::print (pretty_printer *pp) const
+literal::print (pretty_printer *pp,
+               bool formatted ATTRIBUTE_UNUSED) const
 {
   switch (m_kind)
     {
@@ -322,15 +355,18 @@ namespace selftest {
 /* Verify that JV->print () prints EXPECTED_JSON.  */
 
 static void
-assert_print_eq (const location &loc, const json::value &jv, const char *expected_json)
+assert_print_eq (const location &loc,
+                const json::value &jv,
+                bool formatted,
+                const char *expected_json)
 {
   pretty_printer pp;
-  jv.print (&pp);
+  jv.print (&pp, formatted);
   ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
 }
 
-#define ASSERT_PRINT_EQ(JV, EXPECTED_JSON) \
-  assert_print_eq (SELFTEST_LOCATION, JV, EXPECTED_JSON)
+#define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON)  \
+  assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
 
 /* Verify that object::get works as expected.  */
 
@@ -354,7 +390,11 @@ test_writing_objects ()
   obj.set_string ("baz", "quux");
   /* This test relies on json::object writing out key/value pairs
      in key-insertion order.  */
-  ASSERT_PRINT_EQ (obj, "{\"foo\": \"bar\", \"baz\": \"quux\"}");
+  ASSERT_PRINT_EQ (obj, true,
+                  "{\"foo\": \"bar\",\n"
+                  " \"baz\": \"quux\"}");
+  ASSERT_PRINT_EQ (obj, false,
+                  "{\"foo\": \"bar\", \"baz\": \"quux\"}");
 }
 
 /* Verify that JSON arrays are written correctly.  */
@@ -363,13 +403,17 @@ static void
 test_writing_arrays ()
 {
   array arr;
-  ASSERT_PRINT_EQ (arr, "[]");
+  ASSERT_PRINT_EQ (arr, true, "[]");
 
   arr.append (new json::string ("foo"));
-  ASSERT_PRINT_EQ (arr, "[\"foo\"]");
+  ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
 
   arr.append (new json::string ("bar"));
-  ASSERT_PRINT_EQ (arr, "[\"foo\", \"bar\"]");
+  ASSERT_PRINT_EQ (arr, true,
+                  "[\"foo\",\n"
+                  " \"bar\"]");
+  ASSERT_PRINT_EQ (arr, false,
+                  "[\"foo\", \"bar\"]");
 }
 
 /* Verify that JSON numbers are written correctly.  */
@@ -377,20 +421,20 @@ test_writing_arrays ()
 static void
 test_writing_float_numbers ()
 {
-  ASSERT_PRINT_EQ (float_number (0), "0");
-  ASSERT_PRINT_EQ (float_number (42), "42");
-  ASSERT_PRINT_EQ (float_number (-100), "-100");
-  ASSERT_PRINT_EQ (float_number (123456789), "1.23457e+08");
+  ASSERT_PRINT_EQ (float_number (0), true, "0");
+  ASSERT_PRINT_EQ (float_number (42), true, "42");
+  ASSERT_PRINT_EQ (float_number (-100), true, "-100");
+  ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
 }
 
 static void
 test_writing_integer_numbers ()
 {
-  ASSERT_PRINT_EQ (integer_number (0), "0");
-  ASSERT_PRINT_EQ (integer_number (42), "42");
-  ASSERT_PRINT_EQ (integer_number (-100), "-100");
-  ASSERT_PRINT_EQ (integer_number (123456789), "123456789");
-  ASSERT_PRINT_EQ (integer_number (-123456789), "-123456789");
+  ASSERT_PRINT_EQ (integer_number (0), true, "0");
+  ASSERT_PRINT_EQ (integer_number (42), true, "42");
+  ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
+  ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
+  ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
 }
 
 /* Verify that JSON strings are written correctly.  */
@@ -399,16 +443,16 @@ static void
 test_writing_strings ()
 {
   string foo ("foo");
-  ASSERT_PRINT_EQ (foo, "\"foo\"");
+  ASSERT_PRINT_EQ (foo, true, "\"foo\"");
 
   string contains_quotes ("before \"quoted\" after");
-  ASSERT_PRINT_EQ (contains_quotes, "\"before \\\"quoted\\\" after\"");
+  ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
 
   const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
   string not_terminated (data, 3);
-  ASSERT_PRINT_EQ (not_terminated, "\"abc\"");
+  ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
   string embedded_null (data, sizeof data);
-  ASSERT_PRINT_EQ (embedded_null, "\"abcd\\0ef\"");
+  ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
 }
 
 /* Verify that JSON literals are written correctly.  */
@@ -416,12 +460,50 @@ test_writing_strings ()
 static void
 test_writing_literals ()
 {
-  ASSERT_PRINT_EQ (literal (JSON_TRUE), "true");
-  ASSERT_PRINT_EQ (literal (JSON_FALSE), "false");
-  ASSERT_PRINT_EQ (literal (JSON_NULL), "null");
+  ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
+  ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
+  ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
 
-  ASSERT_PRINT_EQ (literal (true), "true");
-  ASSERT_PRINT_EQ (literal (false), "false");
+  ASSERT_PRINT_EQ (literal (true), true, "true");
+  ASSERT_PRINT_EQ (literal (false), true, "false");
+}
+
+/* Verify that nested values are formatted correctly when written.  */
+
+static void
+test_formatting ()
+{
+  object obj;
+  object *child = new object;
+  object *grandchild = new object;
+
+  obj.set_string ("str", "bar");
+  obj.set ("child", child);
+  obj.set_integer ("int", 42);
+
+  child->set ("grandchild", grandchild);
+  child->set_integer ("int", 1776);
+
+  array *arr = new array;
+  for (int i = 0; i < 3; i++)
+    arr->append (new integer_number (i));
+  grandchild->set ("arr", arr);
+  grandchild->set_integer ("int", 1066);
+
+  /* This test relies on json::object writing out key/value pairs
+     in key-insertion order.  */
+  ASSERT_PRINT_EQ (obj, true,
+                  ("{\"str\": \"bar\",\n"
+                   " \"child\": {\"grandchild\": {\"arr\": [0,\n"
+                   "                                  1,\n"
+                   "                                  2],\n"
+                   "                          \"int\": 1066},\n"
+                   "           \"int\": 1776},\n"
+                   " \"int\": 42}"));
+  ASSERT_PRINT_EQ (obj, false,
+                  ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
+                   " {\"arr\": [0, 1, 2], \"int\": 1066},"
+                   " \"int\": 1776}, \"int\": 42}"));
 }
 
 /* Run all of the selftests within this file.  */
@@ -436,6 +518,7 @@ json_cc_tests ()
   test_writing_integer_numbers ();
   test_writing_strings ();
   test_writing_literals ();
+  test_formatting ();
 }
 
 } // namespace selftest
index 6fadd119ba57dded682c3b109c5aa5cd7f559118..862e5676a636a0d92c947919021b90be060f8767 100644 (file)
@@ -80,9 +80,9 @@ class value
  public:
   virtual ~value () {}
   virtual enum kind get_kind () const = 0;
-  virtual void print (pretty_printer *pp) const = 0;
+  virtual void print (pretty_printer *pp, bool formatted) const = 0;
 
-  void dump (FILE *) const;
+  void dump (FILE *, bool formatted) const;
 };
 
 /* Subclass of value for objects: a collection of key/value pairs
@@ -97,7 +97,7 @@ class object : public value
   ~object ();
 
   enum kind get_kind () const final override { return JSON_OBJECT; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
   void set (const char *key, value *v);
   value *get (const char *key) const;
@@ -126,7 +126,7 @@ class array : public value
   ~array ();
 
   enum kind get_kind () const final override { return JSON_ARRAY; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
   void append (value *v);
 
@@ -142,7 +142,7 @@ class float_number : public value
   float_number (double value) : m_value (value) {}
 
   enum kind get_kind () const final override { return JSON_FLOAT; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
   double get () const { return m_value; }
 
@@ -158,7 +158,7 @@ class integer_number : public value
   integer_number (long value) : m_value (value) {}
 
   enum kind get_kind () const final override { return JSON_INTEGER; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
   long get () const { return m_value; }
 
@@ -177,7 +177,7 @@ class string : public value
   ~string () { free (m_utf8); }
 
   enum kind get_kind () const final override { return JSON_STRING; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
   const char *get_string () const { return m_utf8; }
   size_t get_length () const { return m_len; }
@@ -199,7 +199,7 @@ class literal : public value
   literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
 
   enum kind get_kind () const final override { return m_kind; }
-  void print (pretty_printer *pp) const final override;
+  void print (pretty_printer *pp, bool formatted) const final override;
 
  private:
   enum kind m_kind;
index 11cad42a43305bba0a87b441f2826a0d9f83fdf7..b181d6fb15d2ae90ee2f9701ea3b325c0a0f5918 100644 (file)
@@ -103,7 +103,7 @@ void
 optrecord_json_writer::write () const
 {
   pretty_printer pp;
-  m_root_tuple->print (&pp);
+  m_root_tuple->print (&pp, false);
 
   bool emitted_error = false;
   char *filename = concat (dump_base_name, ".opt-record.json.gz", NULL);
@@ -466,7 +466,7 @@ test_building_json_from_dump_calls ()
 
   /* Verify that the json is sane.  */
   pretty_printer pp;
-  json_obj->print (&pp);
+  json_obj->print (&pp, false);
   const char *json_str = pp_formatted_text (&pp);
   ASSERT_STR_CONTAINS (json_str, "impl_location");
   ASSERT_STR_CONTAINS (json_str, "\"kind\": \"note\"");
index 5d5efaf1b9eb7868d036f4e00779fab2044d0edd..7a3830caaa31f169957e287af23a4b8db66fbeca 100644 (file)
@@ -2949,7 +2949,8 @@ common_handle_option (struct gcc_options *opts,
          const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name
                                  : opts->x_main_input_basename);
          diagnostic_output_format_init (dc, basename,
-                                        (enum diagnostics_output_format)value);
+                                        (enum diagnostics_output_format)value,
+                                        opts->x_flag_diagnostics_json_formatting);
          break;
        }
 
index 6bab30e3e6cb0b94a3fcc2c826a512b1a2019b58..c95218c3cfe3c06da7dda7b0d1333b246738d351 100644 (file)
@@ -3,28 +3,20 @@
 
 #error message
 
-/* Use dg-regexp to consume the JSON output starting with
-   the innermost values, and working outwards.  */
-
-/* { 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-1.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { 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-1.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { dg-regexp "\"column\": 6" } */
-/* { dg-regexp "\"display-column\": 6" } */
-/* { dg-regexp "\"byte-column\": 6" } */
-
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
-/* { dg-regexp "\[\[\{\}, \]*\]" } */
+/* { dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "#error message",
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 6,
+                            "byte-column": 6,
+                            "column": 6}}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index 3c12103c9f847746a4adb8e73bb8b73497a54356..a8828b7b2df7a26e44e1261dc465aeb2938044ec 100644 (file)
@@ -3,30 +3,24 @@
 
 #warning message
 
-/* Use dg-regexp to consume the JSON output starting with
-   the innermost values, and working outwards.  */
-
-/* { dg-regexp "\"kind\": \"warning\"" } */
-/* { dg-regexp "\"column-origin\": 1" } */
-/* { dg-regexp "\"escape-source\": false" } */
-/* { dg-regexp "\"message\": \"#warning message\"" } */
-/* { dg-regexp "\"option\": \"-Wcpp\"" } */
-/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
-
-/* { dg-regexp "\"caret\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { 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-2.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { dg-regexp "\"column\": 8" } */
-/* { dg-regexp "\"display-column\": 8" } */
-/* { dg-regexp "\"byte-column\": 8" } */
-
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
-/* { dg-regexp "\[\[\{\}, \]*\]" } */
+/* { dg-begin-multiline-output "" }
+[{"kind": "warning",
+  "message": "#warning message",
+  "option": "-Wcpp",
+   { dg-end-multiline-output "" } */
+/* { dg-regexp "  \"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\",\n" } */
+/* { dg-begin-multiline-output "" }
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 8,
+                            "byte-column": 8,
+                            "column": 8}}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index 11d74624ff1643d29300aa8567787bb9dca0076c..178bbf94b5b2f9f382c5e735d375c7f7bfbb0fee 100644 (file)
@@ -3,30 +3,24 @@
 
 #warning message
 
-/* Use dg-regexp to consume the JSON output starting with
-   the innermost values, and working outwards.  */
-
-/* { dg-regexp "\"kind\": \"error\"" } */
-/* { dg-regexp "\"column-origin\": 1" } */
-/* { dg-regexp "\"escape-source\": false" } */
-/* { dg-regexp "\"message\": \"#warning message\"" } */
-/* { dg-regexp "\"option\": \"-Werror=cpp\"" } */
-/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
-
-/* { dg-regexp "\"caret\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { 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-3.c\"" } */
-/* { dg-regexp "\"line\": 4" } */
-/* { dg-regexp "\"column\": 8" } */
-/* { dg-regexp "\"display-column\": 8" } */
-/* { dg-regexp "\"byte-column\": 8" } */
-
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */
-/* { dg-regexp "\[\[\{\}, \]*\]" } */
+/* { dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "#warning message",
+  "option": "-Werror=cpp",
+   { dg-end-multiline-output "" } */
+/* { dg-regexp "  \"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\",\n" } */
+/* { dg-begin-multiline-output "" }
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 8,
+                            "byte-column": 8,
+                            "column": 8}}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index cec1cf924b4f77a26202cf9269e9f54560b3e89c..899a03f0e5e5ddbb5d7bb586d3d0bbb07edb58ad 100644 (file)
@@ -9,63 +9,36 @@ int test (void)
   return 5;
 }
 
-/* Use dg-regexp to consume the JSON output starting with
-   the innermost values, and working outwards.  */
-
-/* Verify nested diagnostics.  */
-
-/* The nested diagnostic.  */
-
-/* { dg-regexp "\"kind\": \"note\"" } */
-/* { dg-regexp "\"message\": \"...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'\"" } */
-/* { dg-regexp "\"escape-source\": false" } */
-
-/* { dg-regexp "\"caret\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
-/* { dg-regexp "\"line\": 8" } */
-/* { dg-regexp "\"column\": 5" } */
-/* { dg-regexp "\"display-column\": 5" } */
-/* { dg-regexp "\"byte-column\": 5" } */
-
-/* { dg-regexp "\"finish\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
-/* { dg-regexp "\"line\": 8" } */
-/* { dg-regexp "\"column\": 10" } */
-/* { dg-regexp "\"display-column\": 10" } */
-/* { dg-regexp "\"byte-column\": 10" } */
-
-/* The outer diagnostic.  */
-
-/* { dg-regexp "\"kind\": \"warning\"" } */
-/* { dg-regexp "\"column-origin\": 1" } */
-/* { dg-regexp "\"message\": \"this 'if' clause does not guard...\"" } */
-/* { dg-regexp "\"escape-source\": false" } */
-/* { dg-regexp "\"option\": \"-Wmisleading-indentation\"" } */
-/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wmisleading-indentation\"" } */
-
-/* { dg-regexp "\"caret\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
-/* { dg-regexp "\"line\": 6" } */
-/* { dg-regexp "\"column\": 3" } */
-/* { dg-regexp "\"display-column\": 3" } */
-/* { dg-regexp "\"byte-column\": 3" } */
-
-/* { dg-regexp "\"finish\": \{" } */
-/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
-/* { dg-regexp "\"line\": 6" } */
-/* { dg-regexp "\"column\": 4" } */
-/* { dg-regexp "\"display-column\": 4" } */
-/* { dg-regexp "\"byte-column\": 4" } */
-
-/* More from the nested diagnostic (we can't guarantee what order the
-   "file" keys are consumed).  */
-
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-
-/* More from the outer diagnostic.  */
-
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-
-/* { dg-regexp "\"children\": \[\[\{\}, \]*\]" } */
-/* { dg-regexp "\[\[\{\}, \]*\]" } */
-
+/* { dg-begin-multiline-output "" }
+[{"kind": "warning",
+  "message": "this 'if' clause does not guard...",
+  "option": "-Wmisleading-indentation",
+   { dg-end-multiline-output "" } */
+/* { dg-regexp "  \"option_url\": \"https:\[^\n\r\"\]*#index-Wmisleading-indentation\",\n" } */
+/* { dg-begin-multiline-output "" }
+  "children": [{"kind": "note",
+                "message": "...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'",
+                "locations": [{"caret": {"file":
+                                         "line": 8,
+                                         "display-column": 5,
+                                         "byte-column": 5,
+                                         "column": 5},
+                               "finish": {"file":
+                                          "line": 8,
+                                          "display-column": 10,
+                                          "byte-column": 10,
+                                          "column": 10}}],
+                "escape-source": false}],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 6,
+                           "display-column": 3,
+                           "byte-column": 3,
+                           "column": 3},
+                 "finish": {"file":
+                            "line": 6,
+                            "display-column": 4,
+                            "byte-column": 4,
+                            "column": 4}}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index 86f8c5fb3746905dd5ff4d992daa69daf4b55edc..ed3139c7f1b2061e067ba597ffbcf9eb1abdcf95 100644 (file)
@@ -8,61 +8,31 @@ int test (struct s *ptr)
   return ptr->colour;
 }
 
-/* Verify fix-it hints.
-
-   Use dg-regexp to consume the JSON output from start to
-   finish, relying on the ordering of the keys.
-   The following uses indentation to visualize the structure
-   of the JSON (although the actual output is all on one line).
-
-  { dg-regexp {\[} }
-    { dg-regexp {\{} }
-     { dg-regexp {"kind": "error"} }
-     { dg-regexp {, "message": "'struct s' has no member named 'colour'; did you mean 'color'\?"} }
-     { dg-regexp {, "children": \[\]} }
-     { dg-regexp {, "column-origin": 1} }
-     { dg-regexp {, "locations": } }
-       { dg-regexp {\[} }
-         { dg-regexp {\{} }
-           { dg-regexp {"caret": } }
-             { dg-regexp {\{} }
-               { dg-regexp {"file": "[^\n\r"]*diagnostic-format-json-5.c"} }
-               { dg-regexp {, "line": 8} }
-               { dg-regexp {, "display-column": 15} }
-               { dg-regexp {, "byte-column": 15} }
-               { dg-regexp {, "column": 15} }
-             { dg-regexp {\}} }
-           { dg-regexp {, "finish": } }
-             { dg-regexp {\{} }
-               { dg-regexp {"file": "[^\n\r"]*diagnostic-format-json-5.c"} }
-               { dg-regexp {, "line": 8} }
-               { dg-regexp {, "display-column": 20} }
-               { dg-regexp {, "byte-column": 20} }
-               { dg-regexp {, "column": 20} }
-             { dg-regexp {\}} }
-           { dg-regexp {\}} }
-         { dg-regexp {\]} }
-       { dg-regexp {, "fixits": } }
-       { dg-regexp {\[} }
-         { dg-regexp {\{} }
-           { dg-regexp {"start": } }
-             { dg-regexp {\{} }
-               { dg-regexp {"file": "[^\n\r"]*diagnostic-format-json-5.c"} }
-               { dg-regexp {, "line": 8} }
-               { dg-regexp {, "display-column": 15} }
-               { dg-regexp {, "byte-column": 15} }
-               { dg-regexp {, "column": 15} }
-             { dg-regexp {\}} }
-           { dg-regexp {, "next": } }
-             { dg-regexp {\{} }
-               { dg-regexp {"file": "[^\n\r"]*diagnostic-format-json-5.c"} }
-               { dg-regexp {, "line": 8} }
-               { dg-regexp {, "display-column": 21} }
-               { dg-regexp {, "byte-column": 21} }
-               { dg-regexp {, "column": 21} }
-             { dg-regexp {\}} }
-           { dg-regexp {, "string": "color"} }
-         { dg-regexp {\}} }
-       { dg-regexp {\]} }
-     { dg-regexp {, "escape-source": false\}} }
-   { dg-regexp {\]} }  */
+/* { dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "'struct s' has no member named 'colour'; did you mean 'color'?",
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 8,
+                           "display-column": 15,
+                           "byte-column": 15,
+                           "column": 15},
+                 "finish": {"file":
+                            "line": 8,
+                            "display-column": 20,
+                            "byte-column": 20,
+                            "column": 20}}],
+  "fixits": [{"start": {"file":
+                        "line": 8,
+                        "display-column": 15,
+                        "byte-column": 15,
+                        "column": 15},
+              "next": {"file":
+                       "line": 8,
+                       "display-column": 21,
+                       "byte-column": 21,
+                       "column": 21},
+              "string": "color"}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index bcfa92110f546e22ea9946e78201caf49a208f0a..e798c6b21e1e537e61c7c33c88b231bca653fe10 100644 (file)
@@ -5,28 +5,20 @@
 
 #error message
 
-/* Use dg-regexp to consume the JSON output starting with
-   the innermost values, and working outwards.  */
-
-/* { 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 "\[\[\{\}, \]*\]" } */
+/* { dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "#error message",
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 6,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 6,
+                            "display-column": 6,
+                            "byte-column": 6,
+                            "column": 6}}],
+  "escape-source": false}]
+   { dg-end-multiline-output "" } */
index 2585ba0dcdba69b67b60ee2c496863435ce9060d..b35e41921a60632bcb9a2b00858a26a232c0e0ed 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-options "-Wdeprecated-copy -fdiagnostics-format=json" } */
+/* { dg-options "-Wdeprecated-copy -fno-diagnostics-json-formatting -fdiagnostics-format=json" } */
 
 template <class> class b;
 struct B {
index 3d798e687e6f0d2d4960f91dc388df28db2508d1..19ac89f2b67cb2986a6e7e746d69bfedb3636454 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-additional-options "-fdiagnostics-format=sarif-file" } */
+/* { dg-additional-options " -fno-diagnostics-json-formatting -fdiagnostics-format=sarif-file" } */
 
 #include <stdlib.h>
 
index 6971d7cb38b63383162bb7a28b9ddfc985179e1e..a315d208cab7483d3cb786e355a2c387d73521f5 100644 (file)
@@ -32,7 +32,44 @@ make_a_list_of_random_ints_badly(PyObject *self,
   return list;
 }
 
-/* FIXME: test the events within a path.  */
-/* { dg-regexp "\"kind\": \"error\"" } */
-/* { dg-regexp "\"path\": " } */
-/* { dg-regexp ".*" } */
+/* { dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter",
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file": "
+                           "line": 29,
+                           "display-column": 5,
+                           "byte-column": 5,
+                           "column": 5},
+                 "finish": {"file": "
+                            "line": 29,
+                            "display-column": 29,
+                            "byte-column": 29,
+                            "column": 29}}],
+  "path": [{"location": {"file": "
+                         "line": 25,
+                         "display-column": 10,
+                         "byte-column": 10,
+                         "column": 10},
+            "description": "when 'PyList_New' fails, returning NULL",
+            "function": "make_a_list_of_random_ints_badly",
+            "depth": 0},
+           {"location": {"file": "
+                         "line": 27,
+                         "display-column": 17,
+                         "byte-column": 17,
+                         "column": 17},
+            "description": "when 'i < count'",
+            "function": "make_a_list_of_random_ints_badly",
+            "depth": 0},
+           {"location": {"file": "
+                         "line": 29,
+                         "display-column": 5,
+                         "byte-column": 5,
+                         "column": 5},
+            "description": "when calling 'PyList_Append', passing NULL from (1) as argument 1",
+            "function": "make_a_list_of_random_ints_badly",
+            "depth": 0}],
+  "escape-source": false}]
+{ dg-end-multiline-output "" } */
index 2993f7c852bf4207943cd86421dd96978db57a10..b8cd61cff23a12d5a46b221223ef4bd5d66da33f 100644 (file)
@@ -3,29 +3,22 @@
 
 #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-1.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { 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-1.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { dg-regexp "\"column\": 6" }
-! { dg-regexp "\"display-column\": 6" }
-! { dg-regexp "\"byte-column\": 6" }
-
-! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
-! { dg-regexp "\"children\": \[\[\]\[\]\]" }
-! { dg-regexp "\[\[\{\}, \]*\]" }
+#if 0
+{ dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "#error message",
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 6,
+                            "byte-column": 6,
+                            "column": 6}}],
+  "escape-source": false}]
+{ dg-end-multiline-output "" }
+#endif  
index 1681462fa086ab2e18f054c8d8c2ee4692175077..9ff1ef59b3435aaa432ad689390faf0838cc7f22 100644 (file)
@@ -3,31 +3,24 @@
 
 #warning 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\": \"warning\"" }
-! { dg-regexp "\"column-origin\": 1" }
-! { dg-regexp "\"escape-source\": false" }
-! { dg-regexp "\"message\": \"#warning message\"" }
-! { dg-regexp "\"option\": \"-Wcpp\"" }
-! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
-
-! { dg-regexp "\"caret\": \{" }
-! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { 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-2.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { dg-regexp "\"column\": 8" }
-! { dg-regexp "\"display-column\": 8" }
-! { dg-regexp "\"byte-column\": 8" }
-
-! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
-! { dg-regexp "\"children\": \[\[\]\[\]\]" }
-! { dg-regexp "\[\[\{\}, \]*\]" }
+#if 0
+{ dg-begin-multiline-output "" }
+[{"kind": "warning",
+  "message": "#warning message",
+  "option": "-Wcpp",
+  "option_url":
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 8,
+                            "byte-column": 8,
+                            "column": 8}}],
+  "escape-source": false}]
+{ dg-end-multiline-output "" }
+#endif  
index f0a67de76b083bacd4e065a40c15b6cd2ce704a0..750e186c8acfc99b68bb0dc3ddcfd961ddfe1908 100644 (file)
@@ -3,31 +3,24 @@
 
 #warning 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\": \"#warning message\"" }
-! { dg-regexp "\"option\": \"-Werror=cpp\"" }
-! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
-
-! { dg-regexp "\"caret\": \{" }
-! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { 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-3.F90\"" }
-! { dg-regexp "\"line\": 4" }
-! { dg-regexp "\"column\": 8" }
-! { dg-regexp "\"display-column\": 8" }
-! { dg-regexp "\"byte-column\": 8" }
-
-! { dg-regexp "\"locations\": \[\[\{\}, \]*\]" }
-! { dg-regexp "\"children\": \[\[\]\[\]\]" }
-! { dg-regexp "\[\[\{\}, \]*\]" }
+#if 0
+{ dg-begin-multiline-output "" }
+[{"kind": "error",
+  "message": "#warning message",
+  "option": "-Werror=cpp",
+  "option_url":
+  "children": [],
+  "column-origin": 1,
+  "locations": [{"caret": {"file":
+                           "line": 4,
+                           "display-column": 2,
+                           "byte-column": 2,
+                           "column": 2},
+                 "finish": {"file":
+                            "line": 4,
+                            "display-column": 8,
+                            "byte-column": 8,
+                            "column": 8}}],
+  "escape-source": false}]
+{ dg-end-multiline-output "" }
+#endif