File indexing completed on 2024-04-28 04:34:21

0001 /***************************************************************************
0002  *   Copyright 2009 Sandro Andrade <sandroandrade@kde.org>                 *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU Library General Public License as       *
0006  *   published by the Free Software Foundation; either version 2 of the    *
0007  *   License, or (at your option) any later version.                       *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU Library General Public     *
0015  *   License along with this program; if not, write to the                 *
0016  *   Free Software Foundation, Inc.,                                       *
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0018  ***************************************************************************/
0019 
0020 #include "dotcontrolflowgraph.h"
0021 
0022 #include <cstdio>
0023 
0024 #include <language/duchain/declaration.h>
0025 
0026 namespace {
0027     // C interface takes char*, so to avoid deprecated cast and/or undefined behaviour,
0028     // defined the needed constants here.
0029     static char SUFFIX[] = "dot";
0030     static char GRAPH_NAME[] = "Root_Graph";
0031     static char LABEL[] = "label";
0032     static char EMPTY[] = "";
0033     static char FILLED[] = "filled";
0034     static char FILLCOLOR[] = "fillcolor";
0035     static char SHAPE[] = "shape";
0036     static char STYLE[] = "style";
0037     static char BOX[] = "box";
0038 }
0039 
0040 QMutex DotControlFlowGraph::mutex;
0041 
0042 DotControlFlowGraph::DotControlFlowGraph() : m_rootGraph(0)
0043 {
0044     m_gvc = gvContext();
0045 }
0046 
0047 DotControlFlowGraph::~DotControlFlowGraph()
0048 {
0049     gvFreeContext(m_gvc);
0050 }
0051 
0052 void DotControlFlowGraph::graphDone()
0053 {
0054     if (m_rootGraph)
0055     {
0056         if (mutex.tryLock())
0057         {
0058             gvLayout(m_gvc, m_rootGraph, SUFFIX);
0059             gvFreeLayout(m_gvc, m_rootGraph);
0060             mutex.unlock();
0061             emit loadLibrary(m_rootGraph);
0062         }
0063     }
0064 }
0065 
0066 void DotControlFlowGraph::clearGraph()
0067 {
0068     if (m_rootGraph)
0069     {
0070         gvFreeLayout(m_gvc, m_rootGraph);
0071         agclose(m_rootGraph);
0072         m_rootGraph = 0;
0073     }
0074 
0075     m_namedGraphs.clear();
0076     m_rootGraph = agopen(GRAPH_NAME, Agdirected, NULL);
0077     graphDone();
0078 }
0079 
0080 void DotControlFlowGraph::exportGraph(const QString &fileName)
0081 {
0082     if (m_rootGraph)
0083     {
0084         gvLayout(m_gvc, m_rootGraph, SUFFIX);
0085         gvRenderFilename(m_gvc, m_rootGraph, fileName.right(fileName.size()-fileName.lastIndexOf('.')-1).toUtf8().data(), fileName.toUtf8().data());
0086         gvFreeLayout(m_gvc, m_rootGraph);
0087     }
0088 }
0089 
0090 void DotControlFlowGraph::prepareNewGraph()
0091 {
0092     clearGraph();
0093 }
0094 
0095 void DotControlFlowGraph::foundRootNode(const QStringList &containers, const QString &label)
0096 {
0097     Agraph_t *graph = m_rootGraph;
0098     if (!m_rootGraph) {
0099         // This shouldn't happen, as the graph should be generated before this function
0100         // is connected.
0101         Q_ASSERT(false);
0102         return;
0103     }
0104     QString absoluteContainer;
0105     foreach (const QString& container, containers)
0106     {
0107         absoluteContainer += container;
0108         graph = m_namedGraphs[absoluteContainer] = agsubg(graph, ("cluster_" + absoluteContainer).toUtf8().data(), 1);
0109         agsafeset(graph, LABEL, container.toUtf8().data(), EMPTY);
0110     }
0111 
0112     Agnode_t *node = agnode(graph, (containers.join("") + label).toUtf8().data(), 1);
0113     agsafeset(node, SHAPE, BOX, EMPTY);
0114     QColor c = colorFromQualifiedIdentifier(label);
0115     char color[8];
0116     std::sprintf (color, "#%02x%02x%02x", c.red(), c.green(), c.blue());
0117     agsafeset(node, STYLE, FILLED, EMPTY);
0118     agsafeset(node, FILLCOLOR, color, EMPTY);
0119     agsafeset(node, LABEL, label.toUtf8().data(), EMPTY);
0120 }
0121 
0122 void DotControlFlowGraph::foundFunctionCall(const QStringList &sourceContainers, const QString &source, const QStringList &targetContainers, const QString &target)
0123 {
0124     if (!m_rootGraph) {
0125         // This shouldn't happen, as the graph should be generated before this function
0126         // is connected.
0127         Q_ASSERT(false);
0128         return;
0129     }
0130     Agraph_t *sourceGraph, *targetGraph, *newGraph;
0131     sourceGraph = targetGraph = m_rootGraph;
0132     QString absoluteContainer;
0133 
0134     foreach (const QString& container, sourceContainers)
0135     {
0136         Agraph_t *previousGraph = sourceGraph;
0137         absoluteContainer += container;
0138         if (!m_namedGraphs.contains(absoluteContainer))
0139         {
0140             newGraph = agsubg(previousGraph, ("cluster_" + absoluteContainer).toUtf8().data(), 1);
0141             m_namedGraphs.insert(absoluteContainer, newGraph);
0142             agsafeset(newGraph, LABEL, container.toUtf8().data(), EMPTY);
0143         }
0144         sourceGraph = m_namedGraphs[absoluteContainer];
0145     }
0146     absoluteContainer.clear();
0147     foreach (const QString& container, targetContainers)
0148     {
0149         Agraph_t *previousGraph = targetGraph;
0150         absoluteContainer += container;
0151         if (!m_namedGraphs.contains(absoluteContainer))
0152         {
0153             Agraph_t *newGraph = agsubg(previousGraph, ("cluster_" + absoluteContainer).toUtf8().data(), 1);
0154             m_namedGraphs.insert(absoluteContainer, newGraph);
0155             agsafeset(newGraph, LABEL, container.toUtf8().data(), EMPTY);
0156         }
0157         targetGraph = m_namedGraphs[absoluteContainer];
0158     }
0159 
0160     Agnode_t* src = agnode(sourceGraph, (sourceContainers.join("") + source).toUtf8().data(), 1);
0161     Agnode_t* tgt = agnode(targetGraph, (targetContainers.join("") + target).toUtf8().data(), 1);
0162 
0163     char color[8];
0164     char ID[] = "id";
0165 
0166     QColor c = colorFromQualifiedIdentifier(source);
0167     std::sprintf (color, "#%02x%02x%02x", c.red(), c.green(), c.blue());
0168     agsafeset(src, STYLE, FILLED, EMPTY);
0169     agsafeset(src, FILLCOLOR, color, EMPTY);
0170     agsafeset(src, SHAPE, BOX, EMPTY);
0171     agsafeset(src, LABEL, source.toUtf8().data(), EMPTY);
0172 
0173     c = colorFromQualifiedIdentifier(target);
0174     std::sprintf (color, "#%02x%02x%02x", c.red(), c.green(), c.blue());
0175     agsafeset(tgt, STYLE, FILLED, EMPTY);
0176     agsafeset(tgt, FILLCOLOR, color, EMPTY);
0177     agsafeset(tgt, SHAPE, BOX, EMPTY);
0178     agsafeset(tgt, LABEL, target.toUtf8().data(), EMPTY);
0179 
0180     Agedge_t* edge;
0181     if (sourceGraph == targetGraph)
0182         edge = agedge(sourceGraph, src, tgt, NULL, 1);
0183     else
0184         edge = agedge(m_rootGraph, src, tgt, NULL, 1);
0185     agsafeset(edge, ID, (source + "->" + target).toUtf8().data(), EMPTY);
0186 }
0187 
0188 const QColor& DotControlFlowGraph::colorFromQualifiedIdentifier(const QString &label)
0189 {
0190     if (m_colorMap.contains(label.split("::")[0]))
0191         return m_colorMap[label.split("::")[0]];
0192     else
0193         return m_colorMap[label.split("::")[0]] = QColor::fromHsv(qrand() % 256, 255, 190);
0194 }