aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostics/digraphs.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostics/digraphs.h')
-rw-r--r--gcc/diagnostics/digraphs.h379
1 files changed, 379 insertions, 0 deletions
diff --git a/gcc/diagnostics/digraphs.h b/gcc/diagnostics/digraphs.h
new file mode 100644
index 0000000..7193ee4
--- /dev/null
+++ b/gcc/diagnostics/digraphs.h
@@ -0,0 +1,379 @@
+/* Directed graphs associated with a diagnostic.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_DIGRAPHS_H
+#define GCC_DIAGNOSTICS_DIGRAPHS_H
+
+#include "json.h"
+#include "diagnostics/logical-locations.h"
+
+class graphviz_out;
+
+class sarif_graph;
+class sarif_node;
+class sarif_edge;
+
+namespace dot { class graph; }
+
+namespace diagnostics {
+namespace digraphs {
+
+/* A family of classes: digraph, node, and edge, closely related to
+ SARIF's graph, node, and edge types (SARIF v2.1.0 sections 3.39-3.41).
+
+ Nodes can have child nodes, allowing for arbitrarily deep nesting.
+ Edges can be between any pair of nodes (potentially at different
+ nesting levels).
+
+ Digraphs, nodes, and edges also optionally have a JSON property bag,
+ allowing round-tripping of arbitrary key/value pairs through SARIF. */
+
+class digraph;
+class node;
+class edge;
+
+/* A base class for digraph, node, and edge to allow them to have
+ an optional JSON property bag. */
+
+class object
+{
+public:
+ const char *
+ get_attr (const char *key_prefix,
+ const char *key) const;
+
+ void
+ set_attr (const char *key_prefix,
+ const char *key,
+ const char *value);
+
+ void
+ set_json_attr (const char *key_prefix,
+ const char *key,
+ std::unique_ptr<json::value> value);
+
+ json::object *
+ get_property_bag () const { return m_property_bag.get (); }
+
+ void
+ set_property_bag (std::unique_ptr<json::object> property_bag)
+ {
+ m_property_bag = std::move (property_bag);
+ }
+
+private:
+ std::unique_ptr<json::object> m_property_bag;
+};
+
+// A directed graph, corresponding to SARIF v2.1.0 section 3.39.
+
+class digraph : public object
+{
+ public:
+ friend class node;
+ friend class edge;
+
+ digraph () : m_next_edge_id_index (0) {}
+ virtual ~digraph () {}
+
+ const char *
+ get_description () const
+ {
+ if (!m_description)
+ return nullptr;
+ return m_description->c_str ();
+ }
+
+ void
+ set_description (const char *desc)
+ {
+ if (desc)
+ m_description = std::make_unique<std::string> (desc);
+ else
+ m_description = nullptr;
+ }
+ void
+ set_description (std::string desc)
+ {
+ m_description = std::make_unique<std::string> (std::move (desc));
+ }
+
+ node *
+ get_node_by_id (const char *id) const
+ {
+ auto iter = m_id_to_node_map.find (id);
+ if (iter == m_id_to_node_map.end ())
+ return nullptr;
+ return iter->second;
+ }
+
+ edge *
+ get_edge_by_id (const char *id) const
+ {
+ auto iter = m_id_to_edge_map.find (id);
+ if (iter == m_id_to_edge_map.end ())
+ return nullptr;
+ return iter->second;
+ }
+
+ size_t
+ get_num_nodes () const
+ {
+ return m_nodes.size ();
+ }
+
+ node &
+ get_node (size_t idx) const
+ {
+ return *m_nodes[idx].get ();
+ }
+
+ size_t
+ get_num_edges () const
+ {
+ return m_edges.size ();
+ }
+
+ edge &
+ get_edge (size_t idx) const
+ {
+ return *m_edges[idx].get ();
+ }
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ make_json_sarif_graph () const;
+
+ std::unique_ptr<dot::graph>
+ make_dot_graph () const;
+
+ void
+ add_node (std::unique_ptr<node> n)
+ {
+ gcc_assert (n);
+ m_nodes.push_back (std::move (n));
+ }
+
+ void
+ add_edge (std::unique_ptr<edge> e)
+ {
+ gcc_assert (e);
+ m_edges.push_back (std::move (e));
+ }
+
+ void
+ add_edge (const char *id,
+ node &src_node,
+ node &dst_node,
+ const char *label = nullptr);
+
+ std::unique_ptr<digraph> clone () const;
+
+ private:
+ void
+ add_node_id (std::string node_id, node &new_node)
+ {
+ m_id_to_node_map.insert ({std::move (node_id), &new_node});
+ }
+ void
+ add_edge_id (std::string edge_id, edge &new_edge)
+ {
+ m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
+ }
+
+ std::string
+ make_edge_id (const char *edge_id);
+
+ std::unique_ptr<std::string> m_description;
+ std::map<std::string, node *> m_id_to_node_map;
+ std::map<std::string, edge *> m_id_to_edge_map;
+ std::vector<std::unique_ptr<node>> m_nodes;
+ std::vector<std::unique_ptr<edge>> m_edges;
+ size_t m_next_edge_id_index;
+};
+
+// A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
+
+class node : public object
+{
+ public:
+ virtual ~node () {}
+
+ node (digraph &g, std::string id)
+ : m_id (id),
+ m_physical_loc (UNKNOWN_LOCATION)
+ {
+ g.add_node_id (std::move (id), *this);
+ }
+ node (const node &) = delete;
+
+ std::string
+ get_id () const { return m_id; }
+
+ const char *
+ get_label () const
+ {
+ if (!m_label)
+ return nullptr;
+ return m_label->c_str ();
+ }
+
+ void
+ set_label (const char *label)
+ {
+ if (label)
+ m_label = std::make_unique<std::string> (label);
+ else
+ m_label = nullptr;
+ }
+ void
+ set_label (std::string label)
+ {
+ m_label = std::make_unique<std::string> (std::move (label));
+ }
+
+ size_t
+ get_num_children () const { return m_children.size (); }
+
+ node &
+ get_child (size_t idx) const { return *m_children[idx].get (); }
+
+ void
+ add_child (std::unique_ptr<node> child)
+ {
+ gcc_assert (child);
+ m_children.push_back (std::move (child));
+ }
+
+ location_t
+ get_physical_loc () const
+ {
+ return m_physical_loc;
+ }
+
+ void
+ set_physical_loc (location_t physical_loc)
+ {
+ m_physical_loc = physical_loc;
+ }
+
+ logical_locations::key
+ get_logical_loc () const
+ {
+ return m_logical_loc;
+ }
+
+ void
+ set_logical_loc (logical_locations::key logical_loc)
+ {
+ m_logical_loc = logical_loc;
+ }
+
+ void print (graphviz_out &gv) const;
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ to_json_sarif_node () const;
+
+ std::unique_ptr<node>
+ clone (digraph &new_graph,
+ std::map<node *, node *> &node_mapping) const;
+
+ private:
+ std::string m_id;
+ std::unique_ptr<std::string> m_label;
+ std::vector<std::unique_ptr<node>> m_children;
+ location_t m_physical_loc;
+ logical_locations::key m_logical_loc;
+};
+
+// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
+
+class edge : public object
+{
+ public:
+ virtual ~edge () {}
+
+ /* SARIF requires us to provide unique edge IDs within a graph,
+ but otherwise we don't need them.
+ Pass in nullptr for the id to get the graph to generate a unique
+ edge id for us. */
+ edge (digraph &g,
+ const char *id,
+ node &src_node,
+ node &dst_node)
+ : m_id (g.make_edge_id (id)),
+ m_src_node (src_node),
+ m_dst_node (dst_node)
+ {
+ g.add_edge_id (m_id, *this);
+ }
+
+ std::string
+ get_id () const { return m_id; }
+
+ const char *
+ get_label () const
+ {
+ if (!m_label)
+ return nullptr;
+ return m_label->c_str ();
+ }
+
+ void
+ set_label (const char *label)
+ {
+ if (label)
+ m_label = std::make_unique<std::string> (label);
+ else
+ m_label = nullptr;
+ }
+
+ node &
+ get_src_node () const { return m_src_node; }
+
+ node &
+ get_dst_node () const { return m_dst_node; }
+
+ void
+ dump () const;
+
+ std::unique_ptr<json::object>
+ to_json_sarif_edge () const;
+
+ std::unique_ptr<edge>
+ clone (digraph &new_graph,
+ const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
+
+private:
+ std::string m_id;
+ std::unique_ptr<std::string> m_label;
+ node &m_src_node;
+ node &m_dst_node;
+};
+
+} // namespace digraphs
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_DIGRAPHS_H */