LCOV - code coverage report
Current view: top level - gcc/diagnostics - digraphs-to-dot.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 82 82
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Converting directed graphs to dot.
       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 "graphviz.h"
      31              : #include "xml.h"
      32              : #include "xml-printer.h"
      33              : #include "diagnostics/digraphs.h"
      34              : #include "diagnostics/digraphs-to-dot.h"
      35              : #include "diagnostics/sarif-sink.h"
      36              : 
      37              : #include "selftest.h"
      38              : 
      39              : namespace diagnostics {
      40              : namespace digraphs {
      41              : namespace to_dot {
      42              : 
      43              : using digraph = diagnostics::digraphs::digraph;
      44              : using digraph_node = diagnostics::digraphs::node;
      45              : using digraph_edge = diagnostics::digraphs::edge;
      46              : 
      47              : // class conversion_to_dot
      48              : 
      49              : std::unique_ptr<dot::graph>
      50           56 : converter::make_dot_graph_from_diagnostic_graph (const digraph &input_graph)
      51              : {
      52           56 :   auto output_graph = std::make_unique<dot::graph> ();
      53              : 
      54           56 :   if (const char *description = input_graph.get_description ())
      55          104 :     output_graph->m_stmt_list.add_attr (dot::id ("label"),
      56          104 :                                         dot::id (description));
      57              : 
      58           56 :   const int num_nodes = input_graph.get_num_nodes ();
      59           56 :   const int num_edges = input_graph.get_num_edges ();
      60              : 
      61              :   /* Determine which nodes have in-edges and out-edges.  */
      62          722 :   for (int i = 0; i < num_edges; ++i)
      63              :     {
      64          666 :       const digraph_edge &input_edge = input_graph.get_edge (i);
      65          666 :       m_nodes_with_edges.insert (&input_edge.get_src_node ());
      66          666 :       m_nodes_with_edges.insert (&input_edge.get_dst_node ());
      67              :     }
      68              : 
      69          118 :   for (int i = 0; i < num_nodes; ++i)
      70              :     {
      71           62 :       const digraph_node &input_node = input_graph.get_node (i);
      72           62 :       auto dot_node_stmt = make_dot_node_from_digraph_node (input_node);
      73           62 :       output_graph->m_stmt_list.add_stmt (std::move (dot_node_stmt));
      74           62 :     }
      75              : 
      76          722 :   for (int i = 0; i < num_edges; ++i)
      77              :     {
      78          666 :       const digraph_edge &input_edge = input_graph.get_edge (i);
      79          666 :       auto dot_edge_stmt = make_dot_edge_from_digraph_edge (input_edge);
      80          666 :       output_graph->m_stmt_list.add_stmt (std::move (dot_edge_stmt));
      81          666 :     }
      82              : 
      83           56 :   return output_graph;
      84              : }
      85              : 
      86              : std::unique_ptr<dot::stmt>
      87          733 : converter::
      88              : make_dot_node_from_digraph_node (const diagnostics::digraphs::node &input_node)
      89              : {
      90          733 :   dot::id dot_id (get_dot_id_for_node (input_node));
      91              : 
      92              :   /* For now, we can only do either edges or children, not both
      93              :      ...but see https://graphviz.org/docs/attrs/compound/  */
      94              : 
      95          733 :   if (has_edges_p (input_node))
      96              :     {
      97          677 :       auto output_node
      98          677 :         = std::make_unique<dot::node_stmt> (std::move (dot_id));
      99          677 :       m_node_map[&input_node] = output_node.get ();
     100          677 :       if (const char *label = input_node.get_label ())
     101          401 :         output_node->set_label (dot::id (label));
     102          677 :       add_any_node_attrs (input_node, *output_node);
     103          677 :       return output_node;
     104          677 :     }
     105              :   else
     106              :     {
     107           56 :       auto output_node = std::make_unique<dot::subgraph> (std::move (dot_id));
     108           56 :       m_node_map[&input_node] = output_node.get ();
     109           56 :       if (const char *label = input_node.get_label ())
     110            5 :         output_node->add_attr (dot::id ("label"), dot::id (label));
     111           56 :       add_any_subgraph_attrs (input_node, *output_node);
     112           56 :       const int num_children = input_node.get_num_children ();
     113          727 :       for (int i = 0; i < num_children; ++i)
     114              :         {
     115          671 :           const digraph_node &input_child = input_node.get_child (i);
     116          671 :           auto dot_child_stmt = make_dot_node_from_digraph_node (input_child);
     117          671 :           output_node->m_stmt_list.add_stmt (std::move (dot_child_stmt));
     118          671 :         }
     119           56 :       return output_node;
     120           56 :     }
     121          733 : }
     122              : 
     123              : std::unique_ptr<dot::edge_stmt>
     124          666 : converter::
     125              : make_dot_edge_from_digraph_edge (const digraph_edge &input_edge)
     126              : {
     127          666 :   const digraph_node &src_dnode = input_edge.get_src_node ();
     128          666 :   const digraph_node &dst_dnode = input_edge.get_dst_node ();
     129          666 :   auto output_edge
     130         1332 :     = std::make_unique<dot::edge_stmt> (get_node_id_for_node (src_dnode),
     131         1998 :                                         get_node_id_for_node (dst_dnode));
     132          666 :   if (const char *label = input_edge.get_label ())
     133          396 :     output_edge->set_label (dot::id (label));
     134          666 :   add_any_edge_attrs (input_edge, *output_edge);
     135          666 :   return output_edge;
     136              : }
     137              : 
     138              : dot::id
     139         2155 : converter::get_dot_id_for_node (const digraph_node &input_node)
     140              : {
     141         2155 :   if (has_edges_p (input_node))
     142         4198 :     return input_node.get_id ();
     143              :   else
     144          112 :     return std::string ("cluster_") + input_node.get_id ();
     145              : }
     146              : 
     147              : dot::node_id
     148         1422 : converter::get_node_id_for_node (const digraph_node &input_node,
     149              :                                          const char *compass_point)
     150              : {
     151         1422 :   dot::id id = get_dot_id_for_node (input_node);
     152         1422 :   if (compass_point)
     153              :     {
     154           90 :       enum dot::compass_pt pt;
     155           90 :       if (dot::get_compass_pt_from_string (compass_point, pt))
     156           90 :         return dot::node_id (id, pt);
     157              :     }
     158         1332 :   return dot::node_id (id);
     159         1422 : }
     160              : 
     161              : bool
     162         2888 : converter::has_edges_p (const digraph_node &input_node)
     163              : {
     164         2888 :   return m_nodes_with_edges.find (&input_node) != m_nodes_with_edges.end ();
     165              : }
     166              : 
     167              : void
     168           11 : converter::add_any_subgraph_attrs (const digraph_node &/*input_node*/,
     169              :                                    dot::subgraph &/*output_subgraph*/)
     170              : {
     171              :   // No-op
     172           11 : }
     173              : 
     174              : void
     175          407 : converter::add_any_node_attrs (const digraph_node &/*input_node*/,
     176              :                                dot::node_stmt &/*output_node*/)
     177              : {
     178              :   // No-op
     179          407 : }
     180              : 
     181              : void
     182          396 : converter::add_any_edge_attrs (const digraph_edge &/*input_edge*/,
     183              :                                dot::edge_stmt &/*output_edge*/)
     184              : {
     185              :   // No-op
     186          396 : }
     187              : 
     188              : std::unique_ptr<converter>
     189           56 : converter::make (const diagnostics::digraphs::digraph &dg)
     190              : {
     191           56 :   if (const char *graph_kind = dg.get_graph_kind ())
     192              :     {
     193              :       // Try to find a suitable converter subclass and use it
     194           45 :       if (strcmp (graph_kind, "cfg") == 0)
     195           45 :         return make_converter_from_cfg ();
     196              :     }
     197           11 :   return std::make_unique<converter> ();
     198              : }
     199              : 
     200              : } // namespace to_dot
     201              : } // namespace digraphs
     202              : } // namespace diagnostics
        

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.