/* This file is part of KDevelop SPDX-FileCopyrightText: 2010 Niko Sams SPDX-FileCopyrightText: 2011 Milian Wolff SPDX-License-Identifier: LGPL-2.0-only */ #include "duchain_multiplefiles.h" #include #include #include #include #include #include #include #include #include #include QTEST_MAIN(Php::TestDUChainMultipleFiles) using namespace KDevelop; using namespace Php; void TestDUChainMultipleFiles::initTestCase() { DUChainTestBase::initTestCase(); TestCore* core = dynamic_cast(ICore::self()); Q_ASSERT(core); m_projectController = new TestProjectController(core); core->setProjectController(m_projectController); } void TestDUChainMultipleFiles::testImportsGlobalFunction() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f1(QStringLiteral("imports(f1.topContext(), CursorInRevision(0, 0))); } void TestDUChainMultipleFiles::testImportsBaseClassNotYetParsed() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f2(QStringLiteral("imports(f1.topContext(), CursorInRevision(0, 0))); QVERIFY(ICore::self()->languageController()->backgroundParser()->queuedCount() == 0); } void TestDUChainMultipleFiles::testNonExistingBaseClass() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f1(QStringLiteral("languageController()->backgroundParser()->queuedCount() == 0); } void TestDUChainMultipleFiles::testImportsGlobalFunctionNotYetParsed() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f2(QStringLiteral("imports(f1.topContext(), CursorInRevision(0, 0))); } void TestDUChainMultipleFiles::testNonExistingGlobalFunction() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f2(QStringLiteral("languageController()->backgroundParser()->queuedCount() == 0); } void TestDUChainMultipleFiles::testImportsStaticFunctionNotYetParsed() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f2(QStringLiteral("imports(f1.topContext(), CursorInRevision(0, 0))); } void TestDUChainMultipleFiles::testNonExistingStaticFunction() { TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f2(QStringLiteral("languageController()->backgroundParser()->queuedCount() == 0); } void TestDUChainMultipleFiles::testForeachImportedIdentifier() { // see https://bugs.kde.org/show_bug.cgi?id=269369 TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); // build dependency TestFile f1(QStringLiteral("bar(); foreach($i as $a => $b) {} } \n" " public function bar() { $a = new SomeIterator(); return $a; }\n" " }\n"), QStringLiteral("php"), project); for(int i = 0; i < 2; ++i) { if (i > 0) { features = static_cast(features | TopDUContext::ForceUpdate); } f2.parse(features); QVERIFY(f2.waitForParsed()); QTest::qWait(100); DUChainWriteLocker lock(DUChain::lock()); QCOMPARE(f2.topContext()->childContexts().size(), 1); DUContext* ACtx = f2.topContext()->childContexts().first(); QVERIFY(ACtx); QCOMPARE(ACtx->childContexts().size(), 4); Declaration* iDec = ACtx->childContexts().at(1)->localDeclarations().first(); QVERIFY(iDec); Declaration* SomeIteratorDec = f1.topContext()->localDeclarations().first(); QVERIFY(SomeIteratorDec); if (i == 0) { QEXPECT_FAIL("", "needs a full two-pass (i.e. get rid of PreDeclarationBuilder)", Continue); } QVERIFY(iDec->abstractType()->equals(SomeIteratorDec->abstractType().constData())); QVERIFY(f2.topContext()->imports(f1.topContext(), CursorInRevision(0, 0))); } } void TestDUChainMultipleFiles::testUpdateForeach() { TopDUContext::Features features = TopDUContext::AllDeclarationsContextsAndUses; TestProject* project = new TestProject; m_projectController->closeAllProjects(); m_projectController->addProject(project); TestFile f(QStringLiteral(" $k) {}\n"), QStringLiteral("php"), project); f.parse(features); QVERIFY(f.waitForParsed()); QVERIFY(f.topContext()); { DUChainWriteLocker lock; QVERIFY(f.topContext()->problems().isEmpty()); QCOMPARE(f.topContext()->findDeclarations(Identifier("k")).count(), 1); Declaration* kDec = f.topContext()->findDeclarations(Identifier(QStringLiteral("k"))).first(); QCOMPARE(kDec->rangeInCurrentRevision().start().line(), 1); QCOMPARE(kDec->rangeInCurrentRevision().start().column(), 0); QCOMPARE(kDec->uses().count(), 1); QCOMPARE(kDec->uses().begin()->count(), 1); QCOMPARE(kDec->uses().begin()->begin()->start.line, 2); } // delete $k = null; line f.setFileContents(QStringLiteral(" $k) {}\n")); f.parse(static_cast(features | TopDUContext::ForceUpdate)); QVERIFY(f.waitForParsed()); QVERIFY(f.topContext()); { DUChainWriteLocker lock; QVERIFY(f.topContext()->problems().isEmpty()); QCOMPARE(f.topContext()->findDeclarations(Identifier("k")).count(), 1); Declaration* kDec = f.topContext()->findDeclarations(Identifier(QStringLiteral("k"))).first(); QCOMPARE(kDec->rangeInCurrentRevision().start().line(), 1); QCOMPARE(kDec->rangeInCurrentRevision().start().column(), 25); QCOMPARE(kDec->uses().count(), 0); } } void TestDUChainMultipleFiles::testTodoExtractorReparse() { TestFile file(QStringLiteral("baz();"), QStringLiteral("php")); QVERIFY(KDevelop::ICore::self()->languageController()->completionSettings()->todoMarkerWords().contains("TODO")); auto features = TopDUContext::AllDeclarationsContextsAndUses; for (int i = 0; i < 2; ++i) { if (i == 1) { file.setFileContents(QStringLiteral("asdf();")); features = static_cast(features | TopDUContext::ForceUpdate); } file.parse(features); QVERIFY(file.waitForParsed()); DUChainReadLocker lock; auto top = file.topContext(); QVERIFY(top); QCOMPARE(top->problems().size(), 1); QCOMPARE(top->problems().at(0)->description(), QString("TODO")); QCOMPARE(top->problems().at(0)->range(), RangeInRevision(2, 3, 2, 7)); } } void TestDUChainMultipleFiles::testIteratorForeachReparse() { TestFile file(QStringLiteral("(features | TopDUContext::ForceUpdate); } file.parse(features); QVERIFY(file.waitForParsed()); DUChainReadLocker lock; auto top = file.topContext(); QVERIFY(top); QVERIFY(top->localDeclarations().size() == 2); QCOMPARE(top->localDeclarations().at(0)->qualifiedIdentifier(), QualifiedIdentifier("a")); IntegralType::Ptr type = top->localDeclarations().at(0)->type(); QVERIFY(type); //Should actually parse as an TypeInt, but this does not work. QVERIFY(type->dataType() == IntegralType::TypeMixed); } }