diff options
Diffstat (limited to 'gcc/diagnostic-format-sarif.cc')
-rw-r--r-- | gcc/diagnostic-format-sarif.cc | 649 |
1 files changed, 555 insertions, 94 deletions
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index bc6abdf..d20ca86 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -28,6 +28,8 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "diagnostic.h" #include "diagnostic-metadata.h" +#include "diagnostic-digraphs.h" +#include "diagnostic-state-graphs.h" #include "diagnostic-path.h" #include "diagnostic-format.h" #include "diagnostic-buffer.h" @@ -50,6 +52,53 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print-urlifier.h" #include "demangle.h" #include "backtrace.h" +#include "xml.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; @@ -446,6 +495,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). */ @@ -698,7 +754,6 @@ public: sarif_builder (diagnostic_context &context, pretty_printer &printer, const line_maps *line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization_format, const sarif_generation_options &sarif_gen_opts); ~sarif_builder (); @@ -708,12 +763,24 @@ public: m_printer = &printer; } + const logical_location_manager * + get_logical_location_manager () const + { + return m_logical_loc_mgr; + } + + void + set_main_input_filename (const char *name); + void on_report_diagnostic (const diagnostic_info &diagnostic, diagnostic_t orig_diag_kind, diagnostic_sarif_format_buffer *buffer); void emit_diagram (const diagnostic_diagram &diagram); void end_group (); + void + report_global_digraph (const diagnostics::digraphs::lazy_digraph &); + std::unique_ptr<sarif_result> take_current_result () { return std::move (m_cur_group_result); @@ -727,9 +794,9 @@ public: const diagnostic_info &diagnostic, enum diagnostic_artifact_role role); std::unique_ptr<sarif_location> - make_location_object (sarif_location_manager &loc_mgr, + 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 +833,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 +860,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 +893,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 +953,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 +977,10 @@ 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; + + std::unique_ptr<sarif_array_of_unique<sarif_graph>> m_run_graphs; + int m_tabstop; std::unique_ptr<sarif_serialization_format> m_serialization_format; @@ -1232,7 +1312,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 ())); @@ -1572,13 +1653,13 @@ sarif_thread_flow::add_location () sarif_builder::sarif_builder (diagnostic_context &context, pretty_printer &printer, const line_maps *line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization_format, const sarif_generation_options &sarif_gen_opts) : m_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 +1668,10 @@ 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_run_graphs + (std::make_unique<sarif_array_of_unique<sarif_graph>> ()), m_tabstop (context.m_tabstop), m_serialization_format (std::move (serialization_format)), m_sarif_gen_opts (sarif_gen_opts), @@ -1596,16 +1681,8 @@ sarif_builder::sarif_builder (diagnostic_context &context, gcc_assert (m_line_maps); gcc_assert (m_serialization_format); - /* 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, - since otherwise the "no diagnostics" case would quote the main input - file, and doing so noticeably bloated the output seen in analyzer - integration testing (build directory went from 20G -> 21G). */ - if (main_input_filename_) - get_or_create_artifact (main_input_filename_, - diagnostic_artifact_role::analysis_target, - false); + if (auto client_data_hooks = context.get_client_data_hooks ()) + m_logical_loc_mgr = client_data_hooks->get_logical_location_manager (); } sarif_builder::~sarif_builder () @@ -1654,12 +1731,12 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, /* If we don't have any useful information, don't print anything. */ - if (filename == NULL && function == NULL) + if (filename == nullptr && function == nullptr) return 0; /* Skip functions in diagnostic.cc or diagnostic-global-context.cc. */ if (closure->m_frames_arr->size () == 0 - && filename != NULL + && filename != nullptr && (strcmp (lbasename (filename), "diagnostic.cc") == 0 || strcmp (lbasename (filename), "diagnostic-global-context.cc") == 0)) @@ -1673,13 +1750,13 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, return 1; } - char *alc = NULL; - if (function != NULL) + char *alc = nullptr; + if (function != nullptr) { char *str = cplus_demangle_v3 (function, (DMGL_VERBOSE | DMGL_ANSI | DMGL_GNU_V3 | DMGL_PARAMS)); - if (str != NULL) + if (str != nullptr) { alc = str; function = str; @@ -1691,7 +1768,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, if (strncmp (function, bt_stop[i], len) == 0 && (function[len] == '\0' || function[len] == '(')) { - if (alc != NULL) + if (alc != nullptr) free (alc); /* Returning a non-zero value stops the backtrace. */ return 1; @@ -1713,7 +1790,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, frame_obj->set_integer ("lineno", lineno); closure->m_frames_arr->append (std::move (frame_obj)); - if (alc != NULL) + if (alc != nullptr) free (alc); return 0; @@ -1743,6 +1820,20 @@ sarif_builder::make_stack_from_backtrace () return stack; } +void +sarif_builder::set_main_input_filename (const char *name) +{ + /* Mark NAME as the artifact that the tool was instructed to scan. + Only quote the contents if it gets referenced by physical locations, + since otherwise the "no diagnostics" case would quote the main input + file, and doing so noticeably bloated the output seen in analyzer + integration testing (build directory went from 20G -> 21G). */ + if (name) + get_or_create_artifact (name, + diagnostic_artifact_role::analysis_target, + false); +} + /* Implementation of "on_report_diagnostic" for SARIF output. */ void @@ -1813,6 +1904,17 @@ sarif_builder::end_group () } } +void +sarif_builder:: +report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg) +{ + auto &dg = ldg.get_or_create_digraph (); + + /* Presumably the location manager must be nullptr; see + https://github.com/oasis-tcs/sarif-spec/issues/712 */ + m_run_graphs->append (make_sarif_graph (dg, this, nullptr)); +} + /* Create a top-level object, and add it to all the results (and other entities) we've seen so far, moving ownership to the object. */ @@ -1967,6 +2069,19 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic, result_obj->set<json::array> ("codeFlows", std::move (code_flows_arr)); } + // "graphs" property (SARIF v2.1.0 section 3.27.19). */ + if (diagnostic.metadata) + if (auto ldg = diagnostic.metadata->get_lazy_digraphs ()) + { + auto &digraphs = ldg->get_or_create_digraphs (); + auto graphs_arr = std::make_unique<json::array> (); + for (auto &iter : digraphs) + graphs_arr->append (make_sarif_graph (*iter, this, + result_obj.get ())); + if (graphs_arr->size () > 0) + result_obj->set<json::array> ("graphs", std::move (graphs_arr)); + } + /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is set up later, if any nested diagnostics occur within this diagnostic group. */ @@ -2089,12 +2204,12 @@ 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 (); auto location_obj - = make_location_object (loc_mgr, *diagnostic.richloc, logical_loc, role); + = make_location_object (&loc_mgr, *diagnostic.richloc, logical_loc, role); /* Don't add entirely empty location objects to the array. */ if (!location_obj->is_empty ()) locations_arr->append<sarif_location> (std::move (location_obj)); @@ -2103,18 +2218,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)); } @@ -2122,12 +2243,14 @@ set_any_logical_locs_arr (sarif_location &location_obj, /* Make a "location" object (SARIF v2.1.0 section 3.28) for RICH_LOC and LOGICAL_LOC. Use LOC_MGR for any locations that need "id" values, and for - any worklist items. */ + any worklist items. + Note that we might not always have a LOC_MGR; see + https://github.com/oasis-tcs/sarif-spec/issues/712 */ std::unique_ptr<sarif_location> -sarif_builder::make_location_object (sarif_location_manager &loc_mgr, +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 @@ -2221,8 +2344,8 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, /* Add related locations for any secondary locations in RICH_LOC that don't have labels (and thus aren't added to "annotations"). */ - if (i > 0 && !handled) - loc_mgr.add_relationship_to_worklist + if (loc_mgr && i > 0 && !handled) + loc_mgr->add_relationship_to_worklist (*location_obj.get (), sarif_location_manager::worklist_item::kind::unlabelled_secondary_location, range->m_loc); @@ -2233,7 +2356,8 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr, std::move (annotations_arr)); } - add_any_include_chain (loc_mgr, *location_obj.get (), loc); + if (loc_mgr) + add_any_include_chain (*loc_mgr, *location_obj.get (), loc); /* A flag for hinting that the diagnostic involves issues at the level of character encodings (such as homoglyphs, or misleading @@ -2321,7 +2445,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). */ @@ -2648,54 +2772,276 @@ maybe_get_sarif_kind (enum logical_location_kind kind) { default: gcc_unreachable (); - case LOGICAL_LOCATION_KIND_UNKNOWN: + case logical_location_kind::unknown: return nullptr; - case LOGICAL_LOCATION_KIND_FUNCTION: + /* Kinds within executable code. */ + case logical_location_kind::function: return "function"; - case LOGICAL_LOCATION_KIND_MEMBER: + case logical_location_kind::member: return "member"; - case LOGICAL_LOCATION_KIND_MODULE: + case logical_location_kind::module_: return "module"; - case LOGICAL_LOCATION_KIND_NAMESPACE: + case logical_location_kind::namespace_: return "namespace"; - case LOGICAL_LOCATION_KIND_TYPE: + case logical_location_kind::type: return "type"; - case LOGICAL_LOCATION_KIND_RETURN_TYPE: + case logical_location_kind::return_type: return "returnType"; - case LOGICAL_LOCATION_KIND_PARAMETER: + case logical_location_kind::parameter: return "parameter"; - case LOGICAL_LOCATION_KIND_VARIABLE: + 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)); +} + +static void +copy_any_property_bag (const diagnostics::digraphs::object &input_obj, + sarif_object &output_obj) +{ + if (input_obj.get_property_bag ()) + { + const json::object &old_bag = *input_obj.get_property_bag (); + sarif_property_bag &new_bag = output_obj.get_or_create_properties (); + for (size_t i = 0; i < old_bag.get_num_keys (); ++i) + { + const char *key = old_bag.get_key (i); + json::value *val = old_bag.get (key); + new_bag.set (key, val->clone ()); + } + } +} + +std::unique_ptr<sarif_graph> +make_sarif_graph (const diagnostics::digraphs::digraph &g, + sarif_builder *builder, + sarif_location_manager *sarif_location_mgr) +{ + auto result = std::make_unique<sarif_graph> (); + + // 3.39.2 description property + if (const char *desc = g.get_description ()) + if (builder) + result->set<sarif_message> ("description", + builder->make_message_object (desc)); + + copy_any_property_bag (g, *result); + + // 3.39.3 nodes property + auto nodes_arr = std::make_unique<json::array> (); + const int num_nodes = g.get_num_nodes (); + for (int i = 0; i < num_nodes; ++i) + nodes_arr->append (make_sarif_node (g.get_node (i), + builder, + sarif_location_mgr)); + result->set ("nodes", std::move (nodes_arr)); + + // 3.39.4 edges property + auto edges_arr = std::make_unique<json::array> (); + const int num_edges = g.get_num_edges (); + for (int i = 0; i < num_edges; ++i) + edges_arr->append (make_sarif_edge (g.get_edge (i), builder)); + result->set ("edges", std::move (edges_arr)); + + return result; +} + +std::unique_ptr<sarif_node> +make_sarif_node (const diagnostics::digraphs::node &n, + sarif_builder *builder, + sarif_location_manager *sarif_location_mgr) +{ + auto result = std::make_unique<sarif_node> (); + + // 3.40.2 id property + result->set_string ("id", n.get_id ().c_str ()); + + copy_any_property_bag (n, *result); - /* "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); + // 3.40.3 label property + if (const char *label = n.get_label ()) + if (builder) + result->set<sarif_message> ("label", + builder->make_message_object (label)); + + // 3.40.4 location property + if (n.get_logical_loc () + || n.get_physical_loc () != UNKNOWN_LOCATION) + if (builder) + { + rich_location rich_loc + (line_table, n.get_physical_loc ()); + auto loc_obj + = builder->make_location_object + (sarif_location_mgr, + rich_loc, + n.get_logical_loc (), + diagnostic_artifact_role::scanned_file); + result->set<sarif_location> ("location", + std::move (loc_obj)); + } + + // 3.40.5 children property + if (const int num_children = n.get_num_children ()) + { + auto children_arr = std::make_unique<json::array> (); + for (int i = 0; i < num_children; ++i) + children_arr->append (make_sarif_node (n.get_child (i), + builder, + sarif_location_mgr)); + result->set ("children", std::move (children_arr)); + } + + return result; +} + +std::unique_ptr<sarif_edge> +make_sarif_edge (const diagnostics::digraphs::edge &e, + sarif_builder *builder) +{ + auto result = std::make_unique<sarif_edge> (); + + // 3.41.2 id property + result->set_string ("id", e.get_id ().c_str ()); + + copy_any_property_bag (e, *result); + + // 3.41.3 label property + if (const char *label = e.get_label ()) + if (builder) + result->set<sarif_message> ("label", + builder->make_message_object (label)); + + // 3.41.4 sourceNodeId property + result->set_string ("sourceNodeId", e.get_src_node ().get_id ().c_str ()); + + // 3.41.5 targetNodeId property + result->set_string ("targetNodeId", e.get_dst_node ().get_id ().c_str ()); + + return result; +} + +void +sarif_property_bag::set_graph (const char *property_name, + sarif_builder &builder, + sarif_location_manager *sarif_location_mgr, + const diagnostics::digraphs::digraph &g) +{ + set<sarif_graph> (property_name, + make_sarif_graph (g, &builder, sarif_location_mgr)); +} + +/* 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 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); - return logical_loc_obj; + /* "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 +3130,25 @@ 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); + + if (get_opts ().m_state_graph) + if (auto state_graph = ev.maybe_make_diagnostic_state_graph (true)) + { + sarif_property_bag &props = tfl_obj.get_or_create_properties (); + +#define PROPERTY_PREFIX "gcc/diagnostic_event/" + props.set_graph (PROPERTY_PREFIX "state_graph", + *this, + /* Use RESULT for any related locations in the graph's + nodes. + It's not clear if this is correct; see: + https://github.com/oasis-tcs/sarif-spec/issues/712 + */ + &result, + *state_graph); +#undef PROPERTY_PREFIX + } /* "location" property (SARIF v2.1.0 section 3.38.3). */ tfl_obj.set<sarif_location> @@ -2817,9 +3181,9 @@ populate_thread_flow_location_object (sarif_result &result, std::unique_ptr<json::array> sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const { - if (m.m_verb == diagnostic_event::VERB_unknown - && m.m_noun == diagnostic_event::NOUN_unknown - && m.m_property == diagnostic_event::PROPERTY_unknown) + if (m.m_verb == diagnostic_event::verb::unknown + && m.m_noun == diagnostic_event::noun::unknown + && m.m_property == diagnostic_event::property::unknown) return nullptr; auto kinds_arr = std::make_unique<json::array> (); @@ -3038,6 +3402,19 @@ 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)); + } + + // "graphs" property (SARIF v2.1.0 3.14.20) + if (m_run_graphs->size () > 0) + run_obj->set<json::array> ("graphs", + std::move (m_run_graphs)); + return run_obj; } @@ -3480,6 +3857,12 @@ public: diagnostic_output_format::dump (out, indent); } + void + set_main_input_filename (const char *name) final override + { + m_builder.set_main_input_filename (name); + } + std::unique_ptr<diagnostic_per_format_buffer> make_per_format_buffer () final override { @@ -3537,6 +3920,12 @@ public: /* No-op. */ } + void + report_global_digraph (const diagnostics::digraphs::lazy_digraph &lazy_digraph) final override + { + m_builder.report_global_digraph (lazy_digraph); + } + sarif_builder &get_builder () { return m_builder; } size_t num_results () const { return m_builder.num_results (); } @@ -3545,11 +3934,10 @@ public: protected: sarif_output_format (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization_format, const sarif_generation_options &sarif_gen_opts) : diagnostic_output_format (context), - m_builder (context, *get_printer (), line_maps, main_input_filename_, + m_builder (context, *get_printer (), line_maps, std::move (serialization_format), sarif_gen_opts), m_buffer (nullptr) {} @@ -3563,11 +3951,10 @@ class sarif_stream_output_format : public sarif_output_format public: sarif_stream_output_format (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization_format, const sarif_generation_options &sarif_gen_opts, FILE *stream) - : sarif_output_format (context, line_maps, main_input_filename_, + : sarif_output_format (context, line_maps, std::move (serialization_format), sarif_gen_opts), m_stream (stream) { @@ -3589,11 +3976,10 @@ class sarif_file_output_format : public sarif_output_format public: sarif_file_output_format (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization_format, const sarif_generation_options &sarif_gen_opts, diagnostic_output_file output_file) - : sarif_output_format (context, line_maps, main_input_filename_, + : sarif_output_format (context, line_maps, std::move (serialization_format), sarif_gen_opts), m_output_file (std::move (output_file)) { @@ -3737,34 +4123,39 @@ sarif_builder::sarif_token_printer::print_tokens (pretty_printer *pp, } /* Populate CONTEXT in preparation for SARIF output (either to stderr, or - to a file). */ + to a file). + Return a reference to *FMT. */ -static void +static diagnostic_output_format & diagnostic_output_format_init_sarif (diagnostic_context &context, std::unique_ptr<sarif_output_format> fmt) { + gcc_assert (fmt); + diagnostic_output_format &out = *fmt; + fmt->update_printer (); context.set_output_format (std::move (fmt)); + + return out; } -/* Populate CONTEXT in preparation for SARIF output to stderr. */ +/* Populate CONTEXT in preparation for SARIF output to stderr. + Return a reference to the new sink. */ -void +diagnostic_output_format & diagnostic_output_format_init_sarif_stderr (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, bool formatted) { gcc_assert (line_maps); const sarif_generation_options sarif_gen_opts; auto serialization = std::make_unique<sarif_serialization_format_json> (formatted); - diagnostic_output_format_init_sarif + return diagnostic_output_format_init_sarif (context, std::make_unique<sarif_stream_output_format> (context, line_maps, - main_input_filename_, std::move (serialization), sarif_gen_opts, stderr)); @@ -3841,12 +4232,12 @@ diagnostic_output_format_open_sarif_file (diagnostic_context &context, } /* Populate CONTEXT in preparation for SARIF output to a file named - BASE_FILE_NAME.sarif. */ + BASE_FILE_NAME.sarif. + Return a reference to the new sink. */ -void +diagnostic_output_format & diagnostic_output_format_init_sarif_file (diagnostic_context &context, line_maps *line_maps, - const char *main_input_filename_, bool formatted, const char *base_file_name) { @@ -3861,22 +4252,21 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context, = std::make_unique<sarif_serialization_format_json> (formatted); const sarif_generation_options sarif_gen_opts; - diagnostic_output_format_init_sarif + return diagnostic_output_format_init_sarif (context, std::make_unique<sarif_file_output_format> (context, line_maps, - main_input_filename_, std::move (serialization), sarif_gen_opts, std::move (output_file))); } -/* Populate CONTEXT in preparation for SARIF output to STREAM. */ +/* Populate CONTEXT in preparation for SARIF output to STREAM. + Return a reference to the new sink. */ -void +diagnostic_output_format & diagnostic_output_format_init_sarif_stream (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, bool formatted, FILE *stream) { @@ -3884,11 +4274,10 @@ diagnostic_output_format_init_sarif_stream (diagnostic_context &context, const sarif_generation_options sarif_gen_opts; auto serialization = std::make_unique<sarif_serialization_format_json> (formatted); - diagnostic_output_format_init_sarif + return diagnostic_output_format_init_sarif (context, std::make_unique<sarif_stream_output_format> (context, line_maps, - main_input_filename_, std::move (serialization), sarif_gen_opts, stream)); @@ -3897,7 +4286,6 @@ diagnostic_output_format_init_sarif_stream (diagnostic_context &context, std::unique_ptr<diagnostic_output_format> make_sarif_sink (diagnostic_context &context, const line_maps &line_maps, - const char *main_input_filename_, std::unique_ptr<sarif_serialization_format> serialization, const sarif_generation_options &sarif_gen_opts, diagnostic_output_file output_file) @@ -3905,7 +4293,6 @@ make_sarif_sink (diagnostic_context &context, auto sink = std::make_unique<sarif_file_output_format> (context, &line_maps, - main_input_filename_, std::move (serialization), sarif_gen_opts, std::move (output_file)); @@ -3916,7 +4303,8 @@ make_sarif_sink (diagnostic_context &context, // struct sarif_generation_options sarif_generation_options::sarif_generation_options () -: m_version (sarif_version::v2_1_0) +: m_version (sarif_version::v2_1_0), + m_state_graph (false) { } @@ -3924,6 +4312,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. */ @@ -3936,11 +4394,11 @@ public: { auto format = std::make_unique<buffered_output_format> (*this, line_table, - main_input_filename, true, sarif_gen_opts); m_format = format.get (); // borrowed diagnostic_output_format_init_sarif (*this, std::move (format)); + m_format->set_main_input_filename (main_input_filename); } std::unique_ptr<sarif_log> flush_to_object () @@ -3957,10 +4415,9 @@ private: public: buffered_output_format (diagnostic_context &context, const line_maps *line_maps, - const char *main_input_filename_, bool formatted, const sarif_generation_options &sarif_gen_opts) - : sarif_output_format (context, line_maps, main_input_filename_, + : sarif_output_format (context, line_maps, std::make_unique<sarif_serialization_format_json> (formatted), sarif_gen_opts) @@ -3996,7 +4453,7 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts, test_diagnostic_context dc; pretty_printer pp; sarif_builder builder - (dc, pp, line_table, "MAIN_INPUT_FILENAME", + (dc, pp, line_table, std::make_unique<sarif_serialization_format_json> (true), sarif_gen_opts); @@ -4029,7 +4486,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 +5046,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); |