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 }