LCOV - code coverage report
Current view: top level - gcc - graphviz.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.3 % 86 82
Test Date: 2026-02-28 14:20:25 Functions: 90.0 % 10 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Helper code for graphviz output.
       2              :    Copyright (C) 2019-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
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License 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_GRAPHVIZ_H
      22              : #define GCC_GRAPHVIZ_H
      23              : 
      24              : #include "pretty-print.h" /* for ATTRIBUTE_GCC_PPDIAG.  */
      25              : 
      26              : namespace xml { class node; }
      27              : 
      28              : namespace dot {
      29              : 
      30              : /* A class for writing .dot output to a pretty_printer with
      31              :    indentation to show nesting.  */
      32              : 
      33              : class writer {
      34              : public:
      35              :   writer (pretty_printer &pp);
      36              : 
      37         1457 :   void indent () { m_indent++; }
      38         1457 :   void outdent () { m_indent--; }
      39              : 
      40              :   void write_indent ();
      41              : 
      42        34564 :   void write_character (char ch)
      43              :   {
      44        34564 :     pp_character (&m_pp, ch);
      45        28275 :   }
      46        14991 :   void write_string (const char *str)
      47              :   {
      48        14991 :     pp_string (&m_pp, str);
      49        11039 :   }
      50         1841 :   void write_newline ()
      51              :   {
      52         1841 :     pp_newline (&m_pp);
      53              :   }
      54              : 
      55        69994 :   pretty_printer *get_pp () const { return &m_pp; }
      56              : 
      57              :  private:
      58              :   pretty_printer &m_pp;
      59              :   int m_indent;
      60              : };
      61              : 
      62              : // An AST for the dot language
      63              : // See https://graphviz.org/doc/info/lang.html
      64              : 
      65              : // Forward decls
      66              : 
      67              : struct id;
      68              : struct node_id;
      69              : struct port;
      70              : struct kv_pair;
      71              : struct graph;
      72              : struct attr_list;
      73              : struct stmt_list;
      74              : struct stmt;
      75              :   struct node_stmt;
      76              :   struct attr_stmt;
      77              :   struct kv_stmt;
      78              :   struct edge_stmt;
      79              :   struct subgraph;
      80              : 
      81              : // Decls
      82              : 
      83        35380 : struct ast_node
      84              : {
      85        23819 :   virtual ~ast_node () {}
      86              :   virtual void print (writer &w) const = 0;
      87              : 
      88              :   void dump () const;
      89              : };
      90              : 
      91         8650 : struct id : public ast_node
      92              : {
      93              :   enum class kind
      94              :   {
      95              :     identifier,
      96              :     quoted,
      97              :     html
      98              :   };
      99              : 
     100              :   id (std::string str);
     101              : 
     102              :   /* For HTML labels: see https://graphviz.org/doc/info/shapes.html#html  */
     103              :   id (const xml::node &n);
     104              : 
     105              :   void print (writer &w) const final override;
     106              : 
     107              :   static bool is_identifier_p (const char *);
     108              : 
     109              :   std::string m_str;
     110              :   enum kind m_kind;
     111              : };
     112              : 
     113              : /* ID '=' ID */
     114              : 
     115              : struct kv_pair : ast_node
     116              : {
     117         3560 :   kv_pair (id key, id value)
     118         7120 :   : m_key (std::move (key)),
     119         3560 :     m_value (std::move (value))
     120              :   {
     121         3560 :   }
     122              : 
     123              :   void print (writer &w) const final override;
     124              : 
     125              :   id m_key;
     126              :   id m_value;
     127              : };
     128              : 
     129              : /* attr_list: '[' [ a_list ] ']' [ attr_list ] */
     130              : 
     131         2316 : struct attr_list : public ast_node
     132              : {
     133              :   void print (writer &w) const;
     134         3503 :   void add (id key, id value)
     135              :   {
     136         3503 :     m_kvs.push_back ({std::move (key), std::move (value)});
     137         3503 :   }
     138              : 
     139              :   std::vector<kv_pair> m_kvs;
     140              : };
     141              : 
     142              : /* stmt_list : [ stmt [ ';' ] stmt_list ] */
     143              : 
     144          117 : struct stmt_list : public ast_node
     145              : {
     146              :   void print (writer &w) const final override;
     147         1532 :   void add_stmt (std::unique_ptr<stmt> s)
     148              :   {
     149         1532 :     m_stmts.push_back (std::move (s));
     150              :   }
     151              :   void add_edge (node_id src_id, node_id dst_id);
     152              :   void add_attr (id key, id value);
     153              : 
     154              :   std::vector<std::unique_ptr<stmt>> m_stmts;
     155              : };
     156              : 
     157              : /* graph : [ strict ] (graph | digraph) [ ID ] '{' stmt_list '}'  */
     158              : 
     159              : struct graph : public ast_node
     160              : {
     161           61 :   graph ()
     162           61 :   : m_id (nullptr)
     163              :   {
     164              :   }
     165              : 
     166            4 :   graph (id id_)
     167            4 :   : m_id (std::make_unique<id> (std::move (id_)))
     168              :   {
     169              :   }
     170              : 
     171              :   void print (writer &w) const final override;
     172              : 
     173           30 :   void add_stmt (std::unique_ptr<stmt> s)
     174              :   {
     175           30 :     m_stmt_list.add_stmt (std::move (s));
     176           30 :   }
     177              : 
     178              :   std::unique_ptr<id> m_id; // optional
     179              :   stmt_list m_stmt_list;
     180              : };
     181              : 
     182              : /* Abstract base class.
     183              :      stmt : node_stmt
     184              :           | edge_stmt
     185              :           | attr_stmt
     186              :           | ID '=' ID ("kv_stmt")
     187              :           | subgraph  */
     188              : 
     189         1540 : struct stmt
     190              : {
     191              :   virtual ~stmt () {}
     192              :   virtual void print (writer &w) const = 0;
     193              : };
     194              : 
     195         1426 : struct stmt_with_attr_list : public stmt
     196              : {
     197         1890 :   void set_attr (id key, id value)
     198              :   {
     199         1890 :     m_attrs.add (std::move (key), std::move (value));
     200         1890 :   }
     201              :   void set_label (dot::id label);
     202              : 
     203              :   attr_list m_attrs;
     204              : };
     205              : 
     206              : struct node_stmt : public stmt_with_attr_list
     207              : {
     208          698 :   node_stmt (id id_)
     209          698 :   : m_id (id_)
     210              :   {
     211              :   }
     212              : 
     213              :   void print (writer &w) const final override;
     214              : 
     215              :   id m_id;
     216              : };
     217              : 
     218              : struct attr_stmt : public stmt_with_attr_list
     219              : {
     220              :   enum class kind { graph, node, edge };
     221              : 
     222            5 :   attr_stmt (enum kind kind_)
     223            5 :   : m_kind (kind_)
     224              :   {
     225              :   }
     226              : 
     227              :   void print (writer &w) const final override;
     228              : 
     229              :   enum kind m_kind;
     230              : };
     231              : 
     232              : /* "ID '=' ID" as a stmt.  */
     233              : 
     234              : struct kv_stmt : public stmt
     235              : {
     236           57 :   kv_stmt (kv_pair kv)
     237           57 :   : m_kv (std::move (kv))
     238              :   {}
     239              : 
     240              :   void print (writer &w) const final override;
     241              : 
     242              :   kv_pair m_kv;
     243              : };
     244              : 
     245              : /* node_id : ID [ port ] */
     246              : 
     247              : enum class compass_pt
     248              : {
     249              :  n, ne, e, se, s, sw, w, nw, c
     250              :  /* "_" clashes with intl macro */
     251              : };
     252              : 
     253              : bool
     254              : get_compass_pt_from_string (const char *str, enum compass_pt &out);
     255              : 
     256              : /* port : ':' ID [ ':' compass_pt ]
     257              :         | ':' compass_pt
     258              : */
     259              : 
     260              : struct port : public ast_node
     261              : {
     262           16 :   port (id id_)
     263           16 :   : m_id (std::make_unique<id> (std::move (id_))),
     264           16 :     m_compass_pt (nullptr)
     265              :   {
     266              :   }
     267              : 
     268           90 :   port (enum compass_pt compass_pt_)
     269           90 :   : m_id (nullptr),
     270           90 :     m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
     271              :   {
     272              :   }
     273              : 
     274            0 :   port (id id_,
     275              :         enum compass_pt compass_pt_)
     276            0 :   : m_id (std::make_unique<id> (std::move (id_))),
     277            0 :     m_compass_pt (std::make_unique<compass_pt> (compass_pt_))
     278              :   {
     279            0 :   }
     280              : 
     281          371 :   port (const port &other)
     282          371 :   : m_id (nullptr),
     283          371 :     m_compass_pt (nullptr)
     284              :   {
     285          371 :     if (other.m_id)
     286           56 :       m_id = std::make_unique<id> (*other.m_id);
     287          371 :     if (other.m_compass_pt)
     288          315 :       m_compass_pt = std::make_unique<enum compass_pt> (*other.m_compass_pt);
     289          371 :   }
     290              : 
     291              :   void print (writer &w) const final override;
     292              : 
     293              :   std::unique_ptr<id> m_id; // would be std::optional
     294              :   std::unique_ptr<enum compass_pt> m_compass_pt; // would be std::optional
     295              : };
     296              : 
     297              : struct node_id : public ast_node
     298              : {
     299         1340 :   node_id (id id_)
     300         1340 :   : m_id (id_),
     301         1336 :     m_port (nullptr)
     302              :   {
     303              :   }
     304          106 :   node_id (id id_, port port_)
     305          106 :   : m_id (id_),
     306          106 :     m_port (std::make_unique<port> (std::move (port_)))
     307              :   {
     308          106 :   }
     309         3607 :   node_id (const node_id &other)
     310         3607 :   : m_id (other.m_id),
     311         3607 :     m_port (nullptr)
     312              :   {
     313         3607 :     if (other.m_port)
     314          265 :       m_port = std::make_unique<port> (*other.m_port);
     315         3607 :   }
     316              : 
     317              :   node_id &operator= (const node_id &other)
     318              :   {
     319              :     m_id = other.m_id;
     320              :     if (other.m_port)
     321              :       m_port = std::make_unique<port> (*other.m_port);
     322              :     else
     323              :       m_port = nullptr;
     324              :     return *this;
     325              :   }
     326              : 
     327              :   void print (writer &w) const final override;
     328              : 
     329              :   id m_id;
     330              :   std::unique_ptr<port> m_port; // would be std::optional
     331              : };
     332              : 
     333              : /* The full grammar for edge_stmt is:
     334              :      edge_stmt  : (node_id | subgraph) edgeRHS [ attr_list ]
     335              :      edgeRHS    : edgeop (node_id | subgraph) [ edgeRHS ]
     336              :    This class support the subsets where all are "node_id", rather than
     337              :    "subgraph", and doesn't yet support "port" giving effectively:
     338              :       node_id (edgeop node_id)+ [ attr_list]
     339              :  */
     340              : 
     341              : struct edge_stmt : public stmt_with_attr_list
     342              : {
     343          723 :   edge_stmt (node_id src_id, node_id dst_id)
     344          723 :   {
     345          723 :     m_node_ids.push_back (std::move (src_id));
     346          723 :     m_node_ids.push_back (std::move (dst_id));
     347          723 :   }
     348              : 
     349              :   void print (writer &w) const final override;
     350              : 
     351              :   std::vector<node_id> m_node_ids; // should have 2 or more elements
     352              : };
     353              : 
     354              : /* [ subgraph [ ID ] ] '{' stmt_list '}' */
     355              : 
     356              : struct subgraph : public stmt
     357              : {
     358           57 :   subgraph (id id_)
     359           57 :   : m_id (id_)
     360              :   {
     361              :   }
     362              : 
     363              :   void print (writer &w) const final override;
     364              : 
     365              :   void add_stmt (std::unique_ptr<stmt> s)
     366              :   {
     367              :     m_stmt_list.add_stmt (std::move (s));
     368              :   }
     369            5 :   void add_attr (id key, id value)
     370              :   {
     371            5 :     m_stmt_list.add_stmt
     372           10 :       (std::make_unique <kv_stmt> (kv_pair (std::move (key),
     373           10 :                                             std::move (value))));
     374            5 :   }
     375              : 
     376              :   id m_id;
     377              :   stmt_list m_stmt_list;
     378              : };
     379              : 
     380              : extern std::unique_ptr<xml::node>
     381              : make_svg_from_graph (const graph &g);
     382              : 
     383              : } // namespace dot
     384              : 
     385              : /* A class for writing .dot output to a pretty_printer with
     386              :    indentation to show nesting.  */
     387              : 
     388              : class graphviz_out : public dot::writer {
     389              :  public:
     390              :   graphviz_out (pretty_printer *pp);
     391              : 
     392              :   void print (const char *fmt, ...)
     393              :     ATTRIBUTE_GCC_PPDIAG(2,3);
     394              :   void println (const char *fmt, ...)
     395              :     ATTRIBUTE_GCC_PPDIAG(2,3);
     396              : 
     397              :   void begin_tr ();
     398              :   void end_tr ();
     399              : 
     400              :   void begin_td ();
     401              :   void end_td ();
     402              : 
     403              :   void begin_trtd ();
     404              :   void end_tdtr ();
     405              : };
     406              : 
     407              : #endif /* GCC_GRAPHVIZ_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.