]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
sarif-replay: handle embedded links (§3.11.6)
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 16 Dec 2024 16:22:50 +0000 (11:22 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Mon, 16 Dec 2024 16:22:50 +0000 (11:22 -0500)
Handle embedded links in plain text messages.  For now, merely
use the link text and discard the destination.

gcc/ChangeLog:
* libsarifreplay.cc (struct embedded_link): New.
(maybe_consume_embedded_link): New.
(sarif_replayer::make_plain_text_within_result_message): Handle
embedded links by using the link text, for now.

gcc/testsuite/ChangeLog:
* sarif-replay.dg/2.1.0-valid/3.11.6-embedded-links.sarif: New test.
* sarif-replay.dg/2.1.0-valid/malloc-vs-local-4.c.sarif: Update
expected output for handling the embedded links.
* sarif-replay.dg/2.1.0-valid/spec-example-4.sarif: Likewise.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/libsarifreplay.cc
gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.11.6-embedded-links.sarif [new file with mode: 0644]
gcc/testsuite/sarif-replay.dg/2.1.0-valid/malloc-vs-local-4.c.sarif
gcc/testsuite/sarif-replay.dg/2.1.0-valid/spec-example-4.sarif

index f1374ec4fc80fad37127630d4d4e83e7d457ecf5..074ea90f352ba173045773cf0a2d0fa680cb1268 100644 (file)
@@ -1176,11 +1176,91 @@ maybe_consume_placeholder (const char *&iter_src, unsigned *out_arg_idx)
   return false;
 }
 
+struct embedded_link
+{
+  std::string text;
+  std::string destination;
+};
+
+/*  If ITER_SRC starts with an embedded link as per §3.11.6, advance ITER_SRC
+    to immediately beyond the link, and return the link.
+
+    Otherwise, leave ITER_SRC untouched and return nullptr.  */
+
+static std::unique_ptr<embedded_link>
+maybe_consume_embedded_link (const char *&iter_src)
+{
+  if (*iter_src != '[')
+    return nullptr;
+
+  /* This *might* be an embedded link.
+     See §3.11.6 ("Messages with embedded links") and
+     https://github.com/oasis-tcs/sarif-spec/issues/657 */
+
+  /* embedded link = "[", link text, "](", link destination, ")"; */
+
+  embedded_link result;
+
+  /* Try to get the link text.  */
+  const char *iter = iter_src + 1;
+  while (char ch = *(iter++))
+    {
+      if (ch == '\\')
+       {
+         char next_ch = *iter;
+         switch (next_ch)
+           {
+           case '\\':
+           case '[':
+           case ']':
+             /* escaped link character = "\" | "[" | "]";  */
+             result.text += next_ch;
+             iter++;
+             continue;
+
+           default:
+             /* Malformed link text; assume this is not an
+                embedded link.  */
+             return nullptr;
+           }
+       }
+      else if (ch == ']')
+       /* End of link text.  */
+       break;
+      else
+       result.text += ch;
+    }
+
+  if (*iter++ != '(')
+    return nullptr;
+
+  /* Try to get the link destination.  */
+  while (1)
+    {
+      char ch = *(iter++);
+      if (ch == '\0')
+       {
+         /* String ended before terminating ')'.
+            Assume this is not an embedded link.  */
+         return nullptr;
+       }
+      else if (ch == ')')
+       /* Terminator.  */
+       break;
+      else
+       result.destination += ch;
+    }
+
+  iter_src = iter;
+  return ::make_unique<embedded_link> (std::move (result));
+}
+
 /* Lookup the plain text string within a result.message (§3.27.11),
-   and substitute for any placeholders (§3.11.5).
+   and substitute for any placeholders (§3.11.5) and handle any
+   embedded links (§3.11.6).
 
    Limitations:
-   - we don't yet support embedded links
+   - we don't preserve destinations within embedded links
 
    MESSAGE_OBJ is "theMessage"
    RULE_OBJ is "theRule".  */
@@ -1255,6 +1335,13 @@ make_plain_text_within_result_message (const json::object *tool_component_obj,
              return label_text::borrow (nullptr);
            }
        }
+      else if (auto link = maybe_consume_embedded_link (iter_src))
+       {
+         accum += link->text;
+         /* TODO: use the destination.  */
+         /* TODO: potentially could try to convert
+            intra-sarif links into event ids.  */
+       }
       else
        {
          accum += ch;
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.11.6-embedded-links.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.11.6-embedded-links.sarif
new file mode 100644 (file)
index 0000000..bc64521
--- /dev/null
@@ -0,0 +1,25 @@
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "hand-written"}},
+           "results": [{"message": {"text": "001: this is a test"},
+                       "locations": []},
+/* { dg-begin-multiline-output "" }
+hand-written: warning: 001: this is a test
+   { dg-end-multiline-output "" } */
+
+                       /* Without the fix from https://github.com/oasis-tcs/sarif-spec/issues/656 */
+                       {"message": {"text": "002: Prohibited term used in [para\\[0\\]\\\\spans\\[2\\](1)."},
+                       "locations": []},
+/* { dg-begin-multiline-output "" }
+hand-written: warning: 002: Prohibited term used in [para\[0\]\\spans\[2\](1).
+   { dg-end-multiline-output "" } */
+                       
+                       /* With the fix from https://github.com/oasis-tcs/sarif-spec/issues/656 */
+                       {"message": {"text": "003: Prohibited term used in [para\\[0\\]\\\\spans\\[2\\]](1)."},
+                       "locations": []}
+/* { dg-begin-multiline-output "" }
+hand-written: warning: 003: Prohibited term used in para[0]\spans[2].
+   { dg-end-multiline-output "" } */
+
+]}]}
+
index 5fd8e628b47dee79e53c7e56c86b2db07cdd237b..55c646bb5ad2f3419ceebb2e3bf86054131309df 100644 (file)
                                                                        "nestingLevel": 1,
                                                                        "executionOrder": 5}]}]}]}]}]}
 // TODO: show the CWEs
-// TODO: fix URL in message
 
 /* { dg-begin-multiline-output "" }
 In function 'callee_1':
@@ -372,7 +371,7 @@ In function 'callee_1':
            |    5 |   *ptr = 42;
            |      |   ~~~~~~~~~~                    
            |      |   |
-           |      |   (7) ‘ptr’ could be NULL: unchecked value from [(4)](sarif:/runs/0/results/0/codeFlows/0/threadFlows/0/locations/3)
+           |      |   (7) ‘ptr’ could be NULL: unchecked value from (4)
            |
    { dg-end-multiline-output "" } */
 /* { dg-begin-multiline-output "" }
@@ -398,5 +397,5 @@ In function 'test_2':
    38 |       free (ptr);
       |       ~~~~~~~~~~~
       |       |
-      |       (5) second ‘free’ here; first ‘free’ was at [(4)](sarif:/runs/0/results/1/codeFlows/0/threadFlows/0/locations/3)
+      |       (5) second ‘free’ here; first ‘free’ was at (4)
    { dg-end-multiline-output "" } */
index 60c87314e1c84a6659cb226277c5bf66e520d0eb..27a0767bd0ef20e1397f9b2c104c5bd101059d70 100644 (file)
 
 /* { dg-begin-multiline-output "" }
 In function 'collections::list::add':
-collections/list.h:15:9: error: Variable "ptr" was used without being initialized. It was declared [here](0). [C2001]
+collections/list.h:15:9: error: Variable "ptr" was used without being initialized. It was declared here. [C2001]
   events 1-3
 ......
    { dg-end-multiline-output "" } */