From patchwork Wed Nov 15 00:54:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 165135 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:6358:a59:b0:164:83eb:24d7 with SMTP id 25csp2304899rwb; Tue, 14 Nov 2023 16:55:28 -0800 (PST) X-Google-Smtp-Source: AGHT+IFyfps/HosnZwso3CAesJ/uaVMeSX5RNYrxQaksSHvOE4bGx4LqQMBSngCcZi2j8+5mq734 X-Received: by 2002:a05:622a:406:b0:410:ab30:d568 with SMTP id n6-20020a05622a040600b00410ab30d568mr4698514qtx.68.1700009727900; Tue, 14 Nov 2023 16:55:27 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1700009727; cv=pass; d=google.com; s=arc-20160816; b=BK9WN+1Y/xVtAnE4X/WgE1J8w7T7sSMqYcIocXZStvFpH9LYFKEM2NcrCRuiMlKalc DmvyVPSupbqAQo416O2n0T4A7Z/LOv8OMWGn9i5wJSBGPjFCNrGRhQoJGOSAJYVJJ0D4 jpXLZ+ug2mRRf6C2XMWh5tiOtGDDqne5X2jp/0e0+EoK46r8jdOJxC2u3JnVXenDD+8R XIxKjAyu3FfPwKIJjvhPcIDfw/dfRSkyeCmS01zfR+M8tZGCuNbj93ZK40c16FpcVuNn xzv8J5qahqdiy8p8EG0UybBqjZDpQIU7NaJqHZUqV+1RsY6LJNU5GDlmFGg+tyQwr2wb QqVQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :arc-filter:dmarc-filter:delivered-to; bh=86LB7UIAOsu7wVTyFCZnZoHEsQqE2dbNt9ebof06rm4=; fh=NXemEfxTRbZtBxUkxR2ehQUaYlcDfMdzPkO8MChVQE4=; b=Rcx4lExjgv05wrH25B8mcwylVD36UDzb+65l4iEO2Zd0M3jWEJuG/M+KrcopscrAls PURm6ZrYVnWSHt9IzHeqIwkfAVrmXvVgFXOwjosu2KqYXlZ8yLaH9MNM1XiOmz+x1Fqx L7yYZLqqUQO3NNhB+1ZAbo8UTKexYGRzwSTkuGP6Fx+g3Q4Muzb1cyGgNs3pWae+bm8z Qt9uWOPTlK52p5OWCbKua7N58HlunhzoS2yENXonLk/a//ysTns52ZAu8THcK9T4Gt9u OY6HSHoXhgk07InKGwns3D0LahWlIUbOuXQVXkQ2nHc1vf9dAAss20nLzAGJd+H5/+DL HXdA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=WuCTKOtQ; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id x20-20020a05622a001400b0041e772aa6b4si7966335qtw.402.2023.11.14.16.55.27 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Nov 2023 16:55:27 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=WuCTKOtQ; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9B78F3858C2B for ; Wed, 15 Nov 2023 00:55:27 +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 4BEBA3858D32 for ; Wed, 15 Nov 2023 00:55:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4BEBA3858D32 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 4BEBA3858D32 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=1700009702; cv=none; b=jjBmEJ0Z6BUl2QF5Ufkl9gaWfVKgI23Ldf6/Gv5+8MxTBhdG24HwiVnLRA57lhZPZkOZVRaxyxp1vEJL+n8xQPMBm4woApPuZzPcg07oRmJfraxOOZL5VeQTBADK1XmuL8UvRxbzmW+0GjeNRLWoBPDUMb7sFSUGSHVVt3+RBcQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700009702; c=relaxed/simple; bh=6jiF0ARuorSZdecViwJzEbJlbhz9/zMPC4iqdSrIuwo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=Q3fm3v0VQ+Hr7KNvwJuTquCdXYdELzalk/38Ht6ZxaATmRWPUjmFCBMWUJBzQNhg3DNJd/h+cijQoNCdvuHPy+wR6R0C7VIJre6W6oF7jj52nOFWcaW//ndDY0Vtthtppb16mGIdro0tETNfK6h+FZkN4xcyS506Meyn6UkGwd8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700009700; 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; bh=86LB7UIAOsu7wVTyFCZnZoHEsQqE2dbNt9ebof06rm4=; b=WuCTKOtQ3hNkC/QJkxOjmMpxhg5M5hnnmSV1twxj8fx06nm+yevR0Sbq/wL6iGxerTQNAY 5+XRk8M6E6OcPxxAjX6owUC/yEb8X+sPFBCazZkfzBnNQZP3fcvIya0uEpSoUjxkcZjZaJ 6pLqAoXb6BHegO21mCWcx1Abl1B23r4= 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-306-jhhKg46zMuaFhcX-ZoNXUQ-1; Tue, 14 Nov 2023 19:54:58 -0500 X-MC-Unique: jhhKg46zMuaFhcX-ZoNXUQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (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 534E28007B3 for ; Wed, 15 Nov 2023 00:54:58 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.10.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 284DF2026D4C; Wed, 15 Nov 2023 00:54:58 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH/RFC] json.cc: format JSON output Date: Tue, 14 Nov 2023 19:54:57 -0500 Message-Id: <20231115005457.3748674-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.4 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+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1782589400189649943 X-GMAIL-MSGID: 1782589400189649943 Previously our JSON output emitted the JSON all on one line, with no indentation or newlines 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, and it seems to be a quality-of-life improvement for users. 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 considered adding params and an option to control this formatting, but it seems something you'd always want enabled; we already gzip some of our json output, so it seems unlikely to affect sizes. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Thoughts? gcc/ChangeLog: * doc/invoke.texi (-fdiagnostics-format=json): Remove discussion about JSON output needing formatting. * json.cc (object::print): Add whitespace to format the JSON output. (array::print): Likewise. (selftest::test_writing_objects): Update expected output. (selftest::test_writing_arrays): Likewise. (selftest::test_formatting): New. (selftest::json_cc_tests): Call it. * optinfo-emit-json.cc (selftest::test_building_json_from_dump_calls): Update search string to reflect indentation. --- gcc/doc/invoke.texi | 3 +- gcc/json.cc | 62 +++++++++++++++++++++++++++++++++++++--- gcc/optinfo-emit-json.cc | 3 +- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1748afdbfe0a..0c4d27bd0241 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5712,8 +5712,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: diff --git a/gcc/json.cc b/gcc/json.cc index d0f157f0dfe7..d5a38c773f4d 100644 --- a/gcc/json.cc +++ b/gcc/json.cc @@ -66,6 +66,7 @@ void object::print (pretty_printer *pp) const { pp_character (pp, '{'); + pp_indentation (pp) += 1; /* Iterate in the order that the keys were inserted. */ unsigned i; @@ -73,15 +74,23 @@ object::print (pretty_printer *pp) const FOR_EACH_VEC_ELT (m_keys, i, key) { if (i > 0) - pp_string (pp, ", "); + { + pp_string (pp, ","); + pp_newline (pp); + pp_indent (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, ": "); + const int indent = strlen (key) + 4; + pp_indentation (pp) += indent; value->print (pp); + pp_indentation (pp) -= indent; } + pp_indentation (pp) -= 1; pp_character (pp, '}'); } @@ -183,14 +192,20 @@ void array::print (pretty_printer *pp) const { pp_character (pp, '['); + pp_indentation (pp) += 1; unsigned i; value *v; FOR_EACH_VEC_ELT (m_elements, i, v) { if (i) - pp_string (pp, ", "); + { + pp_string (pp, ","); + pp_newline (pp); + pp_indent (pp); + } v->print (pp); } + pp_indentation (pp) -= 1; pp_character (pp, ']'); } @@ -354,7 +369,9 @@ 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, + "{\"foo\": \"bar\",\n" + " \"baz\": \"quux\"}"); } /* Verify that JSON arrays are written correctly. */ @@ -369,7 +386,9 @@ test_writing_arrays () ASSERT_PRINT_EQ (arr, "[\"foo\"]"); arr.append (new json::string ("bar")); - ASSERT_PRINT_EQ (arr, "[\"foo\", \"bar\"]"); + ASSERT_PRINT_EQ (arr, + "[\"foo\",\n" + " \"bar\"]"); } /* Verify that JSON numbers are written correctly. */ @@ -424,6 +443,40 @@ test_writing_literals () ASSERT_PRINT_EQ (literal (false), "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, + ("{\"str\": \"bar\",\n" + " \"child\": {\"grandchild\": {\"arr\": [0,\n" + " 1,\n" + " 2],\n" + " \"int\": 1066},\n" + " \"int\": 1776},\n" + " \"int\": 42}")); +} + /* Run all of the selftests within this file. */ void @@ -436,6 +489,7 @@ json_cc_tests () test_writing_integer_numbers (); test_writing_strings (); test_writing_literals (); + test_formatting (); } } // namespace selftest diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc index 11cad42a4330..1f8cb9b04e8e 100644 --- a/gcc/optinfo-emit-json.cc +++ b/gcc/optinfo-emit-json.cc @@ -471,7 +471,8 @@ test_building_json_from_dump_calls () ASSERT_STR_CONTAINS (json_str, "impl_location"); ASSERT_STR_CONTAINS (json_str, "\"kind\": \"note\""); ASSERT_STR_CONTAINS (json_str, - "\"message\": [\"test of tree: \", {\"expr\": \"0\"}]"); + " \"message\": [\"test of tree: \",\n" + " {\"expr\": \"0\"}]"); delete json_obj; }