diff options
Diffstat (limited to 'gcc/diagnostic-format-sarif.cc')
-rw-r--r-- | gcc/diagnostic-format-sarif.cc | 303 |
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); |