diff options
Diffstat (limited to 'gcc/diagnostics/digraphs.h')
-rw-r--r-- | gcc/diagnostics/digraphs.h | 379 |
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 */ |