Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Successful run of analyzer integration tests on x86_64-pc-linux-gnu. Checked selftests under valgrind on x86_64-pc-linux-gnu.
Pushed to trunk as r15-7255-gb4bd06774ced72. gcc/ChangeLog: PR other/118675 * diagnostic-format-sarif.cc: Define INCLUDE_STRING. (escape_braces): New. (set_string_property_escaping_braces): New. (sarif_builder::make_message_object): Escape braces in the "text" property. (sarif_builder::make_message_object_for_diagram): Likewise, and for the "markdown" property. (sarif_builder::make_multiformat_message_string): Likewise for the "text" property. (xelftest::test_message_with_braces): New. (selftest::diagnostic_format_sarif_cc_tests): Call it. gcc/testsuite/ChangeLog: PR other/118675 * gcc.dg/sarif-output/bad-binary-op.py: Update expected output for escaping of braces in message text. * gcc.dg/sarif-output/missing-semicolon.py: Likewise. * gcc.dg/sarif-output/multiple-outputs.py: Likewise. Signed-off-by: David Malcolm <dmalc...@redhat.com> --- gcc/diagnostic-format-sarif.cc | 68 +++++++++++++++++-- .../gcc.dg/sarif-output/bad-binary-op.py | 6 +- .../gcc.dg/sarif-output/missing-semicolon.py | 2 +- .../gcc.dg/sarif-output/multiple-outputs.py | 2 +- 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 168a52fddf5b..554992bddba1 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #define INCLUDE_LIST #define INCLUDE_MAP +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" @@ -2821,6 +2822,38 @@ sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const return kinds_arr; } +/* In "3.11.5 Messages with placeholders": + "Within both plain text and formatted message strings, the characters + "{" and "}" SHALL be represented by the character sequences + "{{" and "}}" respectively." */ + +static std::string +escape_braces (const char *text) +{ + std::string result; + while (char ch = *text++) + switch (ch) + { + case '{': + case '}': + result += ch; + /* Fall through. */ + default: + result += ch; + break; + } + return result; +} + +static void +set_string_property_escaping_braces (json::object &obj, + const char *property_name, + const char *value) +{ + std::string escaped (escape_braces (value)); + obj.set_string (property_name, escaped.c_str ()); +} + /* Make a "message" object (SARIF v2.1.0 section 3.11) for MSG. */ std::unique_ptr<sarif_message> @@ -2829,7 +2862,8 @@ sarif_builder::make_message_object (const char *msg) const auto message_obj = ::make_unique<sarif_message> (); /* "text" property (SARIF v2.1.0 section 3.11.8). */ - message_obj->set_string ("text", msg); + set_string_property_escaping_braces (*message_obj, + "text", msg); return message_obj; } @@ -2844,7 +2878,8 @@ sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagra auto message_obj = ::make_unique<sarif_message> (); /* "text" property (SARIF v2.1.0 section 3.11.8). */ - message_obj->set_string ("text", diagram.get_alt_text ()); + set_string_property_escaping_braces (*message_obj, + "text", diagram.get_alt_text ()); pretty_printer *const pp = m_printer; char *saved_prefix = pp_take_prefix (pp); @@ -2857,7 +2892,8 @@ sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagra pp_set_prefix (pp, saved_prefix); /* "markdown" property (SARIF v2.1.0 section 3.11.9). */ - message_obj->set_string ("markdown", pp_formatted_text (pp)); + set_string_property_escaping_braces (*message_obj, + "markdown", pp_formatted_text (pp)); pp_clear_output_area (pp); @@ -2873,7 +2909,8 @@ sarif_builder::make_multiformat_message_string (const char *msg) const auto message_obj = ::make_unique<sarif_multiformat_message_string> (); /* "text" property (SARIF v2.1.0 section 3.12.3). */ - message_obj->set_string ("text", msg); + set_string_property_escaping_braces (*message_obj, + "text", msg); return message_obj; } @@ -4341,6 +4378,28 @@ test_message_with_embedded_link (enum sarif_version version) } } +/* Verify that braces in messages get escaped, as per + 3.11.5 ("Messages with placeholders"). */ + +static void +test_message_with_braces (enum sarif_version version) +{ + auto_fix_quotes fix_quotes; + { + test_sarif_diagnostic_context dc ("test.c", version); + rich_location richloc (line_table, UNKNOWN_LOCATION); + dc.report (DK_ERROR, richloc, nullptr, 0, + "open brace: %qs close brace: %qs", + "{", "}"); + std::unique_ptr<sarif_log> log = dc.flush_to_object (); + + auto message_obj = get_message_from_log (log.get ()); + ASSERT_JSON_STRING_PROPERTY_EQ + (message_obj, "text", + "open brace: `{{' close brace: `}}'"); + } +} + static void test_buffering (enum sarif_version version) { @@ -4457,6 +4516,7 @@ diagnostic_format_sarif_cc_tests () test_simple_log (version); test_message_with_embedded_link (version); + test_message_with_braces (version); test_buffering (version); } diff --git a/gcc/testsuite/gcc.dg/sarif-output/bad-binary-op.py b/gcc/testsuite/gcc.dg/sarif-output/bad-binary-op.py index fe139e62e417..2281c06a6c94 100644 --- a/gcc/testsuite/gcc.dg/sarif-output/bad-binary-op.py +++ b/gcc/testsuite/gcc.dg/sarif-output/bad-binary-op.py @@ -45,7 +45,7 @@ def test_error_location(sarif): assert result['level'] == 'error' assert result['message']['text'] \ - == "invalid operands to binary + (have 'S' {aka 'struct s'} and 'T' {aka 'struct t'})" + == "invalid operands to binary + (have 'S' {{aka 'struct s'}} and 'T' {{aka 'struct t'}})" locations = result['locations'] assert len(locations) == 1 @@ -63,8 +63,8 @@ def test_error_location(sarif): assert annotations[0]['startLine'] == EXPECTED_LINE assert annotations[0]['startColumn'] == 10 assert annotations[0]['endColumn'] == 22 - assert annotations[0]['message']['text'] == "S {aka struct s}" + assert annotations[0]['message']['text'] == "S {{aka struct s}}" assert annotations[1]['startLine'] == EXPECTED_LINE assert annotations[1]['startColumn'] == 25 assert annotations[1]['endColumn'] == 37 - assert annotations[1]['message']['text'] == "T {aka struct t}" + assert annotations[1]['message']['text'] == "T {{aka struct t}}" diff --git a/gcc/testsuite/gcc.dg/sarif-output/missing-semicolon.py b/gcc/testsuite/gcc.dg/sarif-output/missing-semicolon.py index 58c0a7d02cd8..a0f848387a22 100644 --- a/gcc/testsuite/gcc.dg/sarif-output/missing-semicolon.py +++ b/gcc/testsuite/gcc.dg/sarif-output/missing-semicolon.py @@ -43,7 +43,7 @@ def test_location_relationships(sarif): result = results[0] assert result['level'] == 'error' - assert result['message']['text'] == "expected ';' before '}' token" + assert result['message']['text'] == "expected ';' before '}}' token" locations = result['locations'] assert len(locations) == 1 diff --git a/gcc/testsuite/gcc.dg/sarif-output/multiple-outputs.py b/gcc/testsuite/gcc.dg/sarif-output/multiple-outputs.py index 8febfac4c7bf..4de91c2c8ef2 100644 --- a/gcc/testsuite/gcc.dg/sarif-output/multiple-outputs.py +++ b/gcc/testsuite/gcc.dg/sarif-output/multiple-outputs.py @@ -36,7 +36,7 @@ def test_result(sarif): result = results[0] assert result['level'] == 'error' - assert result['message']['text'] == "expected ';' before '}' token" + assert result['message']['text'] == "expected ';' before '}}' token" locations = result['locations'] assert len(locations) == 1 -- 2.26.3