From patchwork Thu Jun 2 19:45:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1638436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=s1e9JY+9; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from 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 RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LDc3R2YR8z9s0w for ; Fri, 3 Jun 2022 05:46:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3F6E4396E411 for ; Thu, 2 Jun 2022 19:46:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F6E4396E411 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1654199216; bh=hM0PsVP8D4cJ212qxaRTgm1fedEUHEMqgrrNl8iy+bY=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=s1e9JY+9ImcLqyS3IbaAbLMEsLF2BHBYz/8cCGZ4EU+Y+ZMuzPEhY4OcA6e84KH6X ktPxs3k0zVqxwJYl6DGGrZ5TVACmeMzMhFaPi5aatzCNRFk/VYTcwvakVUs4W98q7A g8r4rjV4B+Be0rq0SuWv7h9MwdXVBSzo2RoLLHGQ= 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 6A054396D836 for ; Thu, 2 Jun 2022 19:45:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6A054396D836 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-442-bjEA4ehCNhmQ9KzSp1QlnQ-1; Thu, 02 Jun 2022 15:45:23 -0400 X-MC-Unique: bjEA4ehCNhmQ9KzSp1QlnQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BB0E9858EFE for ; Thu, 2 Jun 2022 19:45:22 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.16.187]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8EF401415100; Thu, 2 Jun 2022 19:45:22 +0000 (UTC) To: gcc-patches@gcc.gnu.org Subject: [committed] Add -fdiagnostics-format={json-stderr|json-file} Date: Thu, 2 Jun 2022 15:45:21 -0400 Message-Id: <20220602194521.843639-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.7 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This commit adds -fdiagnostics-format=json-file, writing to DUMP_BASE_NAME.gcc.json, and adds -fdiagnostics-format=json-stderr, a synonym for the existing -fdiagnostics-format=json. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r13-966-g5ab73173cca461. gcc/ChangeLog: * common.opt (fdiagnostics-format=): Add json-stderr and json-file to description. (DIAGNOSTICS_OUTPUT_FORMAT_JSON): Rename to... (DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR): ...this. (diagnostics_output_format): Add json-stderr and json-file. * diagnostic-format-json.cc (json_flush_to_file): New. (json_final_cb): Convert to... (json_flush_to_file): ...this, ... (json_stderr_final_cb): ...this, and... (json_file_final_cb): ...this. (diagnostic_output_format_init): Move to diagnostic.cc. (json_output_base_file_name): New. (diagnostic_output_format_init_json): New. (diagnostic_output_format_init_json_stderr): New. (diagnostic_output_format_init_json_file): New. * diagnostic.cc (diagnostic_output_format_init): Move here from diagnostic-format-json.cc; update for changes to enum. * diagnostic.h (enum diagnostics_output_format): Rename DIAGNOSTICS_OUTPUT_FORMAT_JSON to DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, and add DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE. (diagnostic_output_format_init): Add base_file_name param. (diagnostic_output_format_init_json_stderr): New decl. (diagnostic_output_format_init_json_file): New dec. * doc/invoke.texi (-fdiagnostics-format=): Add "json-stderr" and "json-file". Rewrite so that the existing "json" is a synonym of "json-stderr". * gcc.cc (driver_handle_option): Pass dump_base_name to diagnostic_output_format_init. * opts.cc (common_handle_option): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/diagnostic-format-json-file-1.c: New test. * c-c++-common/diagnostic-format-json-stderr-1.c: New test. Signed-off-by: David Malcolm --- gcc/common.opt | 10 +- gcc/diagnostic-format-json.cc | 116 ++++++++++++------ gcc/diagnostic.cc | 26 ++++ gcc/diagnostic.h | 11 +- gcc/doc/invoke.texi | 17 ++- gcc/gcc.cc | 2 +- gcc/opts.cc | 2 +- .../diagnostic-format-json-file-1.c | 8 ++ .../diagnostic-format-json-stderr-1.c | 33 +++++ 9 files changed, 173 insertions(+), 52 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c create mode 100644 gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c diff --git a/gcc/common.opt b/gcc/common.opt index 8a0dafc522d..3237ce9b530 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1390,7 +1390,7 @@ Common Joined RejectNegative UInteger fdiagnostics-format= Common Joined RejectNegative Enum(diagnostics_output_format) --fdiagnostics-format=[text|json] Select output format. +-fdiagnostics-format=[text|json|json-stderr|json-file] Select output format. fdiagnostics-escape-format= Common Joined RejectNegative Enum(diagnostics_escape_format) @@ -1425,7 +1425,13 @@ EnumValue Enum(diagnostics_output_format) String(text) Value(DIAGNOSTICS_OUTPUT_FORMAT_TEXT) EnumValue -Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON) +Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR) + +EnumValue +Enum(diagnostics_output_format) String(json-stderr) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR) + +EnumValue +Enum(diagnostics_output_format) String(json-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE) fdiagnostics-parseable-fixits Common Var(flag_diagnostics_parseable_fixits) diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 62594ebb4d7..051fa6c2e48 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -285,57 +285,93 @@ json_end_group (diagnostic_context *) cur_children_array = NULL; } -/* Callback for final cleanup for JSON output. */ +/* Flush the top-level array to OUTF. */ static void -json_final_cb (diagnostic_context *) +json_flush_to_file (FILE *outf) { - /* Flush the top-level array. */ - toplevel_array->dump (stderr); - fprintf (stderr, "\n"); + toplevel_array->dump (outf); + fprintf (outf, "\n"); delete toplevel_array; toplevel_array = NULL; } -/* Set the output format for CONTEXT to FORMAT. */ +/* Callback for final cleanup for JSON output to stderr. */ -void -diagnostic_output_format_init (diagnostic_context *context, - enum diagnostics_output_format format) +static void +json_stderr_final_cb (diagnostic_context *) +{ + json_flush_to_file (stderr); +} + +static char *json_output_base_file_name; + +/* Callback for final cleanup for JSON output to a file. */ + +static void +json_file_final_cb (diagnostic_context *) { - switch (format) + char *filename = concat (json_output_base_file_name, ".gcc.json", NULL); + FILE *outf = fopen (filename, "w"); + if (!outf) { - default: - gcc_unreachable (); - case DIAGNOSTICS_OUTPUT_FORMAT_TEXT: - /* The default; do nothing. */ - break; - - case DIAGNOSTICS_OUTPUT_FORMAT_JSON: - { - /* Set up top-level JSON array. */ - if (toplevel_array == NULL) - toplevel_array = new json::array (); - - /* Override callbacks. */ - context->begin_diagnostic = json_begin_diagnostic; - context->end_diagnostic = json_end_diagnostic; - context->begin_group_cb = json_begin_group; - context->end_group_cb = json_end_group; - context->final_cb = json_final_cb; - context->print_path = NULL; /* handled in json_end_diagnostic. */ - - /* The metadata is handled in JSON format, rather than as text. */ - context->show_cwe = false; - - /* The option is handled in JSON format, rather than as text. */ - context->show_option_requested = false; - - /* Don't colorize the text. */ - pp_show_color (context->printer) = false; - } - break; + const char *errstr = xstrerror (errno); + fnotice (stderr, "error: unable to open '%s' for writing: %s\n", + filename, errstr); + free (filename); + return; } + json_flush_to_file (outf); + fclose (outf); + free (filename); +} + +/* Populate CONTEXT in preparation for JSON output (either to stderr, or + to a file). */ + +static void +diagnostic_output_format_init_json (diagnostic_context *context) +{ + /* Set up top-level JSON array. */ + if (toplevel_array == NULL) + toplevel_array = new json::array (); + + /* Override callbacks. */ + context->begin_diagnostic = json_begin_diagnostic; + context->end_diagnostic = json_end_diagnostic; + context->begin_group_cb = json_begin_group; + context->end_group_cb = json_end_group; + context->print_path = NULL; /* handled in json_end_diagnostic. */ + + /* The metadata is handled in JSON format, rather than as text. */ + context->show_cwe = false; + + /* The option is handled in JSON format, rather than as text. */ + context->show_option_requested = false; + + /* Don't colorize the text. */ + pp_show_color (context->printer) = false; +} + +/* Populate CONTEXT in preparation for JSON output to stderr. */ + +void +diagnostic_output_format_init_json_stderr (diagnostic_context *context) +{ + diagnostic_output_format_init_json (context); + context->final_cb = json_stderr_final_cb; +} + +/* Populate CONTEXT in preparation for JSON output to a file named + BASE_FILE_NAME.gcc.json. */ + +void +diagnostic_output_format_init_json_file (diagnostic_context *context, + const char *base_file_name) +{ + diagnostic_output_format_init_json (context); + context->final_cb = json_file_final_cb; + json_output_base_file_name = xstrdup (base_file_name); } #if CHECKING_P diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index fef11467b6f..25504834484 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -2072,6 +2072,32 @@ auto_diagnostic_group::~auto_diagnostic_group () } } +/* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for + file-based output formats. */ + +void +diagnostic_output_format_init (diagnostic_context *context, + const char *base_file_name, + enum diagnostics_output_format format) +{ + switch (format) + { + default: + gcc_unreachable (); + case DIAGNOSTICS_OUTPUT_FORMAT_TEXT: + /* The default; do nothing. */ + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR: + diagnostic_output_format_init_json_stderr (context); + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE: + diagnostic_output_format_init_json_file (context, base_file_name); + break; + } +} + /* Implementation of diagnostic_path::num_events vfunc for simple_diagnostic_path: simply get the number of events in the vec. */ diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 3ca32979dde..dd3af033ae4 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -59,8 +59,11 @@ enum diagnostics_output_format /* The default: textual output. */ DIAGNOSTICS_OUTPUT_FORMAT_TEXT, - /* JSON-based output. */ - DIAGNOSTICS_OUTPUT_FORMAT_JSON + /* JSON-based output, to stderr. */ + DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, + + /* JSON-based output, to a file. */ + DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE }; /* An enum for controlling how diagnostic_paths should be printed. */ @@ -577,7 +580,11 @@ extern char *file_name_as_prefix (diagnostic_context *, const char *); extern char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; extern void diagnostic_output_format_init (diagnostic_context *, + const char *base_file_name, enum diagnostics_output_format); +extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context); +extern void diagnostic_output_format_init_json_file (diagnostic_context *context, + const char *base_file_name); /* Compute the number of digits in the decimal representation of an integer. */ extern int num_digits (int); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 71098d86313..d85b66f60f0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -301,7 +301,7 @@ Objective-C and Objective-C++ Dialects}. -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]} @gol -fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]} @gol --fdiagnostics-format=@r{[}text@r{|}json@r{]} @gol +-fdiagnostics-format=@r{[}text@r{|}json@r{|}json-stderr@r{|}json-file@r{]} @gol -fno-diagnostics-show-option -fno-diagnostics-show-caret @gol -fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol -fno-diagnostics-show-cwe @gol @@ -5305,14 +5305,19 @@ Unicode characters. For the example above, the following will be printed: @item -fdiagnostics-format=@var{FORMAT} @opindex fdiagnostics-format Select a different format for printing diagnostics. -@var{FORMAT} is @samp{text} or @samp{json}. +@var{FORMAT} is @samp{text}, @samp{json}, @samp{json-stderr}, +or @samp{json-file}. + The default is @samp{text}. -The @samp{json} format consists of a top-level JSON array containing JSON -objects representing the diagnostics. +The @samp{json} format is a synonym for @samp{json-stderr}. +The @samp{json-stderr} and @samp{json-file} formats are identical, apart from +where the JSON is emitted to - with the former, the JSON is emitted to stderr, +whereas with @samp{json-file} it is written to @file{@var{source}.gcc.json}. -The JSON is emitted as one line, without formatting; the examples below -have been formatted for clarity. +The emitted JSON consists of a top-level JSON array containing JSON objects +representing the diagnostics. The JSON is emitted as one line, without +formatting; the examples below have been formatted for clarity. Diagnostics can have child diagnostics. For example, this error and note: diff --git a/gcc/gcc.cc b/gcc/gcc.cc index 299e09c4f54..563f535d564 100644 --- a/gcc/gcc.cc +++ b/gcc/gcc.cc @@ -4335,7 +4335,7 @@ driver_handle_option (struct gcc_options *opts, break; case OPT_fdiagnostics_format_: - diagnostic_output_format_init (dc, + diagnostic_output_format_init (dc, opts->x_dump_base_name, (enum diagnostics_output_format)value); break; diff --git a/gcc/opts.cc b/gcc/opts.cc index f0c5c4db955..bf06a55456a 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -2800,7 +2800,7 @@ common_handle_option (struct gcc_options *opts, break; case OPT_fdiagnostics_format_: - diagnostic_output_format_init (dc, + diagnostic_output_format_init (dc, opts->x_dump_base_name, (enum diagnostics_output_format)value); break; diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c new file mode 100644 index 00000000000..ddac780f07b --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c @@ -0,0 +1,8 @@ +/* Check that -fdiagnostics-format=json-file works. */ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=json-file" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { scan-file "diagnostic-format-json-file-1.c.gcc.json" "\"message\": \"#warning message\"" } } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c new file mode 100644 index 00000000000..02f780bce10 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c @@ -0,0 +1,33 @@ +/* Check that "json" and "json-stderr" are synonymous when used as + arguments to "-fdiagnostics-format=". */ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=json-stderr" } */ + +#error message + +/* Use dg-regexp to consume the JSON output starting with + the innermost values, and working outwards. + We can't rely on any ordering of the keys. */ + +/* { dg-regexp "\"kind\": \"error\"" } */ +/* { dg-regexp "\"column-origin\": 1" } */ +/* { dg-regexp "\"escape-source\": false" } */ +/* { dg-regexp "\"message\": \"#error message\"" } */ + +/* { dg-regexp "\"caret\": \{" } */ +/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */ +/* { dg-regexp "\"line\": 6" } */ +/* { dg-regexp "\"column\": 2" } */ +/* { dg-regexp "\"display-column\": 2" } */ +/* { dg-regexp "\"byte-column\": 2" } */ + +/* { dg-regexp "\"finish\": \{" } */ +/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */ +/* { dg-regexp "\"line\": 6" } */ +/* { dg-regexp "\"column\": 6" } */ +/* { dg-regexp "\"display-column\": 6" } */ +/* { dg-regexp "\"byte-column\": 6" } */ + +/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */ +/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */ +/* { dg-regexp "\[\[\{\}, \]*\]" } */