Given the .sarif output from e.g.:

  too-many-arguments.c: In function 'test_known_fn':
  too-many-arguments.c:14:3: error: too many arguments to function 'fn_a'; 
expected 0, have 1
     14 |   fn_a (42);
        |   ^~~~  ~~
  too-many-arguments.c:8:13: note: declared here
      8 | extern void fn_a ();
        |             ^~~~

the underlining of the stray argument (the "42") is captured in
'relatedLocations' (§3.27.22) but previously sarif-replay would not
display this:

  In function 'test_known_fn':
  too-many-arguments.c:14:3: error: too many arguments to function 'fn_a'; 
expected 0, have 1 [error]
     14 |   fn_a (42);
        |   ^~~~
  too-many-arguments.c:8:13: note: declared here
      8 | extern void fn_a ();
        |             ^~~~

With this patch sarif-replay handles the relatedLocations element as
a secondary location in libgdiagnostics, and correctly underlines
the "42":

  In function 'test_known_fn':
  too-many-arguments.c:14:3: error: too many arguments to function 'fn_a'; 
expected 0, have 1 [error]
     14 |   fn_a (42);
        |   ^~~~  ~~
  too-many-arguments.c:8:13: note: declared here
      8 | extern void fn_a ();
        |             ^~~~

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r15-7562-g79c311d42f846f.

gcc/ChangeLog:
        * libsarifreplay.cc (sarif_replayer::handle_result_obj): Treat any
        relatedLocations without messages as secondary ranges within the
        diagnostic.  Doing so requires stashing the notes until after
        the diagnostic has been finished, so that relatedLocations can be
        walked in one pass.

gcc/testsuite/ChangeLog:
        * sarif-replay.dg/2.1.0-valid/unlabelled-secondary-locations.sarif:
        New test.

Signed-off-by: David Malcolm <dmalc...@redhat.com>
---
 gcc/libsarifreplay.cc                         | 22 ++++++-
 .../unlabelled-secondary-locations.sarif      | 60 +++++++++++++++++++
 2 files changed, 79 insertions(+), 3 deletions(-)
 create mode 100644 
gcc/testsuite/sarif-replay.dg/2.1.0-valid/unlabelled-secondary-locations.sarif

diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index 075dadba41f..e2d09088a4a 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -998,7 +998,6 @@ add_any_annotations (libgdiagnostics::diagnostic &diag,
    - doesn't yet handle "taxa" property (§3.27.8)
    - handling of "level" property (§3.27.10) doesn't yet support the
      full logic for when "level" is absent.
-   - doesn't yet handle "relatedLocations" property (§3.27.22)
    - doesn't yet handle "fixes" property (§3.27.30)
    - doesn't yet support multithreaded flows (§3.36.3)
 */
@@ -1127,9 +1126,9 @@ sarif_replayer::handle_result_obj (const json::object 
&result_obj,
   add_any_annotations (err, annotations);
   if (path.m_inner)
     err.take_execution_path (std::move (path));
-  err.finish ("%s", text.get ());
 
   // §3.27.22 relatedLocations property
+  std::vector<std::pair<libgdiagnostics::diagnostic, label_text>> notes;
   const property_spec_ref prop_related_locations
     ("result", "relatedLocations", "3.27.22");
   if (auto related_locations_arr
@@ -1172,11 +1171,28 @@ sarif_replayer::handle_result_obj (const json::object 
&result_obj,
              note.set_location (physical_loc);
              note.set_logical_location (logical_loc);
              add_any_annotations (note, annotations);
-             note.finish ("%s", text.get ());
+             notes.push_back ({std::move (note), std::move (text)});
+           }
+         else
+           {
+             /* Treat related locations without a message as a secondary
+                range.  */
+             if (physical_loc.m_inner)
+               err.add_location (physical_loc);
            }
        }
     }
 
+  err.finish ("%s", text.get ());
+
+  // Flush any notes
+  for (auto &iter : notes)
+    {
+      auto &note = iter.first;
+      auto &text = iter.second;
+      note.finish ("%s", text.get ());
+    }
+
   return status::ok;
 
 }
