void TestDUChain::testVirtualMemberFunction() { //Forward-declarations with "struct" or "class" are considered equal, so make sure the override is detected correctly. TestFile file("struct S {}; struct A { virtual S* ret(); }; struct B : public A { virtual S* ret(); };", "cpp"); QVERIFY(file.parseAndWait()); DUChainReadLocker lock; DUContext* top = file.topContext().data(); QVERIFY(top); QCOMPARE(top->childContexts().count(), 3); QCOMPARE(top->localDeclarations().count(), 3); QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1); Declaration* decl = top->childContexts()[2]->localDeclarations()[0]; QCOMPARE(decl->identifier(), Identifier("ret")); QVERIFY(DUChainUtils::getOverridden(decl)); }
void TestDUChain::testNamespace() { TestFile file("namespace foo { struct bar { int baz; }; }\n" "int main() { foo::bar myBar; }\n", "cpp"); QVERIFY(file.parseAndWait()); DUChainReadLocker lock; QVERIFY(file.topContext()); QCOMPARE(file.topContext()->localDeclarations().size(), 2); auto fooDecl = file.topContext()->localDeclarations().first(); QVERIFY(fooDecl->internalContext()); QCOMPARE(fooDecl->internalContext()->localDeclarations().size(), 1); DUContext* top = file.topContext().data(); DUContext* mainCtx = file.topContext()->childContexts().last(); auto foo = top->localDeclarations().first(); QCOMPARE(foo->qualifiedIdentifier().toString(), QString("foo")); DUContext* fooCtx = file.topContext()->childContexts().first(); QCOMPARE(fooCtx->localScopeIdentifier().toString(), QString("foo")); QCOMPARE(fooCtx->scopeIdentifier(true).toString(), QString("foo")); QCOMPARE(fooCtx->localDeclarations().size(), 1); auto bar = fooCtx->localDeclarations().first(); QCOMPARE(bar->qualifiedIdentifier().toString(), QString("foo::bar")); QCOMPARE(fooCtx->childContexts().size(), 1); DUContext* barCtx = fooCtx->childContexts().first(); QCOMPARE(barCtx->localScopeIdentifier().toString(), QString("bar")); QCOMPARE(barCtx->scopeIdentifier(true).toString(), QString("foo::bar")); QCOMPARE(barCtx->localDeclarations().size(), 1); auto baz = barCtx->localDeclarations().first(); QCOMPARE(baz->qualifiedIdentifier().toString(), QString("foo::bar::baz")); for (auto ctx : {top, mainCtx}) { QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo")).size(), 1); QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo::bar")).size(), 1); QCOMPARE(ctx->findDeclarations(QualifiedIdentifier("foo::bar::baz")).size(), 1); } }
void TestDUChain::testTypeDeductionInTemplateInstantiation() { // see: http://clang-developers.42468.n3.nabble.com/RFC-missing-libclang-query-functions-features-td2504253.html TestFile file("template<typename T> struct foo { T member; } foo<int> f; auto i = f.member;", "cpp"); QVERIFY(file.parseAndWait()); DUChainReadLocker lock; DUContext* ctx = file.topContext().data(); QVERIFY(ctx); QCOMPARE(ctx->localDeclarations().size(), 3); Declaration* decl = 0; // check 'foo' declaration decl = ctx->localDeclarations()[0]; QVERIFY(decl); QCOMPARE(decl->identifier(), Identifier("foo")); // check type of 'member' inside declaration-scope QCOMPARE(ctx->childContexts().size(), 1); DUContext* fooCtx = ctx->childContexts().first(); QVERIFY(fooCtx); // Should there really be two declarations? QCOMPARE(fooCtx->localDeclarations().size(), 2); decl = fooCtx->localDeclarations()[1]; QCOMPARE(decl->identifier(), Identifier("member")); // check type of 'member' in definition of 'f' decl = ctx->localDeclarations()[1]; QCOMPARE(decl->identifier(), Identifier("f")); decl = ctx->localDeclarations()[2]; QCOMPARE(decl->identifier(), Identifier("i")); #if CINDEX_VERSION_MINOR < 31 QEXPECT_FAIL("", "No type deduction here unfortunately, missing API in Clang", Continue); #endif QVERIFY(decl->type<IntegralType>()); }
void TestDUChainMultipleFiles::testForeachImportedIdentifier() { // see https://bugs.kde.org/show_bug.cgi?id=269369 TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts; TestProject* project = new TestProject; m_projectController->clearProjects(); m_projectController->addProject(project); // build dependency TestFile f1("<? class SomeIterator implements Countable, Iterator { }", "php", project); f1.parse(features); f1.waitForParsed(); TestFile f2("<?\n" "class A {\n" " public function foo() { $i = $this->bar(); foreach($i as $a => $b) {} } \n" " public function bar() { $a = new SomeIterator(); return $a; }\n" " }\n", "php", project); for(int i = 0; i < 2; ++i) { if (i > 0) { features = static_cast<TopDUContext::Features>(features | TopDUContext::ForceUpdate); } f2.parse(features); f2.waitForParsed(); QTest::qWait(100); DUChainWriteLocker lock(DUChain::lock()); DUContext* ACtx = f2.topContext()->childContexts().first(); QVERIFY(ACtx); 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 TestCppCodegen::testUpdateIndices() { /// @todo Extend this test to make sure t hat all kinds of declarations retain their indices when they are updated { InsertIntoDUChain code1("duchaintest_1.h", "class QW{}; struct A { struct Member2; struct Member1; }; class Oq{};"); InsertIntoDUChain code3("duchaintest_3.h", "#include <duchaintest_1.h>\n struct C : public A { Member1 m1; Member2 m2; A test(int arg) { int v1; \n{}\n { int v2, *v3; }} int test(); };"); qWarning() << "********************* Parsing step 1"; code3.parse(TopDUContext::AllDeclarationsContextsUsesAndAST); DUChainReadLocker lock; IndexedDeclaration CDecl = code3.getDeclaration("C"); QVERIFY(CDecl.isValid()); IndexedDeclaration ADecl = code3.getDeclaration("A"); QVERIFY(ADecl.isValid()); IndexedDeclaration C_m1 = code3.getDeclaration("C::m1"); QVERIFY(C_m1.isValid()); IndexedDeclaration C_m2 = code3.getDeclaration("C::m2"); QVERIFY(C_m2.isValid()); QVERIFY(CDecl.declaration()->internalContext()); QCOMPARE(CDecl.declaration()->internalContext()->localDeclarations().size(), 4); IndexedDeclaration C_test = CDecl.declaration()->internalContext()->localDeclarations()[2]; QVERIFY(C_test.isValid()); DUContext* testCtx = C_test.data()->internalContext(); QVERIFY(testCtx); QCOMPARE(testCtx->localDeclarations().size(), 1); IndexedDeclaration C_test_v1 = testCtx->localDeclarations()[0]; QCOMPARE(testCtx->childContexts().size(), 2); DUContext* child = testCtx->childContexts()[1]; QCOMPARE(child->localDeclarations().size(), 2); IndexedDeclaration C_test_v2 = child->localDeclarations()[0]; IndexedDeclaration C_test_v3 = child->localDeclarations()[1]; QCOMPARE(C_test_v1.declaration()->identifier(), Identifier("v1")); QCOMPARE(C_test_v2.declaration()->identifier(), Identifier("v2")); QCOMPARE(C_test_v3.declaration()->identifier(), Identifier("v3")); QCOMPARE(C_m1.declaration()->identifier(), Identifier("m1")); QCOMPARE(C_m2.declaration()->identifier(), Identifier("m2")); QCOMPARE(C_test.declaration()->identifier(), Identifier("test")); QCOMPARE(CDecl.declaration()->identifier(), Identifier("C")); QCOMPARE(ADecl.declaration()->identifier(), Identifier("A")); lock.unlock(); code1.m_insertedCode.setText("struct A { struct Member2; struct Member1; };"); code3.m_insertedCode.setText("#include <duchaintest_1.h>\n class Q{}; struct C : public A { Member2 m2; int c; A test(int arg) { int w1; int v1;\n\n { int *v3; }} int test(); };"); code3.parse(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdateRecursive, true); lock.lock(); QVERIFY(ADecl.declaration()); QCOMPARE(ADecl.declaration()->identifier(), Identifier("A")); QVERIFY(CDecl.declaration()); QCOMPARE(CDecl.declaration()->identifier(), Identifier("C")); QVERIFY(!C_m1.declaration()); QVERIFY(C_m2.declaration()); QCOMPARE(C_m2.declaration()->identifier(), Identifier("m2")); QVERIFY(C_test.declaration()); QCOMPARE(C_test.declaration()->identifier(), Identifier("test")); QVERIFY(C_test_v1.declaration()); QCOMPARE(C_test_v1.declaration()->identifier(), Identifier("v1")); QVERIFY(!C_test_v2.declaration()); QVERIFY(C_test_v3.declaration()); QCOMPARE(C_test_v3.declaration()->identifier(), Identifier("v3")); } }