LCOV - code coverage report
Current view: top level - gcc/diagnostics - digraphs.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.5 % 91 86
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Directed graphs associated with a diagnostic.
       2              :    Copyright (C) 2025-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #ifndef GCC_DIAGNOSTICS_DIGRAPHS_H
      22              : #define GCC_DIAGNOSTICS_DIGRAPHS_H
      23              : 
      24              : #include "json.h"
      25              : #include "tristate.h"
      26              : #include "diagnostics/logical-locations.h"
      27              : 
      28              : class graphviz_out;
      29              : 
      30              : class sarif_graph;
      31              : class sarif_node;
      32              : class sarif_edge;
      33              : 
      34              : namespace dot { class graph; }
      35              : 
      36              : namespace diagnostics {
      37              : namespace digraphs {
      38              : 
      39              : /* A family of classes: digraph, node, and edge, closely related to
      40              :    SARIF's graph, node, and edge types (SARIF v2.1.0 sections 3.39-3.41).
      41              : 
      42              :    Nodes can have child nodes, allowing for arbitrarily deep nesting.
      43              :    Edges can be between any pair of nodes (potentially at different
      44              :    nesting levels).
      45              : 
      46              :    Digraphs, nodes, and edges also optionally have a JSON property bag,
      47              :    allowing round-tripping of arbitrary key/value pairs through SARIF.  */
      48              : 
      49              : class digraph;
      50              : class node;
      51              : class edge;
      52              : 
      53              : /* A base class for digraph, node, and edge to allow them to have
      54              :    an optional JSON property bag.  */
      55              : 
      56         6940 : class object
      57              : {
      58              : public:
      59              :   /* String properties.  */
      60              :   const char *get_property (const json::string_property &property) const;
      61              :   void set_property (const json::string_property &property,
      62              :                      const char *utf8_value);
      63              : 
      64              :   /* Integer properties.  */
      65              :   bool maybe_get_property (const json::integer_property &property, long &out) const;
      66              :   void set_property (const json::integer_property &property, long value);
      67              : 
      68              :   /* Bool properties.  */
      69              :   tristate
      70              :   get_property_as_tristate (const json::bool_property &property) const;
      71              :   void set_property (const json::bool_property &property, bool value);
      72              : 
      73              :   /* Array-of-string properties.  */
      74              :   json::array *
      75              :   get_property (const json::array_of_string_property &property) const;
      76              : 
      77              :   /* enum properties.  */
      78              :   template <typename EnumType>
      79              :   EnumType
      80           28 :   get_property (const json::enum_property<EnumType> &property) const
      81              :   {
      82           28 :     if (m_property_bag)
      83              :       {
      84              :         EnumType result;
      85           24 :         if (m_property_bag->maybe_get_enum<EnumType> (property, result))
      86           20 :           return result;
      87              :       }
      88            8 :     return json::enum_traits<EnumType>::get_unknown_value ();
      89              :   }
      90              :   template <typename EnumType>
      91              :   void
      92          555 :   set_property (const json::enum_property<EnumType> &property,
      93              :                 EnumType value)
      94              :   {
      95          555 :     auto &bag = ensure_property_bag ();
      96          555 :     bag.set_enum<EnumType> (property, value);
      97          555 :   }
      98              : 
      99              :   /* json::value properties.  */
     100              :   const json::value *get_property (const json::json_property &property) const;
     101              :   void set_property (const json::json_property &property,
     102              :                      std::unique_ptr<json::value> value);
     103              : 
     104              :   json::object *
     105         2021 :   get_property_bag () const { return m_property_bag.get (); }
     106              : 
     107              :   json::object &
     108              :   ensure_property_bag ();
     109              : 
     110              :   void
     111            0 :   set_property_bag (std::unique_ptr<json::object> property_bag)
     112              :   {
     113            0 :     m_property_bag = std::move (property_bag);
     114              :   }
     115              : 
     116              : private:
     117              :   std::unique_ptr<json::object> m_property_bag;
     118              : };
     119              : 
     120              : // A directed graph, corresponding to SARIF v2.1.0 section 3.39.
     121              : 
     122              : class digraph : public object
     123              : {
     124              :  public:
     125              :   friend class node;
     126              :   friend class edge;
     127              : 
     128          130 :   digraph () : m_next_edge_id_index (0) {}
     129          236 :   virtual ~digraph () {}
     130              : 
     131              :   const char *
     132          187 :   get_description () const
     133              :   {
     134          187 :     if (!m_description)
     135              :       return nullptr;
     136          152 :     return m_description->c_str ();
     137              :   }
     138              : 
     139              :   void
     140           94 :   set_description (const char *desc)
     141              :   {
     142           94 :     if (desc)
     143           94 :       m_description = std::make_unique<std::string> (desc);
     144              :     else
     145            0 :       m_description = nullptr;
     146           94 :   }
     147              :   void
     148              :   set_description (std::string desc)
     149              :   {
     150              :     m_description = std::make_unique<std::string> (std::move (desc));
     151              :   }
     152              : 
     153              :   node *
     154              :   get_node_by_id (const char *id) const
     155              :   {
     156              :     auto iter = m_id_to_node_map.find (id);
     157              :     if (iter == m_id_to_node_map.end ())
     158              :       return nullptr;
     159              :     return iter->second;
     160              :   }
     161              : 
     162              :   edge *
     163              :   get_edge_by_id (const char *id) const
     164              :   {
     165              :     auto iter = m_id_to_edge_map.find (id);
     166              :     if (iter == m_id_to_edge_map.end ())
     167              :       return nullptr;
     168              :     return iter->second;
     169              :   }
     170              : 
     171              :   size_t
     172          141 :   get_num_nodes () const
     173              :   {
     174          141 :     return m_nodes.size ();
     175              :   }
     176              : 
     177              :   node &
     178          194 :   get_node (size_t idx) const
     179              :   {
     180          194 :     return *m_nodes[idx].get ();
     181              :   }
     182              : 
     183              :   size_t
     184          141 :   get_num_edges () const
     185              :   {
     186          141 :     return m_edges.size ();
     187              :   }
     188              : 
     189              :   edge &
     190         2046 :   get_edge (size_t idx) const
     191              :   {
     192         2046 :     return *m_edges[idx].get ();
     193              :   }
     194              : 
     195              :   void
     196              :   dump () const;
     197              : 
     198              :   std::unique_ptr<json::object>
     199              :   make_json_sarif_graph () const;
     200              : 
     201              :   std::unique_ptr<dot::graph>
     202              :   make_dot_graph () const;
     203              : 
     204              :   void
     205          168 :   add_node (std::unique_ptr<node> n)
     206              :   {
     207          168 :     gcc_assert (n);
     208          168 :     m_nodes.push_back (std::move (n));
     209          168 :   }
     210              : 
     211              :   void
     212         1372 :   add_edge (std::unique_ptr<edge> e)
     213              :   {
     214         1372 :     gcc_assert (e);
     215         1372 :     m_edges.push_back (std::move (e));
     216         1372 :   }
     217              : 
     218              :   void
     219              :   add_edge (const char *id,
     220              :             node &src_node,
     221              :             node &dst_node,
     222              :             const char *label = nullptr);
     223              : 
     224              :   std::unique_ptr<digraph> clone () const;
     225              : 
     226              :   const char *get_graph_kind () const;
     227              :   void set_graph_kind (const char *);
     228              : 
     229              :   const std::map<std::string, node *> &
     230              :   get_all_nodes () const
     231              :   {
     232           90 :     return m_id_to_node_map;
     233              :   }
     234              : 
     235              :  private:
     236              :   void
     237         1961 :   add_node_id (std::string node_id, node &new_node)
     238              :   {
     239         1961 :     m_id_to_node_map.insert ({std::move (node_id), &new_node});
     240         1961 :   }
     241              :   void
     242         1376 :   add_edge_id (std::string edge_id, edge &new_edge)
     243              :   {
     244         1376 :     m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
     245         1376 :   }
     246              : 
     247              :   std::string
     248              :   make_edge_id (const char *edge_id);
     249              : 
     250              :   std::unique_ptr<std::string> m_description;
     251              :   std::map<std::string, node *> m_id_to_node_map;
     252              :   std::map<std::string, edge *> m_id_to_edge_map;
     253              :   std::vector<std::unique_ptr<node>> m_nodes;
     254              :   std::vector<std::unique_ptr<edge>> m_edges;
     255              :   size_t m_next_edge_id_index;
     256              : };
     257              : 
     258              : // A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
     259              : 
     260              : class node : public object
     261              : {
     262              :  public:
     263         3918 :   virtual ~node () {}
     264              : 
     265         1961 :   node (digraph &g, std::string id)
     266         3922 :   : m_id (id),
     267         3922 :     m_physical_loc (UNKNOWN_LOCATION)
     268              :   {
     269         1961 :     g.add_node_id (std::move (id), *this);
     270         1961 :   }
     271              :   node (const node &) = delete;
     272              : 
     273              :   std::string
     274         8190 :   get_id () const { return m_id; }
     275              : 
     276              :   const char *
     277         1957 :   get_label () const
     278              :   {
     279         1957 :     if (!m_label)
     280              :       return nullptr;
     281          812 :     return m_label->c_str ();
     282              :   }
     283              : 
     284              :   void
     285            4 :   set_label (const char *label)
     286              :   {
     287            4 :     if (label)
     288            4 :       m_label = std::make_unique<std::string> (label);
     289              :     else
     290            0 :       m_label = nullptr;
     291            4 :   }
     292              :   void
     293              :   set_label (std::string label)
     294              :   {
     295              :     m_label = std::make_unique<std::string> (std::move (label));
     296              :   }
     297              : 
     298              :   size_t
     299         1322 :   get_num_children () const { return m_children.size (); }
     300              : 
     301              :   node &
     302         1785 :   get_child (size_t idx) const { return *m_children[idx].get (); }
     303              : 
     304              :   void
     305          977 :   add_child (std::unique_ptr<node> child)
     306              :   {
     307          977 :     gcc_assert (child);
     308          977 :     m_children.push_back (std::move (child));
     309          977 :   }
     310              : 
     311              :   location_t
     312         1224 :   get_physical_loc () const
     313              :   {
     314         1224 :     return m_physical_loc;
     315              :   }
     316              : 
     317              :   void
     318              :   set_physical_loc (location_t physical_loc)
     319              :   {
     320              :     m_physical_loc = physical_loc;
     321              :   }
     322              : 
     323              :   logical_locations::key
     324         1263 :   get_logical_loc () const
     325              :   {
     326         1263 :     return m_logical_loc;
     327              :   }
     328              : 
     329              :   void
     330           39 :   set_logical_loc (logical_locations::key logical_loc)
     331              :   {
     332           39 :     m_logical_loc = logical_loc;
     333              :   }
     334              : 
     335              :   void print (graphviz_out &gv) const;
     336              : 
     337              :   void
     338              :   dump () const;
     339              : 
     340              :   std::unique_ptr<json::object>
     341              :   to_json_sarif_node () const;
     342              : 
     343              :   std::unique_ptr<node>
     344              :   clone (digraph &new_graph,
     345              :          std::map<node *, node *> &node_mapping) const;
     346              : 
     347              : private:
     348              :   std::string m_id;
     349              :   std::unique_ptr<std::string> m_label;
     350              :   std::vector<std::unique_ptr<node>> m_children;
     351              :   location_t m_physical_loc;
     352              :   logical_locations::key m_logical_loc;
     353              : };
     354              : 
     355              : // An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
     356              : 
     357              : class edge : public object
     358              : {
     359              :  public:
     360         2752 :   virtual ~edge () {}
     361              : 
     362              :   /* SARIF requires us to provide unique edge IDs within a graph,
     363              :      but otherwise we don't need them.
     364              :      Pass in nullptr for the id to get the graph to generate a unique
     365              :      edge id for us.  */
     366         1376 :   edge (digraph &g,
     367              :         const char *id,
     368              :         node &src_node,
     369              :         node &dst_node)
     370         1376 :   : m_id (g.make_edge_id (id)),
     371         1376 :     m_src_node (src_node),
     372         1376 :     m_dst_node (dst_node)
     373              :   {
     374         2752 :     g.add_edge_id (m_id, *this);
     375         1376 :   }
     376              : 
     377              :   std::string
     378         1428 :   get_id () const { return m_id; }
     379              : 
     380              :   const char *
     381         1380 :   get_label () const
     382              :   {
     383         1380 :     if (!m_label)
     384              :       return nullptr;
     385          792 :     return m_label->c_str ();
     386              :   }
     387              : 
     388              :   void
     389          784 :   set_label (const char *label)
     390              :   {
     391          784 :     if (label)
     392          784 :       m_label = std::make_unique<std::string> (label);
     393              :     else
     394            0 :       m_label = nullptr;
     395          784 :   }
     396              : 
     397              :   node &
     398         2046 :   get_src_node () const { return m_src_node; }
     399              : 
     400              :   node &
     401         2046 :   get_dst_node () const { return m_dst_node; }
     402              : 
     403              :   void
     404              :   dump () const;
     405              : 
     406              :   std::unique_ptr<json::object>
     407              :   to_json_sarif_edge () const;
     408              : 
     409              :   std::unique_ptr<edge>
     410              :   clone (digraph &new_graph,
     411              :          const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
     412              : 
     413              : private:
     414              :   std::string m_id;
     415              :   std::unique_ptr<std::string> m_label;
     416              :   node &m_src_node;
     417              :   node &m_dst_node;
     418              : };
     419              : 
     420              : } // namespace digraphs
     421              : } // namespace diagnostics
     422              : 
     423              : #endif /* ! GCC_DIAGNOSTICS_DIGRAPHS_H */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.