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 }