Warning, file /kdevelop/kdev-php/duchain/tests/duchaintestbase.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "duchaintestbase.h"
0009 
0010 #include <QtTest>
0011 
0012 #include <language/duchain/parsingenvironment.h>
0013 #include <language/duchain/duchainlock.h>
0014 #include <language/duchain/topducontext.h>
0015 #include <language/duchain/duchaindumper.h>
0016 #include <language/codegen/coderepresentation.h>
0017 
0018 #include <serialization/indexedstring.h>
0019 
0020 #include <tests/autotestshell.h>
0021 #include <tests/testcore.h>
0022 
0023 #include "../completion/codemodelitem.h"
0024 
0025 #include "../builders/declarationbuilder.h"
0026 #include "../builders/usebuilder.h"
0027 
0028 #include "../dumptypes.h"
0029 #include "../../parser/parsesession.h"
0030 #include "../../parser/phpdebugvisitor.h"
0031 
0032 #include "../helper.h"
0033 
0034 using namespace KDevelop;
0035 
0036 namespace Php
0037 {
0038 
0039 void DUChainTestBase::initTestCase()
0040 {
0041     AutoTestShell::init();
0042     TestCore::initialize(Core::NoUi);
0043 
0044     DUChain::self()->disablePersistentStorage();
0045     CodeRepresentation::setDiskChangesForbidden(true);
0046 
0047     //yeah... adding a testcase here is kinda strange, but anyways - we have to check for special
0048     //handling of the internal functions file
0049     //see e.g. testDeclarationReturnTypeDocBlock
0050     QByteArray content("<?php "
0051                         "class Exception {} "
0052                         //test start
0053                         "/** @return Exception **/ function should_return_exception() {}\n"
0054                        "class internal_test_class {/** @return Exception **/ function should_return_exception() {}}\n"
0055                         // test end
0056                        "function define() {} function substr() {} class stdClass {}\n"
0057                        "/**\n * @superglobal\n **/\n$_GET = array();\n"
0058                        "interface testInterface {}\n");
0059     content.append("interface Iterator { function rewind(); function current(); function key(); function next(); function valid(); } ");
0060     QVERIFY(!internalFunctionFile().isEmpty());
0061     TopDUContext* ctx = parseAdditionalFile(internalFunctionFile(), content);
0062     QVERIFY(ctx);
0063 
0064     DUChainWriteLocker lock;
0065     QVERIFY(ctx->problems().isEmpty());
0066 
0067     // set features and modification revision, to prevent test cases that use
0068     // the full language plugin from re-parsing the big internal function file
0069     ctx->setFeatures(TopDUContext::AllDeclarationsAndContexts);
0070     ParsingEnvironmentFilePointer file = ctx->parsingEnvironmentFile();
0071     QVERIFY(file);
0072     file->setModificationRevision(ModificationRevision::revisionForFile(internalFunctionFile()));
0073     DUChain::self()->updateContextEnvironment(ctx, file.data());
0074 }
0075 
0076 void DUChainTestBase::cleanupTestCase()
0077 {
0078     TestCore::shutdown();
0079 }
0080 
0081 CompletionTreeItemPointer DUChainTestBase::searchDeclaration(QList<CompletionTreeItemPointer> items, Declaration* declaration)
0082 {
0083     foreach(const CompletionTreeItemPointer &item, items) {
0084         if (item->declaration().data() == declaration) {
0085             return item;
0086         }
0087     }
0088     return CompletionTreeItemPointer();
0089 }
0090 
0091 bool DUChainTestBase::hasImportedParentContext(TopDUContext* top, DUContext* lookingFor)
0092 {
0093     qDebug() << "this topcontext has " << top->importedParentContexts().count() << " imported parent contexts"
0094     << "\n we are looking for: " << lookingFor->url().byteArray();
0095     foreach(const DUContext::Import &import, top->importedParentContexts()) {
0096         if (import.context(top)) {
0097             qDebug() << import.context(top)->url().byteArray();
0098         }
0099         if (import.context(top) == lookingFor) {
0100             return true;
0101         }
0102     }
0103     return false;
0104 }
0105 
0106 TopDUContext* DUChainTestBase::parseAdditionalFile(const IndexedString& fileName, const QByteArray& contents)
0107 {
0108     ParseSession session;
0109     session.setContents(contents);
0110     StartAst* ast = nullptr;
0111     if (!session.parse(&ast)) qFatal("can't parse");
0112 
0113     EditorIntegrator editor(&session);
0114     session.setCurrentDocument(fileName);
0115     DeclarationBuilder declarationBuilder(&editor);
0116     TopDUContext* top = declarationBuilder.build(fileName, ast);
0117 
0118     if ( fileName != internalFunctionFile() ) {
0119         UseBuilder useBuilder(&editor);
0120         useBuilder.buildUses(ast);
0121     }
0122 
0123     if (!session.problems().isEmpty()) {
0124         DUChainWriteLocker lock;
0125         foreach( const ProblemPointer& p, session.problems() ) {
0126             top->addProblem(p);
0127         }
0128     }
0129 
0130     return top;
0131 }
0132 
0133 TopDUContext* DUChainTestBase::parse(const QByteArray& unit, DumpAreas dump,
0134                                      QUrl url, TopDUContext* update)
0135 {
0136     if (dump)
0137         qDebug() << "==== Beginning new test case...:\n" << unit;
0138 
0139     ParseSession session;
0140     session.setContents(unit);
0141     StartAst* ast = nullptr;
0142     if (!session.parse(&ast)) {
0143         qDebug() << "Parse failed";
0144         return nullptr;
0145     }
0146 
0147     if (dump & DumpAST) {
0148         qDebug() << "===== AST:";
0149         DebugVisitor debugVisitor(session.tokenStream(), session.contents());
0150         debugVisitor.visitNode(ast);
0151     }
0152 
0153     static int testNumber = 0;
0154     if (url.isEmpty()) {
0155         url = QUrl(QStringLiteral("file:///internal/%1").arg(testNumber++));
0156     }
0157 
0158     EditorIntegrator editor(&session);
0159     session.setCurrentDocument(IndexedString(url));
0160     DeclarationBuilder declarationBuilder(&editor);
0161     TopDUContext* top = declarationBuilder.build(session.currentDocument(), ast, ReferencedTopDUContext(update));
0162 
0163     if (!session.problems().isEmpty()) {
0164         DUChainWriteLocker lock;
0165         foreach( const ProblemPointer& p, session.problems() ) {
0166             top->addProblem(p);
0167         }
0168     }
0169 
0170     if ( IndexedString(url) != internalFunctionFile() ) {
0171         UseBuilder useBuilder(&editor);
0172         useBuilder.buildUses(ast);
0173     }
0174 
0175     if (dump & DumpDUChain) {
0176         qDebug() << "===== DUChain:";
0177 
0178         DUChainWriteLocker lock(DUChain::lock());
0179         DUChainDumper d;
0180         d.dump(top);
0181     }
0182 
0183     if (dump & DumpType) {
0184         qDebug() << "===== Types:";
0185         DUChainWriteLocker lock(DUChain::lock());
0186         DumpTypes dt;
0187         foreach(const AbstractType::Ptr& type, declarationBuilder.topTypes()) {
0188             dt.dump(type.data());
0189         }
0190     }
0191 
0192 
0193 
0194     if (dump)
0195         qDebug() << "===== Finished test case.";
0196 
0197     return top;
0198 }
0199 }
0200 
0201 #include "moc_duchaintestbase.cpp"