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

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.