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"