File indexing completed on 2024-05-12 04:37:59
0001 /* 0002 SPDX-FileCopyrightText: 2002-2005 Roberto Raggi <roberto@kdevelop.org> 0003 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0004 SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de> 0005 SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-only 0008 */ 0009 0010 #include "duchaindumper.h" 0011 0012 #include <QString> 0013 #include <QTextStream> 0014 0015 #include "definitions.h" 0016 #include "ducontext.h" 0017 #include "topducontext.h" 0018 #include "declaration.h" 0019 #include "duchainpointer.h" 0020 #include "identifier.h" 0021 #include "use.h" 0022 #include "problem.h" 0023 #include <serialization/indexedstring.h> 0024 #include "functiondefinition.h" 0025 0026 #include <editor/rangeinrevision.h> 0027 #include <editor/documentrange.h> 0028 0029 namespace { 0030 QDebug fromTextStream(const QTextStream& out) 0031 { 0032 if (out.device()) 0033 return { 0034 out.device() 0035 }; return { 0036 out.string() 0037 }; 0038 } 0039 0040 } 0041 0042 namespace KDevelop { 0043 QString typeToString(DUContext::ContextType type) 0044 { 0045 switch (type) { 0046 case DUContext::Global: return QStringLiteral("Global"); 0047 case DUContext::Namespace: return QStringLiteral("Namespace"); 0048 case DUContext::Class: return QStringLiteral("Class"); 0049 case DUContext::Function: return QStringLiteral("Function"); 0050 case DUContext::Template: return QStringLiteral("Template"); 0051 case DUContext::Enum: return QStringLiteral("Enum"); 0052 case DUContext::Helper: return QStringLiteral("Helper"); 0053 case DUContext::Other: return QStringLiteral("Other"); 0054 } 0055 Q_ASSERT(false); 0056 return QString(); 0057 } 0058 0059 class DUChainDumperPrivate 0060 { 0061 public: 0062 DUChainDumperPrivate() 0063 : m_indent(0) 0064 {} 0065 0066 void dumpProblems(TopDUContext* top, QTextStream& out); 0067 void dump(DUContext* context, int allowedDepth, bool isFromImport, QTextStream& out); 0068 0069 int m_indent; 0070 DUChainDumper::Features m_features; 0071 QSet<DUContext*> m_visitedContexts; 0072 }; 0073 0074 DUChainDumper::DUChainDumper(Features features) 0075 : d_ptr(new DUChainDumperPrivate) 0076 { 0077 Q_D(DUChainDumper); 0078 0079 d->m_features = features; 0080 } 0081 0082 DUChainDumper::~DUChainDumper() 0083 { 0084 } 0085 0086 class Indent 0087 { 0088 public: 0089 explicit Indent(int level) : m_level(level) {} 0090 0091 friend QDebug& operator<<(QDebug& debug, const Indent& ind) 0092 { 0093 for (int i = 0; i < ind.m_level; i++) { 0094 debug.nospace() << ' '; 0095 } 0096 0097 return debug.space(); 0098 } 0099 0100 private: 0101 int m_level; 0102 }; 0103 0104 void DUChainDumperPrivate::dumpProblems(TopDUContext* top, QTextStream& out) 0105 { 0106 QDebug qout = fromTextStream(out); 0107 0108 if (!top->problems().isEmpty()) { 0109 qout << top->problems().size() << "problems encountered:" << Qt::endl; 0110 const auto problems = top->problems(); 0111 for (const ProblemPointer& p : problems) { 0112 qout << Indent(m_indent * 2) << p->description() << p->explanation() << p->finalLocation() << Qt::endl; 0113 } 0114 0115 qout << Qt::endl; 0116 } 0117 } 0118 0119 void DUChainDumperPrivate::dump(DUContext* context, int allowedDepth, bool isFromImport, QTextStream& out) 0120 { 0121 QDebug qout = fromTextStream(out); 0122 0123 qout << Indent(m_indent * 2) << (isFromImport ? " ==import==>" : "") 0124 << (dynamic_cast<TopDUContext*>(context) ? "Top-Context" : "Context") << typeToString(context->type()) 0125 << "(owner: " << context->owner() << ")" << context << context->localScopeIdentifier() << "[" 0126 << context->scopeIdentifier(true) << "]" << context->range().castToSimpleRange() 0127 << (dynamic_cast<TopDUContext*>(context) ? static_cast<TopDUContext*>(context)->url().byteArray() : "") 0128 << Qt::endl; 0129 0130 if (m_visitedContexts.contains(context)) { 0131 qout << Indent((m_indent + 2) * 2) << "(Skipping" << context->scopeIdentifier(true) 0132 << "because it was already printed)" << Qt::endl; 0133 return; 0134 } 0135 0136 m_visitedContexts.insert(context); 0137 0138 auto top = context->topContext(); 0139 if (allowedDepth >= 0) { 0140 const auto localDeclarations = context->localDeclarations(top); 0141 for (Declaration* dec : localDeclarations) { 0142 //IdentifiedType* idType = dynamic_cast<IdentifiedType*>(dec->abstractType().data()); 0143 0144 qout << Indent((m_indent + 2) * 2) << "Declaration:" << dec->toString() << "[" << dec->qualifiedIdentifier() 0145 << "]" << dec << "(internal ctx:" << dec->internalContext() << ")" << dec->range().castToSimpleRange() 0146 << "," 0147 << (dec->isDefinition() ? "defined, " : (FunctionDefinition::definition(dec) ? "" : "no definition, ")) 0148 << dec->uses().count() << "use(s)." << Qt::endl; 0149 if (FunctionDefinition::definition(dec)) { 0150 qout << Indent((m_indent + 2) * 2 + 1) 0151 << "Definition:" << FunctionDefinition::definition(dec)->range().castToSimpleRange() << Qt::endl; 0152 } 0153 const auto uses = dec->uses(); 0154 for (auto it = uses.constBegin(); it != uses.constEnd(); ++it) { 0155 qout << Indent((m_indent + 3) * 2) << "File:" << it.key().str() << Qt::endl; 0156 for (const RangeInRevision range : qAsConst(*it)) { 0157 qout << Indent((m_indent + 4) * 2) << "Use:" << range.castToSimpleRange() << Qt::endl; 0158 } 0159 } 0160 } 0161 } else { 0162 qout << Indent((m_indent + 2) * 2) << context->localDeclarations(top).count() << "Declarations," 0163 << context->childContexts().size() << "child-contexts" << Qt::endl; 0164 } 0165 0166 ++m_indent; 0167 { 0168 /* 0169 const auto importedParentContexts = context->importedParentContexts(); 0170 for (const DUContext::Import& parent : importedParentContexts) { 0171 DUContext* import = parent.context(top); 0172 if(!import) { 0173 qout << Indent((m_indent+2) * 2+1) << "Could not get parent, is it registered in the DUChain?" << Qt::endl; 0174 continue; 0175 } 0176 0177 dump(import, allowedDepth-1, true, out); 0178 } 0179 */ 0180 0181 const auto childContexts = context->childContexts(); 0182 for (DUContext* child : childContexts) { 0183 dump(child, allowedDepth - 1, false, out); 0184 } 0185 } 0186 --m_indent; 0187 } 0188 0189 void DUChainDumper::dump(DUContext* context, int allowedDepth, QTextStream& out) 0190 { 0191 Q_D(DUChainDumper); 0192 0193 d->m_visitedContexts.clear(); 0194 0195 if (!context) { 0196 out << "Error: Null context" << Qt::endl; 0197 return; 0198 } 0199 0200 auto top = context->topContext(); 0201 if (d->m_features.testFlag(DumpProblems)) { 0202 d->dumpProblems(top, out); 0203 } 0204 if (d->m_features.testFlag(DumpContext)) { 0205 d->dump(context, allowedDepth, false, out); 0206 } 0207 } 0208 0209 void DUChainDumper::dump(DUContext* context, int allowedDepth) 0210 { 0211 QTextStream out(stdout); 0212 dump(context, allowedDepth, out); 0213 } 0214 0215 }