aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2025-02-15 08:13:06 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2025-02-15 08:13:06 -0500
commita1f63ea36e9c9f2f66980dccc76d18cf781716a7 (patch)
treeb4e5696c96335986b2589a03bc0c36407c8d625f /gcc
parent9f1f4efc06f43b1ba8c1cf5a31d5b73d6a2bb12d (diff)
downloadgcc-a1f63ea36e9c9f2f66980dccc76d18cf781716a7.zip
gcc-a1f63ea36e9c9f2f66980dccc76d18cf781716a7.tar.gz
gcc-a1f63ea36e9c9f2f66980dccc76d18cf781716a7.tar.bz2
sarif-replay: display annotations as labelled ranges (§3.28.6) [PR118881]
In our .sarif output from e.g.: bad-binary-op.c: In function ‘test_4’: bad-binary-op.c:19:23: error: invalid operands to binary + (have ‘S’ {aka ‘struct s’} and ‘T’ {aka ‘struct t’}) 19 | return callee_4a () + callee_4b (); | ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~ | | | | | T {aka struct t} | S {aka struct s} the labelled ranges are captured in the 'annotations' property of the 'location' object (§3.28.6). However sarif-replay emits just: In function 'test_4': bad-binary-op.c:19:23: error: invalid operands to binary + (have ‘S’ {aka ‘struct s’} and ‘T’ {aka ‘struct t’}) [error] 19 | return callee_4a () + callee_4b (); | ^ missing the labelled ranges. This patch adds support to sarif-replay for the 'annotations' property; with this patch we emit: In function 'test_4': bad-binary-op.c:19:23: error: invalid operands to binary + (have ‘S’ {aka ‘struct s’} and ‘T’ {aka ‘struct t’}) [error] 19 | return callee_4a () + callee_4b (); | ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~ | | | | | T {aka struct t} | S {aka struct s} thus showing the labelled ranges. Doing so requires adding a new entrypoint to libgdiagnostics: diagnostic_physical_location_get_file Given that we haven't yet released a stable version and that sarif-replay is built together with libgdiagnostics I didn't bother updating the ABI version. gcc/ChangeLog: PR sarif-replay/118881 * doc/libgdiagnostics/topics/physical-locations.rst: Add diagnostic_physical_location_get_file. * libgdiagnostics++.h (physical_location::get_file): New wrapper. (diagnostic::add_location): Likewise. * libgdiagnostics.cc (diagnostic_manager::get_file_by_name): New. (diagnostic_physical_location::get_file): New. (diagnostic_physical_location_get_file): New. * libgdiagnostics.h (diagnostic_physical_location_get_file): New. * libgdiagnostics.map (diagnostic_physical_location_get_file): New. * libsarifreplay.cc (class annotation): New. (add_any_annotations): New. (sarif_replayer::handle_result_obj): Collect vectors of annotations in the calls to handle_location_object and apply them to "err" and to "note" as appropriate. (sarif_replayer::handle_thread_flow_location_object): Pass nullptr for annotations. (sarif_replayer::handle_location_object): Handle §3.28.6 "annotations" property, using it to populate a new "out_annotations" param. gcc/testsuite/ChangeLog: PR sarif-replay/118881 * sarif-replay.dg/2.1.0-valid/3.28.6-annotations-1.sarif: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/doc/libgdiagnostics/topics/physical-locations.rst5
-rw-r--r--gcc/libgdiagnostics++.h19
-rw-r--r--gcc/libgdiagnostics.cc33
-rw-r--r--gcc/libgdiagnostics.h6
-rw-r--r--gcc/libgdiagnostics.map2
-rw-r--r--gcc/libsarifreplay.cc94
-rw-r--r--gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.28.6-annotations-1.sarif47
7 files changed, 201 insertions, 5 deletions
diff --git a/gcc/doc/libgdiagnostics/topics/physical-locations.rst b/gcc/doc/libgdiagnostics/topics/physical-locations.rst
index fec4a8f..099e27e 100644
--- a/gcc/doc/libgdiagnostics/topics/physical-locations.rst
+++ b/gcc/doc/libgdiagnostics/topics/physical-locations.rst
@@ -198,6 +198,11 @@ are at the parentheses.
TODO: example of output
+.. function:: diagnostic_file *diagnostic_physical_location_get_file (const diagnostic_physical_location *physical_loc)
+
+ Get the :type:`diagnostic_file` associated with a given physical location.
+
+
Associating diagnostics with locations
**************************************
diff --git a/gcc/libgdiagnostics++.h b/gcc/libgdiagnostics++.h
index af75113..39477a0 100644
--- a/gcc/libgdiagnostics++.h
+++ b/gcc/libgdiagnostics++.h
@@ -93,6 +93,8 @@ public:
: m_inner (location)
{}
+ file get_file () const;
+
const diagnostic_physical_location *m_inner;
};
@@ -200,6 +202,9 @@ public:
set_location (physical_location loc);
void
+ add_location (physical_location loc);
+
+ void
add_location_with_label (physical_location loc,
const char *text);
@@ -372,6 +377,14 @@ file::set_buffered_content (const char *data, size_t sz)
diagnostic_file_set_buffered_content (m_inner, data, sz);
}
+// class physical_location
+
+inline file
+physical_location::get_file () const
+{
+ return file (diagnostic_physical_location_get_file (m_inner));
+}
+
// class execution_path
inline diagnostic_event_id
@@ -449,6 +462,12 @@ diagnostic::add_location_with_label (physical_location loc,
}
inline void
+diagnostic::add_location (physical_location loc)
+{
+ diagnostic_add_location (m_inner, loc.m_inner);
+}
+
+inline void
diagnostic::set_logical_location (logical_location loc)
{
diagnostic_set_logical_location (m_inner, loc.m_inner);
diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc
index 89a9b7f..d274283 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -147,6 +147,8 @@ struct diagnostic_physical_location
m_inner (inner)
{}
+ diagnostic_file *get_file () const;
+
diagnostic_manager *m_mgr;
location_t m_inner;
};
@@ -445,6 +447,14 @@ public:
return file;
}
+ diagnostic_file *
+ get_file_by_name (const char *name)
+ {
+ if (diagnostic_file **slot = m_str_to_file_map.get (name))
+ return *slot;
+ return nullptr;
+ }
+
const diagnostic_physical_location *
new_location_from_file_and_line (const diagnostic_file *file,
diagnostic_line_num_t line_num)
@@ -943,6 +953,18 @@ diagnostic_file::set_buffered_content (const char *buf, size_t sz)
fc.add_buffered_content (m_name.get_str (), buf, sz);
}
+// struct diagnostic_physical_location
+
+diagnostic_file *
+diagnostic_physical_location::get_file () const
+{
+ m_mgr->set_line_table_global ();
+ const char *filename = LOCATION_FILE (m_inner);
+ if (!filename)
+ return nullptr;
+ return m_mgr->get_file_by_name (filename);
+}
+
/* class impl_diagnostic_client_data_hooks. */
const client_version_info *
@@ -1753,3 +1775,14 @@ diagnostic_finish_va (diagnostic *diag, const char *gmsgid, va_list *args)
diag->get_manager ().emit (*diag, gmsgid, args);
delete diag;
}
+
+/* Public entrypoint. */
+
+diagnostic_file *
+diagnostic_physical_location_get_file (const diagnostic_physical_location *physical_loc)
+{
+ if (!physical_loc)
+ return nullptr;
+
+ return physical_loc->get_file ();
+}
diff --git a/gcc/libgdiagnostics.h b/gcc/libgdiagnostics.h
index f204147..2ce0f4c 100644
--- a/gcc/libgdiagnostics.h
+++ b/gcc/libgdiagnostics.h
@@ -686,6 +686,12 @@ diagnostic_finish_va (diagnostic *diag, const char *fmt, va_list *args)
LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
LIBGDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (2, 0);
+/* Get the diagnostic_file associated with PHYSICAL_LOC. */
+
+extern diagnostic_file *
+diagnostic_physical_location_get_file (const diagnostic_physical_location *physical_loc)
+ LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL(0);
+
/* DEFERRED:
- thread-safety
- plural forms
diff --git a/gcc/libgdiagnostics.map b/gcc/libgdiagnostics.map
index 995e684..5958cfe 100644
--- a/gcc/libgdiagnostics.map
+++ b/gcc/libgdiagnostics.map
@@ -69,5 +69,7 @@ LIBGDIAGNOSTICS_ABI_0
diagnostic_finish;
diagnostic_finish_va;
+ diagnostic_physical_location_get_file;
+
local: *;
};
diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index 71f8079..075dadb 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -199,6 +199,23 @@ struct string_property_value
ValueType m_value;
};
+/* A class for recording annotations seen in locations (§3.28.6) that
+ should be emitted as secondary locations on diagnostics. */
+
+class annotation
+{
+public:
+ annotation (libgdiagnostics::physical_location phys_loc,
+ label_text label)
+ : m_phys_loc (phys_loc),
+ m_label (std::move (label))
+ {
+ }
+
+ libgdiagnostics::physical_location m_phys_loc;
+ label_text m_label;
+};
+
class sarif_replayer
{
public:
@@ -287,7 +304,8 @@ private:
handle_location_object (const json::object &location_obj,
const json::object &run_obj,
libgdiagnostics::physical_location &out_physical_loc,
- libgdiagnostics::logical_location &out_logical_loc);
+ libgdiagnostics::logical_location &out_logical_loc,
+ std::vector<annotation> *out_annotations);
// "physicalLocation" object (§3.29)
enum status
@@ -962,6 +980,18 @@ sarif_replayer::get_level_from_level_str (const json::string &level_str)
level_values, ARRAY_SIZE (level_values));
}
+static void
+add_any_annotations (libgdiagnostics::diagnostic &diag,
+ const std::vector<annotation> &annotations)
+{
+ for (auto &annotation : annotations)
+ if (annotation.m_label.get ())
+ diag.add_location_with_label (annotation.m_phys_loc,
+ annotation.m_label.get ());
+ else
+ diag.add_location (annotation.m_phys_loc);
+}
+
/* Process a result object (SARIF v2.1.0 section 3.27).
Known limitations:
- doesn't yet handle "ruleIndex" property (§3.27.6)
@@ -1025,6 +1055,7 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
= get_required_property<json::array> (result_obj, locations_prop);
if (!locations_arr)
return status::err_invalid_sarif;
+ std::vector<annotation> annotations;
if (locations_arr->length () > 0)
{
/* Only look at the first, if there's more than one. */
@@ -1035,7 +1066,8 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
return status::err_invalid_sarif;
enum status s = handle_location_object (*location_obj, run_obj,
physical_loc,
- logical_loc);
+ logical_loc,
+ &annotations);
if (s != status::ok)
return s;
}
@@ -1092,6 +1124,7 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
}
err.set_location (physical_loc);
err.set_logical_location (logical_loc);
+ add_any_annotations (err, annotations);
if (path.m_inner)
err.take_execution_path (std::move (path));
err.finish ("%s", text.get ());
@@ -1112,9 +1145,11 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
prop_related_locations);
if (!location_obj)
return status::err_invalid_sarif;
+ std::vector<annotation> annotations;
enum status s = handle_location_object (*location_obj, run_obj,
physical_loc,
- logical_loc);
+ logical_loc,
+ &annotations);
if (s != status::ok)
return s;
@@ -1136,6 +1171,7 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
auto note (m_output_mgr.begin_diagnostic (DIAGNOSTIC_LEVEL_NOTE));
note.set_location (physical_loc);
note.set_logical_location (logical_loc);
+ add_any_annotations (note, annotations);
note.finish ("%s", text.get ());
}
}
@@ -1490,7 +1526,8 @@ handle_thread_flow_location_object (const json::object &tflow_loc_obj,
{
/* location object (§3.28). */
enum status s = handle_location_object (*location_obj, run_obj,
- physical_loc, logical_loc);
+ physical_loc, logical_loc,
+ nullptr);
if (s != status::ok)
return s;
@@ -1564,7 +1601,8 @@ sarif_replayer::
handle_location_object (const json::object &location_obj,
const json::object &run_obj,
libgdiagnostics::physical_location &out_physical_loc,
- libgdiagnostics::logical_location &out_logical_loc)
+ libgdiagnostics::logical_location &out_logical_loc,
+ std::vector<annotation> *out_annotations)
{
// §3.28.3 "physicalLocation" property
{
@@ -1604,6 +1642,52 @@ handle_location_object (const json::object &location_obj,
}
}
+ // §3.28.6 "annotations" property
+ {
+ const property_spec_ref annotations_prop
+ ("location", "annotations", "3.28.6");
+ if (const json::array *annotations_arr
+ = get_optional_property<json::array> (location_obj,
+ annotations_prop))
+ for (auto element : *annotations_arr)
+ {
+ const json::object *annotation_obj
+ = require_object_for_element (*element, annotations_prop);
+ if (!annotation_obj)
+ return status::err_invalid_sarif;
+ libgdiagnostics::file file = out_physical_loc.get_file ();
+ if (!file.m_inner)
+ return report_invalid_sarif
+ (*annotation_obj, annotations_prop,
+ "cannot find artifact for %qs property",
+ annotations_prop.get_property_name ());
+ libgdiagnostics::physical_location phys_loc;
+ enum status s = handle_region_object (*annotation_obj,
+ file,
+ phys_loc);
+ if (s != status::ok)
+ return s;
+
+ label_text label;
+
+ // §3.30.14 message property
+ {
+ const property_spec_ref message_prop
+ ("region", "message", "3.30.14");
+
+ if (const json::object *message_obj
+ = get_optional_property<json::object> (*annotation_obj,
+ message_prop))
+ label = make_plain_text_within_result_message (nullptr,
+ *message_obj,
+ nullptr);
+ }
+
+ if (out_annotations)
+ out_annotations->push_back ({phys_loc, std::move (label)});
+ }
+ }
+
return status::ok;
}
diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.28.6-annotations-1.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.28.6-annotations-1.sarif
new file mode 100644
index 0000000..4ff6e07
--- /dev/null
+++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/3.28.6-annotations-1.sarif
@@ -0,0 +1,47 @@
+{"$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": []}],
+ "artifacts": [{"location": {"uri": "bad-binary-ops-highlight-colors.c"},
+ "sourceLanguage": "c",
+ "contents": {"text": "/* Verify that colorization affects both text within diagnostic messages\n and underlined ranges of quoted source, and that the types we use\n match up between them.\n Also implicitly verify that -fdiagnostics-show-highlight-colors is\n on by default. */\n\n\n\nstruct s {};\nstruct t {};\ntypedef struct s S;\ntypedef struct t T;\n\nextern S callee_4a (void);\nextern T callee_4b (void);\n\nint test_4 (void)\n{\n return callee_4a () + callee_4b ();\n}\n"},
+ "roles": ["analysisTarget"]}],
+ "results": [{"ruleId": "error",
+ "level": "error",
+ "message": {"text": "invalid operands to binary + (have ‘S’ {{aka ‘struct s’}} and ‘T’ {{aka ‘struct t’}})"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "bad-binary-ops-highlight-colors.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 19,
+ "startColumn": 23,
+ "endColumn": 24},
+ "contextRegion": {"startLine": 19,
+ "snippet": {"text": " return callee_4a () + callee_4b ();\n"}}},
+ "logicalLocations": [{"name": "test_4",
+ "fullyQualifiedName": "test_4",
+ "decoratedName": "test_4",
+ "kind": "function"}],
+ "annotations": [{"startLine": 19,
+ "startColumn": 10,
+ "endColumn": 22,
+ "message": {"text": "S {{aka struct s}}"}},
+ {"startLine": 19,
+ "startColumn": 25,
+ "endColumn": 37,
+ "message": {"text": "T {{aka struct t}}"}}]}]}]}]}
+
+/* Verify that we underline and label the ranges for the
+ "annotations" above. */
+/* { dg-begin-multiline-output "" }
+bad-binary-ops-highlight-colors.c:19:23: error: invalid operands to binary + (have ‘S’ {aka ‘struct s’} and ‘T’ {aka ‘struct t’}) [error]
+ 19 | return callee_4a () + callee_4b ();
+ | ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | | |
+ | | T {aka struct t}
+ | S {aka struct s}
+ { dg-end-multiline-output "" } */
+// TODO: trailing [error]