diff --git 
a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/unlabelled-secondary-locations.sarif
 
b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/unlabelled-secondary-locations.sarif
new file mode 100644
index 00000000000..251e2fd2e78
--- /dev/null
+++ 
b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/unlabelled-secondary-locations.sarif
@@ -0,0 +1,60 @@
+{"$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": "GNU C23",
+                               "fullName": "GNU C23 (GCC) version 15.0.1 
20250203 (experimental) (x86_64-pc-linux-gnu)",
+                               "version": "15.0.1 20250203 (experimental)",
+                               "informationUri": "https://gcc.gnu.org/gcc-15/";,
+                               "rules": []}},
+           "invocations": [{"executionSuccessful": false,
+                            "toolExecutionNotifications": []}],
+           "originalUriBaseIds": {"PWD": {"uri": "file:///nonexistent/"}},
+           "artifacts": [{"location": {"uri": "too-many-arguments.c",
+                                       "uriBaseId": "PWD"},
+                          "sourceLanguage": "c",
+                          "contents": {"text": "extern void fn_a ();\n\nvoid 
test_known_fn (void)\n{\n  fn_a (42);\n}\n"},
+                          "roles": ["analysisTarget"]}],
+           "results": [{"ruleId": "error",
+                        "level": "error",
+                        "message": {"text": "too many arguments to function 
'fn_a'; expected 0, have 1"},
+                        "locations": [{"physicalLocation": 
{"artifactLocation": {"uri": "too-many-arguments.c",
+                                                                               
  "uriBaseId": "PWD"},
+                                                            "region": 
{"startLine": 5,
+                                                                       
"startColumn": 3,
+                                                                       
"endColumn": 7},
+                                                            "contextRegion": 
{"startLine": 5,
+                                                                              
"snippet": {"text": "  fn_a (42);\n"}}},
+                                       "logicalLocations": [{"name": 
"test_known_fn",
+                                                             
"fullyQualifiedName": "test_known_fn",
+                                                             "decoratedName": 
"test_known_fn",
+                                                             "kind": 
"function"}],
+                                       "relationships": [{"target": 0,
+                                                          "kinds": 
["relevant"]}]}],
+                        "relatedLocations": [{"physicalLocation": 
{"artifactLocation": {"uri": "too-many-arguments.c",
+                                                                               
         "uriBaseId": "PWD"},
+                                                                   "region": 
{"startLine": 1,
+                                                                              
"startColumn": 13,
+                                                                              
"endColumn": 17},
+                                                                   
"contextRegion": {"startLine": 1,
+                                                                               
      "snippet": {"text": "extern void fn_a ();\n"}}},
+                                              "message": {"text": "declared 
here"},
+                                              "properties": {"nestingLevel": 
0}},
+                                             {"physicalLocation": 
{"artifactLocation": {"uri": "too-many-arguments.c",
+                                                                               
         "uriBaseId": "PWD"},
+                                                                   "region": 
{"startLine": 5,
+                                                                              
"startColumn": 9,
+                                                                              
"endColumn": 11},
+                                                                   
"contextRegion": {"startLine": 5,
+                                                                               
      "snippet": {"text": "  fn_a (42);\n"}}},
+                                              "id": 0}]}]}]}
+
+/* Verify that we underline the "42" here.  */
+/* { dg-begin-multiline-output "" }
+In function 'test_known_fn':
+too-many-arguments.c:5:3: error: too many arguments to function 'fn_a'; 
expected 0, have 1 [error]
+    5 |   fn_a (42);
+      |   ^~~~  ~~
+too-many-arguments.c:1:13: note: declared here
+    1 | extern void fn_a ();
+      |             ^~~~
+   { dg-end-multiline-output "" } */
+// TODO: trailing [error]
-- 
2.26.3

Reply via email to