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.cc649
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);