aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostic-format-sarif.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostic-format-sarif.cc')
-rw-r--r--gcc/diagnostic-format-sarif.cc303
1 files changed, 277 insertions, 26 deletions
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index bc6abdf..454eaae 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -51,6 +51,52 @@ along with GCC; see the file COPYING3. If not see
#include "demangle.h"
#include "backtrace.h"
+/* A json::array where the values are "unique" as per
+ SARIF v2.1.0 section 3.7.3 ("Array properties with unique values"). */
+
+template <typename JsonElementType>
+class sarif_array_of_unique : public json::array
+{
+ public:
+ size_t append_uniquely (std::unique_ptr<JsonElementType> val)
+ {
+ /* This should be O(log(n)) due to the std::map. */
+ auto search = m_index_by_value.find (val.get ());
+ if (search != m_index_by_value.end())
+ return (*search).second;
+
+ const size_t insertion_idx = size ();
+ m_index_by_value.insert ({val.get (), insertion_idx});
+ append (std::move (val));
+ return insertion_idx;
+ }
+
+ /* For ease of reading output, add "index": idx to all
+ objects in the array.
+ We don't do this until we've added everything, since
+ the "index" property would otherwise confuse the
+ comparison against new elements. */
+ void add_explicit_index_values ()
+ {
+ for (size_t idx = 0; idx < length (); ++idx)
+ if (json::object *obj = get (idx)->dyn_cast_object ())
+ obj->set_integer ("index", idx);
+ }
+
+private:
+ struct comparator_t {
+ bool operator () (const json::value *a, const json::value *b) const
+ {
+ gcc_assert (a);
+ gcc_assert (b);
+ return json::value::compare (*a, *b) < 0;
+ }
+ };
+
+ // json::value * here is borrowed from m_elements
+ std::map<json::value *, int, comparator_t> m_index_by_value;
+};
+
/* Forward decls. */
class sarif_builder;
class content_renderer;
@@ -446,6 +492,13 @@ class sarif_physical_location : public sarif_object {};
class sarif_region : public sarif_object {};
+/* Subclass of sarif_object for SARIF "logicalLocation" objects
+ (SARIF v2.1.0 section 3.33). */
+
+class sarif_logical_location : public sarif_object
+{
+};
+
/* Subclass of sarif_object for SARIF "locationRelationship" objects
(SARIF v2.1.0 section 3.34). */
@@ -708,6 +761,12 @@ public:
m_printer = &printer;
}
+ const logical_location_manager *
+ get_logical_location_manager () const
+ {
+ return m_logical_loc_mgr;
+ }
+
void on_report_diagnostic (const diagnostic_info &diagnostic,
diagnostic_t orig_diag_kind,
diagnostic_sarif_format_buffer *buffer);
@@ -729,7 +788,7 @@ public:
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
const rich_location &rich_loc,
- const logical_location *logical_loc,
+ logical_location logical_loc,
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
@@ -766,6 +825,9 @@ public:
const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; }
+ std::unique_ptr<sarif_logical_location>
+ make_minimal_sarif_logical_location (logical_location);
+
private:
class sarif_token_printer : public token_printer
{
@@ -790,7 +852,7 @@ private:
location_t where);
void
set_any_logical_locs_arr (sarif_location &location_obj,
- const logical_location *logical_loc);
+ logical_location logical_loc);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
const diagnostic_event &event,
@@ -823,6 +885,10 @@ private:
const content_renderer *snippet_renderer) const;
std::unique_ptr<sarif_region>
make_region_object_for_hint (const fixit_hint &hint) const;
+
+ int
+ ensure_sarif_logical_location_for (logical_location k);
+
std::unique_ptr<sarif_multiformat_message_string>
make_multiformat_message_string (const char *msg) const;
std::unique_ptr<sarif_log>
@@ -879,6 +945,8 @@ private:
const line_maps *m_line_maps;
sarif_token_printer m_token_printer;
+ const logical_location_manager *m_logical_loc_mgr;
+
/* The JSON object for the invocation object. */
std::unique_ptr<sarif_invocation> m_invocation_obj;
@@ -901,6 +969,8 @@ private:
/* The set of all CWE IDs we've seen, if any. */
hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
+ std::unique_ptr<sarif_array_of_unique<sarif_logical_location>> m_cached_logical_locs;
+
int m_tabstop;
std::unique_ptr<sarif_serialization_format> m_serialization_format;
@@ -1232,7 +1302,8 @@ sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
sometimes these will related to current_function_decl, but
often they won't. */
auto location_obj
- = builder.make_location_object (*this, *diagnostic.richloc, nullptr,
+ = builder.make_location_object (*this, *diagnostic.richloc,
+ logical_location (),
diagnostic_artifact_role::result_file);
auto message_obj
= builder.make_message_object (pp_formatted_text (builder.get_printer ()));
@@ -1579,6 +1650,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_printer (&printer),
m_line_maps (line_maps),
m_token_printer (*this),
+ m_logical_loc_mgr (nullptr),
m_invocation_obj
(std::make_unique<sarif_invocation> (*this,
context.get_original_argv ())),
@@ -1587,6 +1659,8 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_seen_any_relative_paths (false),
m_rule_id_set (),
m_rules_arr (new json::array ()),
+ m_cached_logical_locs
+ (std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
m_tabstop (context.m_tabstop),
m_serialization_format (std::move (serialization_format)),
m_sarif_gen_opts (sarif_gen_opts),
@@ -1596,6 +1670,9 @@ sarif_builder::sarif_builder (diagnostic_context &context,
gcc_assert (m_line_maps);
gcc_assert (m_serialization_format);
+ if (auto client_data_hooks = context.get_client_data_hooks ())
+ m_logical_loc_mgr = client_data_hooks->get_logical_location_manager ();
+
/* Mark MAIN_INPUT_FILENAME_ as the artifact that the tool was
instructed to scan.
Only quote the contents if it gets referenced by physical locations,
@@ -2089,7 +2166,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
enum diagnostic_artifact_role role)
{
auto locations_arr = std::make_unique<json::array> ();
- const logical_location *logical_loc = nullptr;
+ logical_location logical_loc;
if (auto client_data_hooks = m_context.get_client_data_hooks ())
logical_loc = client_data_hooks->get_current_logical_location ();
@@ -2103,18 +2180,24 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
}
/* If LOGICAL_LOC is non-null, use it to create a "logicalLocations" property
- within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
+ within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4) with a minimal logical
+ location object referencing theRuns.logicalLocations (3.33.3). */
void
sarif_builder::
set_any_logical_locs_arr (sarif_location &location_obj,
- const logical_location *logical_loc)
+ logical_location logical_loc)
{
if (!logical_loc)
return;
+ gcc_assert (m_logical_loc_mgr);
auto location_locs_arr = std::make_unique<json::array> ();
+
+ auto logical_loc_obj = make_minimal_sarif_logical_location (logical_loc);
+
location_locs_arr->append<sarif_logical_location>
- (make_sarif_logical_location_object (*logical_loc));
+ (std::move (logical_loc_obj));
+
location_obj.set<json::array> ("logicalLocations",
std::move (location_locs_arr));
}
@@ -2127,7 +2210,7 @@ set_any_logical_locs_arr (sarif_location &location_obj,
std::unique_ptr<sarif_location>
sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
const rich_location &rich_loc,
- const logical_location *logical_loc,
+ logical_location logical_loc,
enum diagnostic_artifact_role role)
{
class escape_nonascii_renderer : public content_renderer
@@ -2321,7 +2404,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
std::move (phs_loc_obj));
/* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
- const logical_location *logical_loc = event.get_logical_location ();
+ logical_location logical_loc = event.get_logical_location ();
set_any_logical_locs_arr (*location_obj, logical_loc);
/* "message" property (SARIF v2.1.0 section 3.28.5). */
@@ -2651,6 +2734,7 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
case LOGICAL_LOCATION_KIND_UNKNOWN:
return nullptr;
+ /* Kinds within executable code. */
case LOGICAL_LOCATION_KIND_FUNCTION:
return "function";
case LOGICAL_LOCATION_KIND_MEMBER:
@@ -2667,35 +2751,120 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
return "parameter";
case LOGICAL_LOCATION_KIND_VARIABLE:
return "variable";
+
+ /* Kinds within XML or HTML documents. */
+ case LOGICAL_LOCATION_KIND_ELEMENT:
+ return "element";
+ case LOGICAL_LOCATION_KIND_ATTRIBUTE:
+ return "attribute";
+ case LOGICAL_LOCATION_KIND_TEXT:
+ return "text";
+ case LOGICAL_LOCATION_KIND_COMMENT:
+ return "comment";
+ case LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION:
+ return "processingInstruction";
+ case LOGICAL_LOCATION_KIND_DTD:
+ return "dtd";
+ case LOGICAL_LOCATION_KIND_DECLARATION:
+ return "declaration";
+
+ /* Kinds within JSON documents. */
+ case LOGICAL_LOCATION_KIND_OBJECT:
+ return "object";
+ case LOGICAL_LOCATION_KIND_ARRAY:
+ return "array";
+ case LOGICAL_LOCATION_KIND_PROPERTY:
+ return "property";
+ case LOGICAL_LOCATION_KIND_VALUE:
+ return "value";
}
}
-/* Make a "logicalLocation" object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
- or return nullptr. */
+/* Set PROPERTY_NAME within this bag to a "logicalLocation" object (SARIF v2.1.0
+ section 3.33) for LOGICAL_LOC. The object has an "index" property to refer to
+ theRuns.logicalLocations (3.33.3). */
-std::unique_ptr<sarif_logical_location>
-make_sarif_logical_location_object (const logical_location &logical_loc)
+void
+sarif_property_bag::set_logical_location (const char *property_name,
+ sarif_builder &builder,
+ logical_location logical_loc)
{
- auto logical_loc_obj = std::make_unique<sarif_logical_location> ();
+ set<sarif_logical_location>
+ (property_name,
+ builder.make_minimal_sarif_logical_location (logical_loc));
+}
- /* "name" property (SARIF v2.1.0 section 3.33.4). */
- if (const char *short_name = logical_loc.get_short_name ())
- logical_loc_obj->set_string ("name", short_name);
+/* Ensure that m_cached_logical_locs has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for K, and return its index within the
+ array. */
+
+int
+sarif_builder::
+ensure_sarif_logical_location_for (logical_location k)
+{
+ gcc_assert (m_logical_loc_mgr);
+
+ auto sarif_logical_loc = std::make_unique<sarif_logical_location> ();
+
+ if (const char *short_name = m_logical_loc_mgr->get_short_name (k))
+ sarif_logical_loc->set_string ("name", short_name);
/* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
- if (const char *name_with_scope = logical_loc.get_name_with_scope ())
- logical_loc_obj->set_string ("fullyQualifiedName", name_with_scope);
+ if (const char *name_with_scope = m_logical_loc_mgr->get_name_with_scope (k))
+ sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
/* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
- if (const char *internal_name = logical_loc.get_internal_name ())
- logical_loc_obj->set_string ("decoratedName", internal_name);
+ if (const char *internal_name = m_logical_loc_mgr->get_internal_name (k))
+ sarif_logical_loc->set_string ("decoratedName", internal_name);
/* "kind" property (SARIF v2.1.0 section 3.33.7). */
- enum logical_location_kind kind = logical_loc.get_kind ();
+ enum logical_location_kind kind = m_logical_loc_mgr->get_kind (k);
if (const char *sarif_kind_str = maybe_get_sarif_kind (kind))
- logical_loc_obj->set_string ("kind", sarif_kind_str);
+ sarif_logical_loc->set_string ("kind", sarif_kind_str);
+
+ /* "parentIndex" property (SARIF v2.1.0 section 3.33.8). */
+ if (auto parent_key = m_logical_loc_mgr->get_parent (k))
+ {
+ /* Recurse upwards. */
+ int parent_index = ensure_sarif_logical_location_for (parent_key);
+ sarif_logical_loc->set_integer ("parentIndex", parent_index);
+ }
+
+ /* Consolidate if this logical location already exists. */
+ int index
+ = m_cached_logical_locs->append_uniquely (std::move (sarif_logical_loc));
- return logical_loc_obj;
+ return index;
+}
+
+/* Ensure that theRuns.logicalLocations (3.14.17) has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for LOGICAL_LOC.
+ Create and return a minimal logicalLocation object referring to the
+ full object by index. */
+
+std::unique_ptr<sarif_logical_location>
+sarif_builder::
+make_minimal_sarif_logical_location (logical_location logical_loc)
+{
+ gcc_assert (m_logical_loc_mgr);
+
+ /* Ensure that m_cached_logical_locs has a "logicalLocation" object
+ (SARIF v2.1.0 section 3.33) for LOGICAL_LOC, and return its index within
+ the array. */
+
+ auto sarif_logical_loc = std::make_unique <sarif_logical_location> ();
+
+ int index = ensure_sarif_logical_location_for (logical_loc);
+
+ // 3.33.3 index property
+ sarif_logical_loc->set_integer ("index", index);
+
+ /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
+ if (const char *name_with_scope
+ = m_logical_loc_mgr->get_name_with_scope (logical_loc))
+ sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
+
+ return sarif_logical_loc;
}
label_text
@@ -2784,7 +2953,7 @@ populate_thread_flow_location_object (sarif_result &result,
{
/* Give diagnostic_event subclasses a chance to add custom properties
via a property bag. */
- ev.maybe_add_sarif_properties (tfl_obj);
+ ev.maybe_add_sarif_properties (*this, tfl_obj);
/* "location" property (SARIF v2.1.0 section 3.38.3). */
tfl_obj.set<sarif_location>
@@ -3038,6 +3207,14 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
/* "results" property (SARIF v2.1.0 section 3.14.23). */
run_obj->set<json::array> ("results", std::move (results));
+ /* "logicalLocations" property (SARIF v2.1.0 3.14.17). */
+ if (m_cached_logical_locs->size () > 0)
+ {
+ m_cached_logical_locs->add_explicit_index_values ();
+ run_obj->set<json::array> ("logicalLocations",
+ std::move (m_cached_logical_locs));
+ }
+
return run_obj;
}
@@ -3924,6 +4101,76 @@ sarif_generation_options::sarif_generation_options ()
namespace selftest {
+static void
+test_sarif_array_of_unique_1 ()
+{
+ sarif_array_of_unique<json::string> arr;
+
+ ASSERT_EQ (arr.length (), 0);
+
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+ }
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+
+ /* Try adding them again, should be idempotent. */
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 2);
+ }
+ {
+ size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+}
+
+static void
+test_sarif_array_of_unique_2 ()
+{
+ sarif_array_of_unique<json::object> arr;
+
+ ASSERT_EQ (arr.length (), 0);
+
+ {
+ auto obj0 = std::make_unique<json::object> ();
+ size_t idx = arr.append_uniquely (std::move (obj0));
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+
+ // Attempting to add another empty objects should be idempotent.
+ idx = arr.append_uniquely (std::make_unique<json::object> ());
+ ASSERT_EQ (idx, 0);
+ ASSERT_EQ (arr.length (), 1);
+ }
+ {
+ auto obj1 = std::make_unique<json::object> ();
+ obj1->set_string ("foo", "bar");
+ size_t idx = arr.append_uniquely (std::move (obj1));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+
+ // Attempting to add an equivalent object should be idempotent.
+ auto other = std::make_unique<json::object> ();
+ other->set_string ("foo", "bar");
+ idx = arr.append_uniquely (std::move (other));
+ ASSERT_EQ (idx, 1);
+ ASSERT_EQ (arr.length (), 2);
+ }
+
+ // Verify behavior of add_explicit_index_values.
+ arr.add_explicit_index_values ();
+ ASSERT_JSON_INT_PROPERTY_EQ (arr[0], "index", 0);
+ ASSERT_JSON_INT_PROPERTY_EQ (arr[1], "index", 1);
+}
+
/* A subclass of sarif_output_format for writing selftests.
The JSON output is cached internally, rather than written
out to a file. */
@@ -4029,7 +4276,8 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts,
std::unique_ptr<sarif_location> location_obj
= builder.make_location_object
- (result, richloc, nullptr, diagnostic_artifact_role::analysis_target);
+ (result, richloc, logical_location (),
+ diagnostic_artifact_role::analysis_target);
ASSERT_NE (location_obj, nullptr);
auto physical_location
@@ -4588,6 +4836,9 @@ run_line_table_case_tests_per_version (const line_table_case &case_)
void
diagnostic_format_sarif_cc_tests ()
{
+ test_sarif_array_of_unique_1 ();
+ test_sarif_array_of_unique_2 ();
+
for_each_sarif_gen_option (test_simple_log);
for_each_sarif_gen_option (test_message_with_embedded_link);
for_each_sarif_gen_option (test_message_with_braces);