From: David Malcolm Date: Wed, 6 Dec 2023 17:35:44 +0000 (-0500) Subject: diagnostics: prettify JSON output formats X-Git-Tag: basepoints/gcc-15~3911 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3bd8241a1f19827586cbed7832a24f44ff3e22ac;p=thirdparty%2Fgcc.git diagnostics: prettify JSON output formats 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 --- diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 1f930a21eb37..825b3af43fce 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -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; diff --git a/gcc/common.opt b/gcc/common.opt index f070aff8cbc1..5eb5ecff04bd 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -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. diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 418db74522d8..c013192de06e 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -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)); } diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 941fd0f5f747..05b2c6df2e27 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -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 > 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)); } diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 5854c89a387f..b5b6a760ccf9 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -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; } } diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 4fc31438b165..80e53ec92b06 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -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. */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 32f535e1ed46..8e9204302d19 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/gcc.cc b/gcc/gcc.cc index 03ec6e1cb2fa..d73fb0414e98 100644 --- a/gcc/gcc.cc +++ b/gcc/gcc.cc @@ -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; } diff --git a/gcc/gcov.cc b/gcc/gcov.cc index 8b4748d3a1a8..6d4a7bde53ab 100644 --- a/gcc/gcov.cc +++ b/gcc/gcov.cc @@ -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", diff --git a/gcc/json.cc b/gcc/json.cc index d0f157f0dfe7..90ddd7ab3b15 100644 --- a/gcc/json.cc +++ b/gcc/json.cc @@ -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 (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 diff --git a/gcc/json.h b/gcc/json.h index 6fadd119ba57..862e5676a636 100644 --- a/gcc/json.h +++ b/gcc/json.h @@ -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; diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc index 11cad42a4330..b181d6fb15d2 100644 --- a/gcc/optinfo-emit-json.cc +++ b/gcc/optinfo-emit-json.cc @@ -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\""); diff --git a/gcc/opts.cc b/gcc/opts.cc index 5d5efaf1b9eb..7a3830caaa31 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -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; } diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c index 6bab30e3e6cb..c95218c3cfe3 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-1.c @@ -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 "" } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c index 3c12103c9f84..a8828b7b2df7 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-2.c @@ -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 "" } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c index 11d74624ff16..178bbf94b5b2 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-3.c @@ -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 "" } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c index cec1cf924b4f..899a03f0e5e5 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-4.c @@ -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 "" } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c index 86f8c5fb3746..ed3139c7f1b2 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-5.c @@ -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 "" } */ 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 index bcfa92110f54..e798c6b21e1e 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c @@ -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 "" } */ diff --git a/gcc/testsuite/g++.dg/pr90462.C b/gcc/testsuite/g++.dg/pr90462.C index 2585ba0dcdba..b35e41921a60 100644 --- a/gcc/testsuite/g++.dg/pr90462.C +++ b/gcc/testsuite/g++.dg/pr90462.C @@ -1,4 +1,4 @@ -/* { dg-options "-Wdeprecated-copy -fdiagnostics-format=json" } */ +/* { dg-options "-Wdeprecated-copy -fno-diagnostics-json-formatting -fdiagnostics-format=json" } */ template class b; struct B { diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c index 3d798e687e6f..19ac89f2b67c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c @@ -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 diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c index 6971d7cb38b6..a315d208cab7 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c @@ -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 "" } */ diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 index 2993f7c852bf..b8cd61cff23a 100644 --- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 +++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-1.F90 @@ -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 diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 index 1681462fa086..9ff1ef59b343 100644 --- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 +++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90 @@ -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 diff --git a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 index f0a67de76b08..750e186c8acf 100644 --- a/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 +++ b/gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90 @@ -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