File indexing completed on 2024-05-12 04:38:01
0001 /* 0002 SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "dumpdotgraph.h" 0008 0009 #include "ducontext.h" 0010 #include "topducontext.h" 0011 #include "declaration.h" 0012 #include "duchainpointer.h" 0013 #include "parsingenvironment.h" 0014 #include "identifier.h" 0015 #include "functiondefinition.h" 0016 0017 namespace KDevelop { 0018 QString shortLabel(KDevelop::DUContext* context) 0019 { 0020 return QStringLiteral("q%1").arg(( quint64 )context); 0021 } 0022 0023 QString shortLabel(KDevelop::Declaration* declaration) 0024 { 0025 return QStringLiteral("q%1").arg(( quint64 )declaration); 0026 } 0027 0028 QString rangeToString(const KTextEditor::Range& r) 0029 { 0030 return QStringLiteral("%1:%2->%3:%4").arg(r.start().line()).arg(r.start().column()).arg(r.end().line()).arg( 0031 r.end().column()); 0032 } 0033 0034 class DumpDotGraphPrivate 0035 { 0036 public: 0037 0038 QString dotGraphInternal(KDevelop::DUContext* contex, bool isMaster, bool shortened); 0039 0040 void addDeclaration(QTextStream& stream, Declaration* decl); 0041 0042 QMap<QUrl, QString> m_hadVersions; 0043 QMap<KDevelop::DUChainBase*, bool> m_hadObjects; 0044 TopDUContext* m_topContext; 0045 }; 0046 0047 QString DumpDotGraph::dotGraph(KDevelop::DUContext* context, bool shortened) 0048 { 0049 Q_D(DumpDotGraph); 0050 0051 d->m_hadObjects.clear(); 0052 d->m_hadVersions.clear(); 0053 d->m_topContext = context->topContext(); ///@todo maybe get this as a parameter 0054 return d->dotGraphInternal(context, true, shortened); 0055 } 0056 0057 DumpDotGraph::DumpDotGraph() 0058 : d_ptr(new DumpDotGraphPrivate()) 0059 { 0060 } 0061 0062 DumpDotGraph::~DumpDotGraph() = default; 0063 0064 void DumpDotGraphPrivate::addDeclaration(QTextStream& stream, Declaration* dec) 0065 { 0066 if (m_hadObjects.contains(dec)) 0067 return; 0068 0069 m_hadObjects[dec] = true; 0070 0071 Declaration* declarationForDefinition = nullptr; 0072 if (dynamic_cast<FunctionDefinition*>(dec)) 0073 declarationForDefinition = static_cast<FunctionDefinition*>(dec)->declaration(m_topContext); 0074 0075 if (!declarationForDefinition) { 0076 //Declaration 0077 stream << shortLabel(dec) << 0078 "[shape=box, label=\"" << 0079 dec->toString() << " [" << 0080 dec->qualifiedIdentifier().toString() << "]" << " " << 0081 rangeToString(dec->range().castToSimpleRange()) << "\"];\n"; 0082 stream << shortLabel(dec->context()) << " -> " << shortLabel(dec) << "[color=green];\n"; 0083 if (dec->internalContext()) 0084 stream << shortLabel(dec) << " -> " << shortLabel(dec->internalContext()) << 0085 "[label=\"internal\", color=blue];\n"; 0086 } else { 0087 //Definition 0088 stream << shortLabel(dec) << "[shape=regular,color=yellow,label=\"" << declarationForDefinition->toString() << 0089 " " << rangeToString(dec->range().castToSimpleRange()) << "\"];\n"; 0090 stream << shortLabel(dec->context()) << " -> " << shortLabel(dec) << ";\n"; 0091 0092 stream << shortLabel(dec) << " -> " << shortLabel(declarationForDefinition) << 0093 "[label=\"defines\",color=green];\n"; 0094 addDeclaration(stream, declarationForDefinition); 0095 0096 if (dec->internalContext()) 0097 stream << shortLabel(dec) << " -> " << shortLabel(dec->internalContext()) << 0098 "[label=\"internal\", color=blue];\n"; 0099 } 0100 } 0101 0102 QString DumpDotGraphPrivate::dotGraphInternal(KDevelop::DUContext* context, bool isMaster, bool shortened) 0103 { 0104 if (m_hadObjects.contains(context)) 0105 return QString(); 0106 0107 m_hadObjects[context] = true; 0108 0109 QTextStream stream; 0110 QString ret; 0111 stream.setString(&ret, QIODevice::WriteOnly); 0112 0113 if (isMaster) 0114 stream << "Digraph chain {\n"; 0115 0116 QString shape = QStringLiteral("parallelogram"); 0117 //QString shape = "box"; 0118 QString label = QStringLiteral("unknown"); 0119 0120 if (dynamic_cast<TopDUContext*>(context)) { 0121 auto* topCtx = static_cast<TopDUContext*>(context); 0122 if (topCtx->parsingEnvironmentFile()) { 0123 QUrl url = topCtx->parsingEnvironmentFile()->url().toUrl(); 0124 const QString fileName = url.fileName(); 0125 QString file = url.toDisplayString(QUrl::PreferLocalFile); 0126 if (topCtx->parsingEnvironmentFile() && topCtx->parsingEnvironmentFile()->isProxyContext()) 0127 url.setPath(url.path() + QLatin1String("/_[proxy]_")); 0128 0129 //Find the context this one is derived from. If there is one, connect it with a line, and shorten the url. 0130 if (m_hadVersions.contains(url)) { 0131 stream << shortLabel(context) << " -> " << m_hadVersions[url] << "[color=blue,label=\"version\"];\n"; 0132 file = fileName; 0133 } else { 0134 m_hadVersions[url] = shortLabel(context); 0135 } 0136 0137 label = file; 0138 0139 if (topCtx->importers().count() != 0) 0140 label += QStringLiteral(" imported by %1").arg(topCtx->importers().count()); 0141 } else { 0142 label = QStringLiteral("unknown file"); 0143 } 0144 if (topCtx->parsingEnvironmentFile() && topCtx->parsingEnvironmentFile()->isProxyContext()) 0145 label = QLatin1String("Proxy-context ") + label; 0146 } else { 0147 label = /*"context " + */ context->localScopeIdentifier().toString(); 0148 label += QLatin1Char(' ') + rangeToString(context->range().castToSimpleRange()); 0149 } 0150 0151 //label = QStringLiteral("%1 ").arg((size_t)context) + label; 0152 0153 if (isMaster && !dynamic_cast<TopDUContext*>(context)) { 0154 //Also draw contexts that import this one 0155 const auto importers = context->importers(); 0156 for (DUContext* ctx : importers) { 0157 stream << dotGraphInternal(ctx, false, true); 0158 } 0159 } 0160 const auto importedParentContexts = context->importedParentContexts(); 0161 for (const DUContext::Import& parent : importedParentContexts) { 0162 if (parent.context(m_topContext)) { 0163 stream << dotGraphInternal(parent.context(m_topContext), false, true); 0164 QString label = QStringLiteral("imports"); 0165 if ((!dynamic_cast<TopDUContext*>(parent.context(m_topContext)) || !dynamic_cast<TopDUContext*>(context)) && 0166 !(parent.context(m_topContext)->url() == context->url())) { 0167 label += QLatin1String(" from ") + parent.context(m_topContext)->url().toUrl().fileName() 0168 + QLatin1String(" to ") + context->url().toUrl().fileName(); 0169 } 0170 0171 stream << shortLabel(context) << QLatin1String(" -> ") << shortLabel(parent.context(m_topContext)) << 0172 QLatin1String("[style=dotted,label=\"") << label << QLatin1String("\"];\n"); 0173 } 0174 } 0175 0176 const auto childContexts = context->childContexts(); 0177 if (!childContexts.isEmpty()) { 0178 label += QStringLiteral(", %1 C.").arg(childContexts.count()); 0179 } 0180 0181 if (!shortened) { 0182 for (DUContext* child : childContexts) { 0183 stream << dotGraphInternal(child, false, false); 0184 stream << shortLabel(context) << QLatin1String(" -> ") << shortLabel(child) << QLatin1String( 0185 "[style=dotted,color=green];\n"); 0186 } 0187 } 0188 0189 const auto localDeclarations = context->localDeclarations(); 0190 if (!localDeclarations.isEmpty()) { 0191 label += QStringLiteral(", %1 D.").arg(localDeclarations.count()); 0192 } 0193 0194 if (!shortened) { 0195 for (Declaration* dec : localDeclarations) { 0196 addDeclaration(stream, dec); 0197 } 0198 } 0199 0200 if (context->owner()) { 0201 addDeclaration(stream, context->owner()); 0202 } 0203 0204 stream << shortLabel(context) << "[shape=" << shape << ",label=\"" << label << "\"" << 0205 (isMaster ? QLatin1String("color=red") : QLatin1String("color=blue")) << "];\n"; 0206 0207 if (isMaster) 0208 stream << "}\n"; 0209 0210 return ret; 0211 } 0212 }