LCOV - code coverage report
Current view: top level - gcc/diagnostics - state-graphs-to-dot.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 65.6 % 279 183
Test Date: 2025-10-18 14:39:06 Functions: 85.7 % 14 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Creating GraphViz .dot files from diagnostic state graphs.
       2                 :             :    Copyright (C) 2025 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                 :             : #define INCLUDE_ALGORITHM
      22                 :             : #define INCLUDE_MAP
      23                 :             : #define INCLUDE_SET
      24                 :             : #define INCLUDE_STRING
      25                 :             : #define INCLUDE_VECTOR
      26                 :             : #include "config.h"
      27                 :             : #include "system.h"
      28                 :             : #include "coretypes.h"
      29                 :             : 
      30                 :             : #include "custom-sarif-properties/state-graphs.h"
      31                 :             : #include "diagnostics/state-graphs.h"
      32                 :             : #include "graphviz.h"
      33                 :             : #include "xml.h"
      34                 :             : #include "xml-printer.h"
      35                 :             : #include "intl.h"
      36                 :             : 
      37                 :             : using namespace diagnostics;
      38                 :             : using namespace diagnostics::state_graphs;
      39                 :             : 
      40                 :             : namespace state_node_properties = custom_sarif_properties::state_graphs::node;
      41                 :             : 
      42                 :             : static int
      43                 :          12 : get_depth (const digraphs::node &n)
      44                 :             : {
      45                 :          12 :   int deepest_child = 0;
      46                 :          23 :   for (size_t i = 0; i < n.get_num_children (); ++i)
      47                 :          11 :       deepest_child = std::max (deepest_child,
      48                 :          11 :                                 get_depth (n.get_child (i)));
      49                 :          12 :   return deepest_child + 1;
      50                 :             : }
      51                 :             : 
      52                 :             : static const char *
      53                 :           2 : get_color_for_dynalloc_state (enum state_node_properties::dynalloc_state_t dynalloc_st)
      54                 :             : {
      55                 :           2 :   switch (dynalloc_st)
      56                 :             :     {
      57                 :           0 :     default:
      58                 :           0 :       gcc_unreachable ();
      59                 :             :       break;
      60                 :             :     case state_node_properties::dynalloc_state_t::unknown:
      61                 :             :     case state_node_properties::dynalloc_state_t::nonnull:
      62                 :             :       return nullptr;
      63                 :             : 
      64                 :           0 :     case state_node_properties::dynalloc_state_t::unchecked:
      65                 :           0 :       return "#ec7a08"; // pf-orange-400
      66                 :             : 
      67                 :           0 :     case state_node_properties::dynalloc_state_t::freed:
      68                 :           0 :       return "#cc0000"; // pf-red-100
      69                 :             :     }
      70                 :             : }
      71                 :             : 
      72                 :             : static void
      73                 :           0 : set_color_for_dynalloc_state (dot::attr_list &attrs,
      74                 :             :                               enum state_node_properties::dynalloc_state_t state)
      75                 :             : {
      76                 :           0 :   if (const char *color = get_color_for_dynalloc_state (state))
      77                 :           0 :     attrs.add (dot::id ("color"), dot::id (color));
      78                 :           0 : }
      79                 :             : 
      80                 :             : class state_diagram : public dot::graph
      81                 :             : {
      82                 :             : public:
      83                 :           1 :   state_diagram (const diagnostics::digraphs::digraph &input_state_graph,
      84                 :             :                  const logical_locations::manager &logical_loc_mgr)
      85                 :           1 :   : m_logical_loc_mgr (logical_loc_mgr)
      86                 :             :   {
      87                 :             :     // "node [shape=plaintext]\n"
      88                 :           1 :     {
      89                 :           1 :       auto attr_stmt
      90                 :           1 :         = std::make_unique<dot::attr_stmt> (dot::attr_stmt::kind::node);
      91                 :           1 :       attr_stmt->m_attrs.add (dot::id ("shape"), dot::id ("plaintext"));
      92                 :           1 :       add_stmt (std::move (attr_stmt));
      93                 :           1 :     }
      94                 :             : 
      95                 :             :     /* Determine which nodes are involved in edges.  */
      96                 :           1 :     for (size_t i = 0; i < input_state_graph.get_num_edges (); ++i)
      97                 :             :       {
      98                 :           0 :         auto &edge = input_state_graph.get_edge (i);
      99                 :           0 :         m_src_nodes.insert (&edge.get_src_node ());
     100                 :           0 :         m_dst_nodes.insert (&edge.get_dst_node ());
     101                 :             :       }
     102                 :             : 
     103                 :             :     /* Recurse down the nodes in the state graph, creating subgraphs
     104                 :             :        and then eventually creating nodes, and recursively
     105                 :             :        creating XML tables, and adding ports for the endpoints of edges
     106                 :             :        where needed.  */
     107                 :             : 
     108                 :           1 :     auto root_cluster
     109                 :           1 :       = std::make_unique<dot::subgraph> (dot::id ("cluster_memory_regions"));
     110                 :           2 :     for (size_t i = 0; i < input_state_graph.get_num_nodes (); ++i)
     111                 :           1 :       on_input_state_node (*root_cluster,
     112                 :           1 :                            input_state_graph.get_node (i));
     113                 :           1 :     add_stmt (std::move (root_cluster));
     114                 :             : 
     115                 :             :     /* Now create dot edges for edges in input_stage_graph.  */
     116                 :           1 :     for (size_t i = 0; i < input_state_graph.get_num_edges (); ++i)
     117                 :             :       {
     118                 :           0 :         auto &edge = input_state_graph.get_edge (i);
     119                 :           0 :         auto &src_node = edge.get_src_node ();
     120                 :           0 :         auto &dst_node = edge.get_dst_node ();
     121                 :             : 
     122                 :           0 :         auto src_port_id = m_src_node_to_port_id.find (&src_node);
     123                 :           0 :         if (src_port_id == m_src_node_to_port_id.end ())
     124                 :           0 :           continue;
     125                 :           0 :         auto dst_port_id = m_dst_node_to_port_id.find (&dst_node);
     126                 :           0 :         if (dst_port_id == m_dst_node_to_port_id.end ())
     127                 :           0 :           continue;
     128                 :             : 
     129                 :           0 :         auto e = std::make_unique<dot::edge_stmt> (src_port_id->second,
     130                 :           0 :                                                    dst_port_id->second);
     131                 :           0 :         set_color_for_dynalloc_state
     132                 :           0 :           (e->m_attrs,
     133                 :             :            dst_node.get_property (state_node_properties::dynalloc_state_prop));
     134                 :             : 
     135                 :           0 :         add_stmt (std::move (e));
     136                 :           0 :       }
     137                 :           1 :   }
     138                 :             : 
     139                 :             : private:
     140                 :             :   struct pending_edge
     141                 :             :   {
     142                 :             :     dot::node_id m_src_node_id;
     143                 :             :     std::string m_dst_region_id;
     144                 :             :   };
     145                 :             : 
     146                 :             :   dot::id
     147                 :             :   get_id_for_region (const char *region_id)
     148                 :             :   {
     149                 :             :     gcc_assert (region_id);
     150                 :             :     return std::string ("cluster_region_") + region_id;
     151                 :             :   }
     152                 :             : 
     153                 :             :   dot::id
     154                 :           2 :   make_id (const diagnostics::digraphs::node &state_node, bool cluster)
     155                 :             :   {
     156                 :           2 :     std::string input_node_id = state_node.get_id ();
     157                 :           2 :     if (cluster)
     158                 :           1 :       return std::string ("cluster_") + input_node_id;
     159                 :             :     else
     160                 :           1 :       return input_node_id;
     161                 :           2 :   }
     162                 :             : 
     163                 :             :   bool
     164                 :           1 :   starts_node_p (const diagnostics::digraphs::node &state_node)
     165                 :             :   {
     166                 :           1 :     switch (state_node.get_property (state_node_properties::kind_prop))
     167                 :             :       {
     168                 :             :       default:
     169                 :             :         return false;
     170                 :             : 
     171                 :           1 :       case state_node_properties::kind_t::stack:
     172                 :             :         /* We want all frames in the stack in the same table,
     173                 :             :            so they are grouped.  */
     174                 :           1 :       case state_node_properties::kind_t::dynalloc_buffer:
     175                 :           1 :       case state_node_properties::kind_t::variable:
     176                 :           1 :         return true;
     177                 :             :       }
     178                 :             :   }
     179                 :             : 
     180                 :             :   const char *
     181                 :           0 :   get_label_for_node (const diagnostics::digraphs::node &state_node)
     182                 :             :   {
     183                 :           0 :     switch (state_node.get_property (state_node_properties::kind_prop))
     184                 :             :       {
     185                 :             :       default:
     186                 :             :         return nullptr;
     187                 :             : 
     188                 :           0 :       case state_node_properties::kind_t::globals:
     189                 :           0 :         return _("Globals");
     190                 :           0 :       case state_node_properties::kind_t::code:
     191                 :           0 :         return _("Code");
     192                 :           0 :       case state_node_properties::kind_t::stack:
     193                 :           0 :         return _("Stack");
     194                 :           0 :       case state_node_properties::kind_t::heap_:
     195                 :           0 :         return _("Heap");
     196                 :             :       }
     197                 :             :   }
     198                 :             : 
     199                 :             :   void
     200                 :           1 :   on_input_state_node (dot::subgraph &parent_subgraph,
     201                 :             :                        const diagnostics::digraphs::node &state_node)
     202                 :             :   {
     203                 :           1 :     dot::id sg_id = make_id (state_node, true);
     204                 :             : 
     205                 :           1 :     if (starts_node_p (state_node))
     206                 :             :       {
     207                 :             :         // Create node with table
     208                 :           1 :         xml::element table ("table", false);
     209                 :           1 :         xml::printer xp (table);
     210                 :           1 :         xp.set_attr ("border", "0");
     211                 :           1 :         xp.set_attr ("cellborder", "1");
     212                 :           1 :         xp.set_attr ("cellspacing", "0");
     213                 :             : 
     214                 :           1 :         const int max_depth = get_depth (state_node);
     215                 :           1 :         const int num_columns = max_depth + 2;
     216                 :             : 
     217                 :           1 :         dot::id id_of_dot_node = make_id (state_node, false);
     218                 :           1 :         on_node_in_table (id_of_dot_node, xp, state_node,
     219                 :             :                           max_depth, 0, num_columns);
     220                 :             : 
     221                 :           1 :         auto node = std::make_unique<dot::node_stmt> (std::move (id_of_dot_node));
     222                 :           2 :         node->m_attrs.add (dot::id ("shape"),
     223                 :           2 :                            dot::id ("plaintext"));
     224                 :             : 
     225                 :             :         // xml must be done by now
     226                 :             : 
     227                 :           1 :         node->m_attrs.add (dot::id ("label"),
     228                 :           1 :                            dot::id (table));
     229                 :             : 
     230                 :           1 :         parent_subgraph.m_stmt_list.add_stmt (std::move (node));
     231                 :           1 :       }
     232                 :             :     else
     233                 :             :       {
     234                 :           0 :         auto child_subgraph = std::make_unique<dot::subgraph> (std::move (sg_id));
     235                 :             : 
     236                 :           0 :         if (const char *label = get_label_for_node (state_node))
     237                 :           0 :           child_subgraph->add_attr (dot::id ("label"), dot::id (label));
     238                 :             : 
     239                 :             :         // recurse:
     240                 :           0 :         for (size_t i = 0; i < state_node.get_num_children (); ++i)
     241                 :           0 :           on_input_state_node (*child_subgraph,
     242                 :           0 :                                state_node.get_child (i));
     243                 :           0 :         parent_subgraph.m_stmt_list.add_stmt (std::move (child_subgraph));
     244                 :           0 :       }
     245                 :           1 :   }
     246                 :             : 
     247                 :             :   enum class style { h1, h2 };
     248                 :             : 
     249                 :             :   void
     250                 :           2 :   add_title_tr (const dot::id &id_of_dot_node,
     251                 :             :                 xml::printer &xp,
     252                 :             :                 int num_columns,
     253                 :             :                 const diagnostics::digraphs::node &state_node,
     254                 :             :                 std::string heading,
     255                 :             :                 enum style styl,
     256                 :             :                 enum state_node_properties::dynalloc_state_t dynalloc_state)
     257                 :             :   {
     258                 :           2 :     xp.push_tag ("tr", true);
     259                 :           2 :     xp.push_tag ("td", false);
     260                 :           2 :     xp.set_attr ("colspan", std::to_string (num_columns));
     261                 :           2 :     xp.set_attr ("cellpadding", "5");
     262                 :             : 
     263                 :           2 :     const char *bgcolor;
     264                 :           2 :     const char *color;
     265                 :           2 :     if (const char *c = get_color_for_dynalloc_state (dynalloc_state))
     266                 :             :       {
     267                 :             :         bgcolor = c;
     268                 :             :         color = "white";
     269                 :             :       }
     270                 :             :     else
     271                 :           2 :       switch (styl)
     272                 :             :         {
     273                 :           0 :         default:
     274                 :           0 :           gcc_unreachable ();
     275                 :             :         case style::h1:
     276                 :             :           // from diagnostics/html-sink.cc: HTML_STYLE .linenum
     277                 :             :           bgcolor = "#0088ce";
     278                 :             :           color = "white";
     279                 :             :           break;
     280                 :           1 :         case style::h2:
     281                 :             :           // from diagnostics/html-sink.cc: HTML_STYLE .events-hdr
     282                 :           1 :           bgcolor = "#393f44"; // pf-black-800
     283                 :           1 :           color = "white";
     284                 :           1 :           break;
     285                 :             :         }
     286                 :             : 
     287                 :           2 :     xp.set_attr ("bgcolor", bgcolor);
     288                 :           2 :     xp.push_tag ("font", false);
     289                 :           2 :     xp.set_attr ("color", color);
     290                 :           2 :     if (heading == "")
     291                 :           0 :       heading = " ";
     292                 :           2 :     xp.add_text (std::move (heading));
     293                 :           2 :     xp.pop_tag ("font");
     294                 :             : 
     295                 :           2 :     maybe_add_dst_port (id_of_dot_node, xp, state_node);
     296                 :             : 
     297                 :           2 :     xp.pop_tag ("td");
     298                 :           2 :     xp.pop_tag ("tr");
     299                 :           2 :   }
     300                 :             : 
     301                 :             :   /* Recursively add <TR> to XP for STATE_NODE and its descendents.  */
     302                 :             :   void
     303                 :          11 :   on_node_in_table (const dot::id &id_of_dot_node,
     304                 :             :                     xml::printer &xp,
     305                 :             :                     const diagnostics::digraphs::node &state_node,
     306                 :             :                     int max_depth,
     307                 :             :                     int depth,
     308                 :             :                     int num_columns)
     309                 :             :   {
     310                 :          11 :     bool recurse = true;
     311                 :          11 :     auto input_node_kind
     312                 :          11 :       = state_node.get_property (state_node_properties::kind_prop);
     313                 :             : 
     314                 :          11 :     switch (input_node_kind)
     315                 :             :       {
     316                 :             :       case state_node_properties::kind_t::padding:
     317                 :             :       case state_node_properties::kind_t::other:
     318                 :             :         return;
     319                 :             : 
     320                 :           1 :       case state_node_properties::kind_t::stack:
     321                 :           1 :         add_title_tr (id_of_dot_node, xp, num_columns, state_node, "Stack",
     322                 :             :                       style::h1,
     323                 :             :                       state_node_properties::dynalloc_state_t::unknown);
     324                 :           1 :         break;
     325                 :           1 :       case state_node_properties::kind_t::stack_frame:
     326                 :           1 :         if (auto logical_loc = state_node.get_logical_loc ())
     327                 :           2 :           if (const char *function
     328                 :           1 :                 = m_logical_loc_mgr.get_short_name (logical_loc))
     329                 :           2 :             add_title_tr (id_of_dot_node, xp, num_columns, state_node,
     330                 :           3 :                           std::string ("Frame: ") + function,
     331                 :             :                           style::h2,
     332                 :             :                           state_node_properties::dynalloc_state_t::unknown);
     333                 :             :         break;
     334                 :           0 :       case state_node_properties::kind_t::dynalloc_buffer:
     335                 :           0 :         {
     336                 :           0 :           enum state_node_properties::dynalloc_state_t dynalloc_st
     337                 :             :             = state_node.get_property
     338                 :           0 :                 (state_node_properties::dynalloc_state_prop);
     339                 :           0 :           const char *extents
     340                 :           0 :             = state_node.get_property (state_node_properties::dynamic_extents);
     341                 :           0 :           const char *type = state_node.get_property (state_node_properties::type);
     342                 :           0 :           pretty_printer pp;
     343                 :           0 :           switch (dynalloc_st)
     344                 :             :             {
     345                 :           0 :             default:
     346                 :           0 :               gcc_unreachable ();
     347                 :             : 
     348                 :           0 :             case state_node_properties::dynalloc_state_t::unknown:
     349                 :           0 :             case state_node_properties::dynalloc_state_t::nonnull:
     350                 :           0 :               if (type)
     351                 :             :                 {
     352                 :           0 :                 if (extents)
     353                 :           0 :                   pp_printf (&pp, "%s (%s byte allocation)",
     354                 :             :                              type, extents);
     355                 :             :                 else
     356                 :           0 :                   pp_printf (&pp, "%s", type);
     357                 :             :                 }
     358                 :             :               else
     359                 :             :                 {
     360                 :           0 :                   if (extents)
     361                 :           0 :                     pp_printf (&pp, "%s byte allocation",
     362                 :             :                                extents);
     363                 :             :                 }
     364                 :             :               break;
     365                 :             : 
     366                 :           0 :             case state_node_properties::dynalloc_state_t::unchecked:
     367                 :           0 :               if (type)
     368                 :             :                 {
     369                 :           0 :                   if (extents)
     370                 :           0 :                     pp_printf (&pp, "%s (unchecked %s byte allocation)",
     371                 :             :                                type, extents);
     372                 :             :                 }
     373                 :             :               else
     374                 :             :                 {
     375                 :           0 :                   if (extents)
     376                 :           0 :                     pp_printf (&pp, "Unchecked %s byte allocation",
     377                 :             :                                extents);
     378                 :             :                 }
     379                 :             :               break;
     380                 :             : 
     381                 :           0 :             case state_node_properties::dynalloc_state_t::freed:
     382                 :             :               // TODO: show deallocator
     383                 :             :               // TODO: show deallocation event
     384                 :           0 :               pp_printf (&pp, "Freed buffer");
     385                 :           0 :               break;
     386                 :             :             }
     387                 :           0 :           maybe_add_dst_port (id_of_dot_node, xp, state_node);
     388                 :           0 :           add_title_tr (id_of_dot_node, xp, num_columns, state_node,
     389                 :           0 :                         pp_formatted_text (&pp),
     390                 :             :                         style::h2,
     391                 :             :                         dynalloc_st);
     392                 :           0 :         }
     393                 :           0 :         break;
     394                 :             : 
     395                 :           8 :       default:
     396                 :           8 :         {
     397                 :           8 :           xp.push_tag ("tr", true);
     398                 :             : 
     399                 :           8 :           maybe_add_dst_port (id_of_dot_node, xp, state_node);
     400                 :             : 
     401                 :           8 :           if (depth > 0)
     402                 :             :             {
     403                 :             :               /* Indent, by create a <td> spanning "depth" columns.  */
     404                 :           8 :               xp.push_tag ("td", false);
     405                 :           8 :               xp.set_attr ("colspan", std::to_string (depth));
     406                 :           8 :               xp.add_text (" "); // graphviz doesn't like <td/>
     407                 :           8 :               xp.pop_tag ("td");
     408                 :             :             }
     409                 :             : 
     410                 :           8 :           switch (input_node_kind)
     411                 :             :             {
     412                 :             :             default:
     413                 :             :               break;
     414                 :           1 :             case state_node_properties::kind_t::variable:
     415                 :           1 :               {
     416                 :           1 :                 const char *name
     417                 :           1 :                   = state_node.get_property (state_node_properties::name);
     418                 :           1 :                 gcc_assert (name);
     419                 :           1 :                 xp.push_tag ("td", false);
     420                 :           1 :                 maybe_add_dst_port (id_of_dot_node, xp, state_node);
     421                 :           1 :                 push_src_text (xp);
     422                 :           1 :                 xp.add_text (name);
     423                 :           2 :                 pop_src_text (xp);
     424                 :           1 :                 xp.pop_tag ("td");
     425                 :             :               }
     426                 :           1 :               break;
     427                 :           4 :             case state_node_properties::kind_t::element:
     428                 :           4 :               {
     429                 :           4 :                 const char *index
     430                 :           4 :                   = state_node.get_property (state_node_properties::index);
     431                 :           4 :                 gcc_assert (index);
     432                 :           4 :                 xp.push_tag ("td", false);
     433                 :           4 :                 maybe_add_dst_port (id_of_dot_node, xp, state_node);
     434                 :           4 :                 push_src_text (xp);
     435                 :           4 :                 xp.add_text ("[");
     436                 :           4 :                 xp.add_text (index);
     437                 :           4 :                 xp.add_text ("]");
     438                 :           8 :                 pop_src_text (xp);
     439                 :           4 :                 xp.pop_tag ("td");
     440                 :             :               }
     441                 :           4 :               break;
     442                 :           3 :             case state_node_properties::kind_t::field:
     443                 :           3 :               {
     444                 :           3 :                 const char *name
     445                 :           3 :                   = state_node.get_property (state_node_properties::name);
     446                 :           3 :                 gcc_assert (name);
     447                 :           3 :                 xp.push_tag ("td", false);
     448                 :           3 :                 maybe_add_dst_port (id_of_dot_node, xp, state_node);
     449                 :           3 :                 push_src_text (xp);
     450                 :           3 :                 xp.add_text (".");
     451                 :           3 :                 xp.add_text (name);
     452                 :           6 :                 pop_src_text (xp);
     453                 :           3 :                 xp.pop_tag ("td");
     454                 :             :               }
     455                 :           3 :               break;
     456                 :             :             }
     457                 :             : 
     458                 :          16 :           if (const char *type
     459                 :           8 :                 = state_node.get_property (state_node_properties::type))
     460                 :             :             {
     461                 :           8 :               xp.push_tag ("td", false);
     462                 :           8 :               xp.set_attr ("align", "right");
     463                 :           8 :               push_src_text (xp);
     464                 :           8 :               xp.add_text (type);
     465                 :          16 :               pop_src_text (xp);
     466                 :           8 :               xp.pop_tag ("td");
     467                 :             :             }
     468                 :             : 
     469                 :          16 :           if (const char *value
     470                 :           8 :                 = state_node.get_property (state_node_properties::value_str))
     471                 :             :             {
     472                 :           1 :               xp.push_tag ("td", false);
     473                 :           1 :               xp.set_attr ("align", "left");
     474                 :           1 :               maybe_add_src_port (id_of_dot_node, xp, state_node);
     475                 :           1 :               push_src_text (xp);
     476                 :           1 :               xp.add_text (value);
     477                 :           2 :               pop_src_text (xp);
     478                 :           1 :               xp.pop_tag ("td");
     479                 :           1 :               recurse = false;
     480                 :             :             }
     481                 :             : 
     482                 :           8 :           xp.pop_tag ("tr");
     483                 :             :         }
     484                 :           8 :         break;
     485                 :             :       }
     486                 :             : 
     487                 :          10 :     if (recurse)
     488                 :          19 :       for (size_t i = 0; i < state_node.get_num_children (); ++i)
     489                 :          10 :         on_node_in_table (id_of_dot_node, xp,
     490                 :          10 :                           state_node.get_child (i),
     491                 :             :                           max_depth, depth + 1, num_columns);
     492                 :             :   }
     493                 :             : 
     494                 :             :   void
     495                 :          17 :   push_src_text (xml::printer &xp)
     496                 :             :   {
     497                 :          17 :     xp.push_tag ("font");
     498                 :          17 :     xp.set_attr ("color", "blue");
     499                 :          17 :   }
     500                 :             : 
     501                 :             :   void
     502                 :          17 :   pop_src_text (xml::printer &xp)
     503                 :             :   {
     504                 :          17 :     xp.pop_tag ("font");
     505                 :             :   }
     506                 :             : 
     507                 :             :   /* If STATE_NODE is in m_src_nodes, add a port to XP for possible
     508                 :             :      incoming edges to use.  */
     509                 :             : 
     510                 :             :   void
     511                 :           1 :   maybe_add_src_port (const dot::id &id_of_dot_node,
     512                 :             :                       xml::printer &xp,
     513                 :             :                       const diagnostics::digraphs::node &state_node)
     514                 :             :   {
     515                 :           1 :     auto iter = m_src_nodes.find (&state_node);
     516                 :           1 :     if (iter == m_src_nodes.end ())
     517                 :           1 :       return;
     518                 :             : 
     519                 :           0 :     dot::id src_id = make_id (state_node, false);
     520                 :           0 :     dot::node_id node_id (id_of_dot_node,
     521                 :           0 :                           dot::port (src_id,
     522                 :           0 :                                      dot::compass_pt::e));
     523                 :           0 :     m_src_node_to_port_id.insert ({&state_node, node_id});
     524                 :           0 :     xp.set_attr ("port", src_id.m_str);
     525                 :           0 :   }
     526                 :             : 
     527                 :             :   /* If STATE_NODE is in m_dst_nodes, add a port to XP for possible
     528                 :             :      incoming edges to use.  */
     529                 :             : 
     530                 :             :   void
     531                 :          18 :   maybe_add_dst_port (const dot::id &id_of_dot_node,
     532                 :             :                       xml::printer &xp,
     533                 :             :                       const diagnostics::digraphs::node &state_node)
     534                 :             :   {
     535                 :          18 :     auto iter = m_dst_nodes.find (&state_node);
     536                 :          18 :     if (iter == m_dst_nodes.end ())
     537                 :          18 :       return;
     538                 :             : 
     539                 :           0 :     dot::id dst_id = make_id (state_node, false);
     540                 :           0 :     dot::node_id node_id (id_of_dot_node,
     541                 :           0 :                           dot::port (dst_id/*,
     542                 :           0 :                                              dot::compass_pt::w*/));
     543                 :           0 :     m_dst_node_to_port_id.insert ({&state_node, node_id});
     544                 :           0 :     xp.set_attr ("port", dst_id.m_str);
     545                 :           0 :   }
     546                 :             : 
     547                 :             : private:
     548                 :             :   const logical_locations::manager &m_logical_loc_mgr;
     549                 :             : 
     550                 :             :   /* All nodes involved in edges (and thus will need a port).  */
     551                 :             :   std::set<const digraphs::node *> m_src_nodes;
     552                 :             :   std::set<const digraphs::node *> m_dst_nodes;
     553                 :             : 
     554                 :             :   std::map<const digraphs::node *, dot::node_id> m_src_node_to_port_id;
     555                 :             :   std::map<const digraphs::node *, dot::node_id> m_dst_node_to_port_id;
     556                 :             : };
     557                 :             : 
     558                 :             : std::unique_ptr<dot::graph>
     559                 :           1 : state_graphs::
     560                 :             : make_dot_graph (const digraphs::digraph &state_graph,
     561                 :             :                 const logical_locations::manager &logical_loc_mgr)
     562                 :             : {
     563                 :           1 :   return std::make_unique<state_diagram> (state_graph, logical_loc_mgr);
     564                 :             : }
        

Generated by: LCOV version 2.1-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.