aboutsummaryrefslogtreecommitdiff
path: root/gcc/libsarifreplay.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/libsarifreplay.cc')
-rw-r--r--gcc/libsarifreplay.cc435
1 files changed, 419 insertions, 16 deletions
diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index 2d6c394..cad535b 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "libgdiagnostics++.h"
+#include "libgdiagnostics-private.h"
#include "json-parsing.h"
#include "intl.h"
#include "sarif-spec-urls.def"
@@ -291,6 +292,8 @@ public:
label_text m_label;
};
+using id_map = std::map<std::string, const json::string *>;
+
class sarif_replayer
{
public:
@@ -413,6 +416,30 @@ private:
const json::object &run_obj,
libgdiagnostics::execution_path &out);
+ // "graph" object (§3.39)
+ enum status
+ handle_graph_object (const json::object &graph_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &out);
+ // "node" object (§3.40)
+ libgdiagnostics::node
+ handle_node_object (const json::object &node_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &graph,
+ libgdiagnostics::node parent_node,
+ id_map &node_id_map);
+
+ // "edge" object (§3.41)
+ libgdiagnostics::edge
+ handle_edge_object (const json::object &edge_obj,
+ libgdiagnostics::graph &graph,
+ id_map &edge_id_map);
+
+ libgdiagnostics::node
+ get_graph_node_by_id_property (const json::object &edge_json_object,
+ const property_spec_ref &id_prop,
+ libgdiagnostics::graph &graph);
+
// reportingDescriptor lookup (§3.52.3)
const json::object *
lookup_rule_by_id_in_tool (const char *rule_id,
@@ -446,7 +473,7 @@ private:
{
va_list ap;
va_start (ap, gmsgid);
- report_problem (jv, ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_ERROR);
+ report_problem (jv, &ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_ERROR);
va_end (ap);
return status::err_invalid_sarif;
}
@@ -462,14 +489,25 @@ private:
{
va_list ap;
va_start (ap, gmsgid);
- report_problem (jv, ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_SORRY);
+ report_problem (jv, &ref, gmsgid, &ap, DIAGNOSTIC_LEVEL_SORRY);
va_end (ap);
return status::err_unhandled_sarif;
}
void
+ report_note (const json::value &jv,
+ const char *gmsgid, ...)
+ LIBGDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (3, 4)
+ {
+ va_list ap;
+ va_start (ap, gmsgid);
+ report_problem (jv, nullptr, gmsgid, &ap, DIAGNOSTIC_LEVEL_NOTE);
+ va_end (ap);
+ }
+
+ void
report_problem (const json::value &jv,
- const spec_ref &ref,
+ const spec_ref *ref,
const char *gmsgid,
va_list *args,
enum diagnostic_level level)
@@ -481,11 +519,14 @@ private:
There doesn't seem to be a systematic mapping from spec sections to
HTML anchors, so we can't provide URLs
(filed as https://github.com/oasis-tcs/sarif-spec/issues/533 ). */
- char *ref_desc = ref.make_description ();
- char *ref_url = ref.make_url ();
- diag.add_rule (ref_desc, ref_url);
- free (ref_desc);
- free (ref_url);
+ if (ref)
+ {
+ char *ref_desc = ref->make_description ();
+ char *ref_url = ref->make_url ();
+ diag.add_rule (ref_desc, ref_url);
+ free (ref_desc);
+ free (ref_url);
+ }
auto loc_range
= make_physical_location (m_control_mgr,
@@ -651,6 +692,38 @@ private:
const string_property_value<ValueType> *value_arr,
size_t num_values);
+ const json::object *
+ maybe_get_property_bag (const json::object &obj)
+ {
+ const property_spec_ref properties
+ ("object", "properties", "3.8.1");
+ return get_optional_property<json::object> (obj, properties);
+ }
+
+ /* Look for a property bag within OBJ.
+ If found, look for a property within it named PROPERTY_NAME
+ of the given type.
+ If successful, return the property's value.
+ Otherwise, return nullptr without complaining (unless the property bag
+ is itself not an object). */
+ template <typename JsonType>
+ const JsonType *
+ maybe_get_property_bag_value (const json::object &obj,
+ const char *property_name)
+ {
+ auto property_bag_obj = maybe_get_property_bag (obj);
+ if (!property_bag_obj)
+ return nullptr;
+ const json::value *property_val = property_bag_obj->get (property_name);
+ if (!property_val)
+ return nullptr;
+ const JsonType *sub = dyn_cast<const JsonType *> (property_val);
+ if (!sub)
+ /* Property is wrong kind of value. Don't treat this as an error. */
+ return nullptr;
+ return sub;
+ }
+
/* The manager to replay the SARIF files to. */
libgdiagnostics::manager m_output_mgr;
@@ -929,6 +1002,31 @@ sarif_replayer::handle_run_obj (const json::object &run_obj)
break;
}
+ // §3.14.20 "graphs"
+ const property_spec_ref prop_graphs ("run", "graphs", "3.14.20");
+ if (const json::array *graphs
+ = get_optional_property<json::array> (run_obj,
+ prop_graphs))
+ {
+ for (auto element : *graphs)
+ {
+ if (const json::object *graph_json_obj
+ = require_object_for_element (*element, prop_graphs))
+ {
+ libgdiagnostics::graph graph;
+ enum status s = handle_graph_object (*graph_json_obj,
+ run_obj,
+ graph);
+ if (s != status::ok)
+ return s;
+
+ m_output_mgr.take_global_graph (std::move (graph));
+ }
+ else
+ return status::err_invalid_sarif;
+ }
+ }
+
return status::ok;
}
@@ -1244,6 +1342,31 @@ sarif_replayer::handle_result_obj (const json::object &result_obj,
if (path.m_inner)
err.take_execution_path (std::move (path));
+ // §3.27.19 "graphs" property
+ const property_spec_ref prop_graphs ("result", "graphs", "3.27.19");
+ if (const json::array *graphs
+ = get_optional_property<json::array> (result_obj,
+ prop_graphs))
+ {
+ for (auto element : *graphs)
+ {
+ if (const json::object *graph_json_obj
+ = require_object_for_element (*element, prop_graphs))
+ {
+ libgdiagnostics::graph graph;
+ enum status s = handle_graph_object (*graph_json_obj,
+ run_obj,
+ graph);
+ if (s != status::ok)
+ return s;
+
+ err.take_graph (std::move (graph));
+ }
+ else
+ return status::err_invalid_sarif;
+ }
+ }
+
// §3.27.22 relatedLocations property
std::vector<std::pair<libgdiagnostics::diagnostic, label_text>> notes;
const property_spec_ref prop_related_locations
@@ -1740,16 +1863,32 @@ handle_thread_flow_location_object (const json::object &tflow_loc_obj,
}
}
+ libgdiagnostics::graph state_graph;
+ if (auto sarif_state_graph
+ = maybe_get_property_bag_value<json::object> (tflow_loc_obj,
+ "gcc/diagnostic_event/state_graph"))
+ {
+ enum status s
+ = handle_graph_object (*sarif_state_graph, run_obj, state_graph);
+ if (s != status::ok)
+ return s;
+ }
+
if (message.get ())
- path.add_event (physical_loc,
- logical_loc,
- stack_depth,
- "%s", message.get ());
+ private_diagnostic_execution_path_add_event_2 (path.m_inner,
+ physical_loc.m_inner,
+ logical_loc.m_inner,
+ stack_depth,
+ state_graph.m_inner,
+ "%s", message.get ());
else
- path.add_event (physical_loc,
- logical_loc,
- stack_depth,
- "");
+ private_diagnostic_execution_path_add_event_2 (path.m_inner,
+ physical_loc.m_inner,
+ logical_loc.m_inner,
+ stack_depth,
+ state_graph.m_inner,
+ "");
+ state_graph.m_owned = false;
return status::ok;
}
@@ -2142,6 +2281,270 @@ handle_logical_location_object (const json::object &logical_loc_obj,
return status::ok;
}
+// "graph" object (§3.39)
+
+enum status
+sarif_replayer::handle_graph_object (const json::object &graph_json_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &out_graph)
+{
+ out_graph = libgdiagnostics::graph
+ (diagnostic_manager_new_graph (m_output_mgr.m_inner));
+
+ id_map node_id_map;
+ id_map edge_id_map;
+
+ if (auto properties = maybe_get_property_bag (graph_json_obj))
+ private_diagnostic_graph_set_property_bag (*out_graph.m_inner,
+ properties->clone_as_object ());
+
+ // §3.39.2: MAY contain a "description" property
+ const property_spec_ref description_prop
+ ("graph", "description", "3.39.2");
+ if (auto description_obj
+ = get_optional_property<json::object> (graph_json_obj, description_prop))
+ {
+ label_text text
+ = make_plain_text_within_result_message (&run_obj,
+ *description_obj,
+ nullptr);
+ if (!text.get ())
+ return status::err_invalid_sarif;
+ out_graph.set_description (text.get ());
+ }
+
+ // §3.39.3: MAY contain a "nodes" property
+ const property_spec_ref nodes_prop
+ ("graph", "nodes", "3.39.3");
+ if (auto nodes_arr
+ = get_optional_property<json::array> (graph_json_obj, nodes_prop))
+ {
+ for (auto element : *nodes_arr)
+ {
+ const json::object *node_json_obj
+ = require_object_for_element (*element, nodes_prop);
+ if (!node_json_obj)
+ return status::err_invalid_sarif;
+ libgdiagnostics::node node
+ = handle_node_object (*node_json_obj, run_obj, out_graph,
+ nullptr, node_id_map);
+ if (node.m_inner == nullptr)
+ return status::err_invalid_sarif;
+ }
+ }
+ else
+ // If we have no nodes, we can't handle the edges.
+ return status::ok;
+
+ // §3.39.4 edges property
+ const property_spec_ref edges_prop
+ ("graph", "edges", "3.39.4");
+ if (auto edges_arr
+ = get_optional_property<json::array> (graph_json_obj, edges_prop))
+ {
+ for (auto element : *edges_arr)
+ {
+ const json::object *edge_json_obj
+ = require_object_for_element (*element, edges_prop);
+ if (!edge_json_obj)
+ return status::err_invalid_sarif;
+ libgdiagnostics::edge edge
+ = handle_edge_object (*edge_json_obj, out_graph, edge_id_map);
+ if (edge.m_inner == nullptr)
+ return status::err_invalid_sarif;
+ }
+ }
+
+ return status::ok;
+}
+
+// "node" object (§3.40)
+
+libgdiagnostics::node
+sarif_replayer::handle_node_object (const json::object &node_json_obj,
+ const json::object &run_obj,
+ libgdiagnostics::graph &graph,
+ libgdiagnostics::node parent_node,
+ id_map &node_id_map)
+{
+ // §3.40.2 "id" property
+ const property_spec_ref id_prop ("node", "id", "3.40.2");
+ auto id_str = get_required_property<json::string> (node_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ if (diagnostic_graph_get_node_by_id (graph.m_inner, id))
+ {
+ // Duplicate id; fail:
+ libgdiagnostics::group g (m_control_mgr);
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "duplicate node id %qs within graph",
+ id);
+ gcc_assert (node_id_map[id]);
+ report_note (*node_id_map[id],
+ "%qs already used as node id within graph here",
+ id);
+ return nullptr;
+ }
+ node_id_map[id] = id_str;
+
+ libgdiagnostics::node new_node
+ = libgdiagnostics::node (diagnostic_graph_add_node (graph.m_inner,
+ id,
+ parent_node.m_inner));
+ if (auto properties = maybe_get_property_bag (node_json_obj))
+ private_diagnostic_node_set_property_bag (*new_node.m_inner,
+ properties->clone_as_object ());
+
+ // §3.40.3 "label" property
+ const property_spec_ref label_prop
+ ("node", "label", "3.40.3");
+ if (auto label_obj
+ = get_optional_property<json::object> (node_json_obj, label_prop))
+ {
+ label_text text
+ = make_plain_text_within_result_message (&run_obj,
+ *label_obj,
+ nullptr);
+ if (!text.get ())
+ return nullptr;
+ new_node.set_label (text.get ());
+ }
+
+ // §3.40.4 "location" property
+ const property_spec_ref location_prop ("node", "location", "3.40.4");
+ if (auto location_json_obj
+ = get_optional_property<json::object> (node_json_obj, location_prop))
+ {
+ libgdiagnostics::physical_location physical_loc;
+ libgdiagnostics::logical_location logical_loc;
+ enum status s = handle_location_object (*location_json_obj,
+ run_obj,
+ physical_loc,
+ logical_loc,
+ nullptr); // annotations
+ if (s != status::ok)
+ return nullptr;
+
+ new_node.set_location (physical_loc);
+ new_node.set_logical_location (logical_loc);
+ }
+
+ // §3.40.5: MAY contain a "children" property
+ const property_spec_ref children_prop
+ ("graph", "children", "3.40.5");
+ if (auto children_json_arr
+ = get_optional_property<json::array> (node_json_obj, children_prop))
+ {
+ for (auto json_element : *children_json_arr)
+ {
+ const json::object *child_json_obj
+ = require_object_for_element (*json_element, children_prop);
+ if (!child_json_obj)
+ return nullptr;
+ libgdiagnostics::node child_node
+ = handle_node_object (*child_json_obj, run_obj, graph,
+ new_node, node_id_map);
+ if (child_node.m_inner == nullptr)
+ return nullptr;
+ }
+ }
+
+ return new_node;
+}
+
+// "edge" object (§3.41)
+
+libgdiagnostics::edge
+sarif_replayer::handle_edge_object (const json::object &edge_json_obj,
+ libgdiagnostics::graph &graph,
+ id_map &edge_id_map)
+{
+ // §3.41.2 "id" property
+ const property_spec_ref id_prop ("edge", "id", "3.41.2");
+ auto id_str = get_required_property<json::string> (edge_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ if (diagnostic_graph_get_edge_by_id (graph.m_inner, id))
+ {
+ // Duplicate id; fail:
+ libgdiagnostics::group g (m_control_mgr);
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "duplicate edge id %qs within graph",
+ id);
+ gcc_assert (edge_id_map[id]);
+ report_note (*edge_id_map[id],
+ "%qs already used as edge id within graph here",
+ id);
+ return nullptr;
+ }
+ edge_id_map[id] = id_str;
+
+ // §3.41.3 "label" property
+ label_text label;
+ const property_spec_ref label_prop
+ ("edge", "label", "3.41.3");
+ if (auto label_obj
+ = get_optional_property<json::object> (edge_json_obj, label_prop))
+ {
+ label = make_plain_text_within_result_message (nullptr,
+ *label_obj,
+ nullptr);
+ if (!label.get ())
+ return nullptr;
+ }
+
+ // §3.41.4 "sourceNodeId" property
+ const property_spec_ref src_id_prop ("edge", "sourceNodeId", "3.41.4");
+ auto src_node = get_graph_node_by_id_property (edge_json_obj,
+ src_id_prop,
+ graph);
+ if (!src_node.m_inner)
+ return nullptr;
+
+ // §3.41.5 "targetNodeId" property
+ const property_spec_ref dst_id_prop ("edge", "targetNodeId", "3.41.5");
+ auto dst_node = get_graph_node_by_id_property (edge_json_obj,
+ dst_id_prop,
+ graph);
+ if (!dst_node.m_inner)
+ return nullptr;
+
+ auto result = graph.add_edge (id, src_node, dst_node, label.get ());
+
+ if (auto properties = maybe_get_property_bag (edge_json_obj))
+ private_diagnostic_edge_set_property_bag (*result.m_inner,
+ properties->clone_as_object ());
+
+ return result;
+}
+
+libgdiagnostics::node
+sarif_replayer::
+get_graph_node_by_id_property (const json::object &edge_json_obj,
+ const property_spec_ref &id_prop,
+ libgdiagnostics::graph &graph)
+{
+ auto id_str = get_required_property<json::string> (edge_json_obj, id_prop);
+ if (!id_str)
+ return nullptr;
+ const char *id = id_str->get_string ();
+ auto node = graph.get_node_by_id (id);
+ if (!node.m_inner)
+ {
+ // id not found; complain:
+ report_invalid_sarif (*id_str,
+ id_prop,
+ "no node with id %qs in graph",
+ id);
+ return nullptr;
+ }
+ return node;
+}
+
// 3.52.3 reportingDescriptor lookup
// "For an example of the interaction between ruleId and rule.id, see §3.52.4."