From patchwork Wed Dec 6 17:50:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1872934 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=G0k4qIcY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SllcP64xBz1yST for ; Thu, 7 Dec 2023 05:02:45 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 404F6385C6F9 for ; Wed, 6 Dec 2023 18:02:43 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id BCC1F3858D3C for ; Wed, 6 Dec 2023 18:02:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BCC1F3858D3C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BCC1F3858D3C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701885749; cv=none; b=Ng/R+aEFDQcmwqokiDXDzrdKBUw937KsAs9P1D7FJkZaL+6USpCf8uie4/JhA24E9wP7cNz0N3U+A8qPoFVEzqvvMvgN0ksl8zK6MICQ6SWofVzNWWI0Uc9xAmS/6G4DDyXvWocotXdc1HTf51fj9ApphjUfOEU2XLpKR7Fig98= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701885749; c=relaxed/simple; bh=7tXCrMSogkeM4G8wrdxRiEeVusEKiKx4knYeAsMHp0s=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=CkmZDxgyW+T3xa9IkqdOlanuVuglDruGULuO0vX2ivKbM0xxYpFYSBqXnq0zdZH0WGYENKP+rpzhfH71evDGyJmszBV5a3kR7dG/4kWd+6QKWMkgHRxBUFD0zfLzm3bpJYqWNC9wrbu9s42/MK66Q79MsSbhy+bI5W1B5WlOZvM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1701885742; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+wA7Dee8GF2WbRY4I2KiaGGW4dNqRgjQK87szII1A9Q=; b=G0k4qIcYmQ+g4s7r3pbp4HZ1ExVTf9uEzC4xE091hHjwvYX3KnZLXy6U2KzLjqxXPjl6qw 3GK8cJxM7hMG0OoQeNMlpNpjAE+SfMBWfTZNPpRMZsd9Hiwb9l/2DK3hB5S/0ocgdhnk4/ WZx02klbwMip+5y1OlcdHL4YHylXtiM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-640-NCHljLwIN8WIO2tpJvPEbQ-1; Wed, 06 Dec 2023 12:50:13 -0500 X-MC-Unique: NCHljLwIN8WIO2tpJvPEbQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B19CD890FC5 for ; Wed, 6 Dec 2023 17:50:12 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.33.182]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6DC1F3C2E; Wed, 6 Dec 2023 17:50:12 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] v2: diagnostics: prettify JSON output formats Date: Wed, 6 Dec 2023 12:50:11 -0500 Message-Id: <20231206175011.2462694-1-dmalcolm@redhat.com> In-Reply-To: <20231115005457.3748674-1-dmalcolm@redhat.com> References: <20231115005457.3748674-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org I messed up the testing of the previous version of this patch, and it turned out to have regressions. Whilst fixing them, it turned out I needed a way to disable the formatting for some test cases, so this version of the patch restricts the formatting to just the diagnostics format, and adds a -fno-diagnostics-json-formatting for turning it off. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r14-6228-g3bd8241a1f1982. For reference, here's what I've pushed: 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. --- gcc/analyzer/engine.cc | 2 +- gcc/common.opt | 4 + gcc/diagnostic-format-json.cc | 26 ++- gcc/diagnostic-format-sarif.cc | 37 ++-- gcc/diagnostic.cc | 17 +- gcc/diagnostic.h | 12 +- gcc/doc/invoke.texi | 22 ++- gcc/gcc.cc | 3 +- gcc/gcov.cc | 4 +- gcc/json.cc | 163 +++++++++++++----- gcc/json.h | 16 +- gcc/optinfo-emit-json.cc | 4 +- gcc/opts.cc | 3 +- .../c-c++-common/diagnostic-format-json-1.c | 42 ++--- .../c-c++-common/diagnostic-format-json-2.c | 48 +++--- .../c-c++-common/diagnostic-format-json-3.c | 48 +++--- .../c-c++-common/diagnostic-format-json-4.c | 93 ++++------ .../c-c++-common/diagnostic-format-json-5.c | 86 +++------ .../diagnostic-format-json-stderr-1.c | 42 ++--- gcc/testsuite/g++.dg/pr90462.C | 2 +- .../gcc.dg/analyzer/malloc-sarif-1.c | 2 +- .../gcc.dg/plugin/diagnostic-test-paths-3.c | 45 ++++- .../gfortran.dg/diagnostic-format-json-1.F90 | 45 ++--- .../gfortran.dg/diagnostic-format-json-2.F90 | 49 +++--- .../gfortran.dg/diagnostic-format-json-3.F90 | 49 +++--- 25 files changed, 470 insertions(+), 394 deletions(-) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 232636cde21..d2524e34f58 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -6073,7 +6073,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 161a035d736..cb82272e31d 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 418db74522d..c013192de06 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 941fd0f5f74..05b2c6df2e2 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 5854c89a387..b5b6a760ccf 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 4fc31438b16..80e53ec92b0 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 ee5002cc75d..166db887e83 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -305,6 +305,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 @@ -5719,8 +5720,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: @@ -5983,6 +5983,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 9f21ad9453e..c970c26e3db 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 8b4748d3a1a..6d4a7bde53a 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 d0f157f0dfe..90ddd7ab3b1 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 6fadd119ba5..862e5676a63 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 11cad42a433..b181d6fb15d 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 5d5efaf1b9e..7a3830caaa3 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 6bab30e3e6c..c95218c3cfe 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 3c12103c9f8..a8828b7b2df 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 11d74624ff1..178bbf94b5b 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 cec1cf924b4..899a03f0e5e 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 86f8c5fb374..ed3139c7f1b 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 bcfa92110f5..e798c6b21e1 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 2585ba0dcdb..b35e41921a6 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 3d798e687e6..19ac89f2b67 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 6971d7cb38b..a315d208cab 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 2993f7c852b..b8cd61cff23 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 1681462fa08..9ff1ef59b34 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 f0a67de76b0..750e186c8ac 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