mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 03:12:53 +00:00
6109 lines
272 KiB
C++
6109 lines
272 KiB
C++
/* This file is part of KDevelop
|
|
Copyright 2006 Hamish Rodda <rodda@kde.org>
|
|
Copyright 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "test_duchain.h"
|
|
|
|
#include <QTest>
|
|
|
|
#include "declarationbuilder.h"
|
|
#include "usebuilder.h"
|
|
#include "cpptypes.h"
|
|
#include "templateparameterdeclaration.h"
|
|
#include "dumptypes.h"
|
|
#include "typeutils.h"
|
|
#include "templatedeclaration.h"
|
|
#include "qtfunctiondeclaration.h"
|
|
#include "sourcemanipulation.h"
|
|
#include "ptrtomembertype.h"
|
|
#include "overloadresolution.h"
|
|
|
|
#include "rpp/chartools.h"
|
|
#include "rpp/pp-engine.h"
|
|
#include "rpp/preprocessor.h"
|
|
|
|
#include <language/duchain/duchain.h>
|
|
#include <language/duchain/duchainlock.h>
|
|
#include <language/duchain/topducontext.h>
|
|
#include <language/duchain/forwarddeclaration.h>
|
|
#include <language/duchain/functiondefinition.h>
|
|
#include <language/duchain/declarationid.h>
|
|
#include <language/duchain/declaration.h>
|
|
#include <language/duchain/dumpdotgraph.h>
|
|
#include <language/duchain/dumpchain.h>
|
|
#include <language/duchain/indexedstring.h>
|
|
#include <language/duchain/classdeclaration.h>
|
|
#include <language/duchain/types/alltypes.h>
|
|
#include <language/duchain/persistentsymboltable.h>
|
|
#include <language/duchain/codemodel.h>
|
|
#include <language/duchain/navigation/abstractnavigationwidget.h>
|
|
#include <language/duchain/duchainutils.h>
|
|
|
|
#include <language/codegen/coderepresentation.h>
|
|
#include <language/editor/documentrange.h>
|
|
|
|
#include <typeinfo>
|
|
|
|
#include <tests/testhelpers.h>
|
|
#include <tests/testcore.h>
|
|
|
|
using namespace KTextEditor;
|
|
using namespace TypeUtils;
|
|
using namespace KDevelop;
|
|
using namespace Cpp;
|
|
using namespace Utils;
|
|
|
|
QTEST_MAIN(TestDUChain)
|
|
|
|
#define TEST_FILE_PARSE_ONLY if (testFileParseOnly) QSKIP("Skip", SkipSingle);
|
|
TestDUChain::TestDUChain()
|
|
{
|
|
testFileParseOnly = false;
|
|
}
|
|
|
|
void TestDUChain::initTestCase()
|
|
{
|
|
noDef = 0;
|
|
|
|
initShell();
|
|
|
|
file1 = "file:///media/data/kdedev/4.0/kdevelop/languages/cpp/parser/duchain.cpp";
|
|
file2 = "file:///media/data/kdedev/4.0/kdevelop/languages/cpp/parser/dubuilder.cpp";
|
|
|
|
topContext = new TopDUContext(IndexedString(file1.pathOrUrl()), RangeInRevision(CursorInRevision(0,0),CursorInRevision(25,0)));
|
|
DUChainWriteLocker lock(DUChain::lock());
|
|
|
|
DUChain::self()->addDocumentChain(topContext);
|
|
|
|
typeVoid = AbstractType::Ptr(new IntegralType(IntegralType::TypeVoid))->indexed();
|
|
typeInt = AbstractType::Ptr(new IntegralType(IntegralType::TypeInt))->indexed();
|
|
AbstractType::Ptr s(new IntegralType(IntegralType::TypeInt));
|
|
s->setModifiers(AbstractType::ShortModifier);
|
|
typeShort = s->indexed();
|
|
}
|
|
|
|
void TestDUChain::cleanupTestCase()
|
|
{
|
|
//Just a few tests so there is always something cleared away
|
|
QualifiedIdentifier id("test_bla12310915205342");
|
|
IndexedQualifiedIdentifier indexedId(id);
|
|
DelayedType::Ptr delayed(new DelayedType);
|
|
delayed->setIdentifier(IndexedTypeIdentifier("frokkoflasdasotest_bla12310915205342"));
|
|
IndexedType indexed = delayed->indexed();
|
|
DUChain::self()->finalCleanup();
|
|
|
|
{
|
|
DUChainWriteLocker lock(DUChain::lock());
|
|
|
|
DUChain::self()->removeDocumentChain(topContext);
|
|
}
|
|
|
|
TestCore::shutdown();
|
|
}
|
|
|
|
Declaration* TestDUChain::findDeclaration(DUContext* context, const Identifier& id, const CursorInRevision& position)
|
|
{
|
|
QList<Declaration*> ret = context->findDeclarations(id, position);
|
|
if (ret.count())
|
|
return ret.first();
|
|
return 0;
|
|
}
|
|
|
|
Declaration* TestDUChain::findDeclaration(DUContext* context, const QualifiedIdentifier& id, const CursorInRevision& position)
|
|
{
|
|
QList<Declaration*> ret = context->findDeclarations(id, position);
|
|
if (ret.count())
|
|
return ret.first();
|
|
return 0;
|
|
}
|
|
|
|
void TestDUChain::testIdentifiers()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
QualifiedIdentifier aj("::Area::jump");
|
|
QCOMPARE(aj.count(), 2);
|
|
QCOMPARE(aj.explicitlyGlobal(), true);
|
|
QCOMPARE(aj.at(0), Identifier("Area"));
|
|
QCOMPARE(aj.at(1), Identifier("jump"));
|
|
|
|
QualifiedIdentifier aj2 = QualifiedIdentifier("Area::jump");
|
|
QCOMPARE(aj2.count(), 2);
|
|
QCOMPARE(aj2.explicitlyGlobal(), false);
|
|
QCOMPARE(aj2.at(0), Identifier("Area"));
|
|
QCOMPARE(aj2.at(1), Identifier("jump"));
|
|
kDebug() << aj.toString() << aj2.toString();
|
|
kDebug() << aj.index() << aj2.index();
|
|
QCOMPARE(aj == aj2, true);
|
|
|
|
QVERIFY(QualifiedIdentifier("") == QualifiedIdentifier());
|
|
QVERIFY(QualifiedIdentifier("").index() == QualifiedIdentifier().index());
|
|
|
|
// QCOMPARE(aj.match(aj2), QualifiedIdentifier::ExactMatch);
|
|
|
|
QualifiedIdentifier ajt("Area::jump::test");
|
|
QualifiedIdentifier jt("jump::test");
|
|
QualifiedIdentifier ajt2("Area::jump::tes");
|
|
|
|
// QCOMPARE(aj2.match(ajt), QualifiedIdentifier::NoMatch);
|
|
// QCOMPARE(ajt.match(aj2), QualifiedIdentifier::NoMatch);
|
|
// //QCOMPARE(jt.match(aj2), QualifiedIdentifier::ContainedBy); ///@todo reenable this(but it fails)
|
|
// QCOMPARE(ajt.match(jt), QualifiedIdentifier::EndsWith);
|
|
|
|
/* QCOMPARE(aj2.match(ajt2), QualifiedIdentifier::NoMatch);
|
|
QCOMPARE(ajt2.match(aj2), QualifiedIdentifier::NoMatch);*/
|
|
QualifiedIdentifier t(" Area<A,B>::jump <F> ::tes<C>");
|
|
QCOMPARE(t.count(), 3);
|
|
QCOMPARE(t.at(0).templateIdentifiersCount(), 2u);
|
|
QCOMPARE(t.at(1).templateIdentifiersCount(), 1u);
|
|
QCOMPARE(t.at(2).templateIdentifiersCount(), 1u);
|
|
QCOMPARE(t.at(0).identifier().str(), QString("Area"));
|
|
QCOMPARE(t.at(1).identifier().str(), QString("jump"));
|
|
QCOMPARE(t.at(2).identifier().str(), QString("tes"));
|
|
|
|
QualifiedIdentifier op1("operator<");
|
|
QualifiedIdentifier op2("operator<=");
|
|
QualifiedIdentifier op3("operator>");
|
|
QualifiedIdentifier op4("operator>=");
|
|
QualifiedIdentifier op5("operator()");
|
|
QualifiedIdentifier op6("operator( )");
|
|
QCOMPARE(op1.count(), 1);
|
|
QCOMPARE(op2.count(), 1);
|
|
QCOMPARE(op3.count(), 1);
|
|
QCOMPARE(op4.count(), 1);
|
|
QCOMPARE(op5.count(), 1);
|
|
QCOMPARE(op6.count(), 1);
|
|
QCOMPARE(op4.toString(), QString("operator>="));
|
|
QCOMPARE(op3.toString(), QString("operator>"));
|
|
QCOMPARE(op1.toString(), QString("operator<"));
|
|
QCOMPARE(op2.toString(), QString("operator<="));
|
|
QCOMPARE(op5.toString(), QString("operator()"));
|
|
QCOMPARE(op6.toString(), QString("operator( )"));
|
|
QCOMPARE(QualifiedIdentifier("Area<A,B>::jump <F> ::tes<C>").index(), t.index());
|
|
QCOMPARE(op4.index(), QualifiedIdentifier("operator>=").index());
|
|
///@todo create a big randomized test for the identifier repository(check that indices are the same)
|
|
}
|
|
|
|
void TestDUChain::testContextRelationships()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
DUChainWriteLocker lock(DUChain::lock());
|
|
|
|
QCOMPARE(DUChain::self()->chainForDocument(file1), topContext);
|
|
|
|
DUContext* firstChild = new DUContext(RangeInRevision(CursorInRevision(4,4), CursorInRevision(10,3)), topContext);
|
|
|
|
QCOMPARE(firstChild->parentContext(), topContext);
|
|
QCOMPARE(firstChild->childContexts().count(), 0);
|
|
QCOMPARE(topContext->childContexts().count(), 1);
|
|
QCOMPARE(topContext->childContexts().last(), firstChild);
|
|
|
|
DUContext* secondChild = new DUContext(RangeInRevision(CursorInRevision(14,4), CursorInRevision(19,3)), topContext);
|
|
|
|
QCOMPARE(topContext->childContexts().count(), 2);
|
|
QCOMPARE(topContext->childContexts()[1], secondChild);
|
|
|
|
DUContext* thirdChild = new DUContext(RangeInRevision(CursorInRevision(10,4), CursorInRevision(14,3)), topContext);
|
|
|
|
QCOMPARE(topContext->childContexts().count(), 3);
|
|
QCOMPARE(topContext->childContexts()[1], thirdChild);
|
|
|
|
topContext->deleteChildContextsRecursively();
|
|
QVERIFY(topContext->childContexts().isEmpty());
|
|
}
|
|
|
|
void TestDUChain::testDeclareInt()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
QByteArray method("int i;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 0);
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* def = top->localDeclarations().first();
|
|
QCOMPARE(def->identifier(), Identifier("i"));
|
|
QCOMPARE(findDeclaration(top, def->identifier()), def);
|
|
}
|
|
|
|
void TestDUChain::testMultiByteCStrings()
|
|
{
|
|
// 01234567 89 012345678901234567890123456789
|
|
QByteArray method("char* c=\"ä\";void test() { c = 1; }");
|
|
LockedTopDUContext top = parse(method, DumpAST, 0, true);
|
|
QVERIFY(top);
|
|
Declaration* cDec = top->localDeclarations().first();
|
|
QCOMPARE(cDec->uses().size(), 1);
|
|
QCOMPARE(cDec->uses().begin()->size(), 1);
|
|
kDebug() << cDec->uses().begin()->first();
|
|
QEXPECT_FAIL("", "The wide ä-char is seen as two, breaking anything afterwards. see also parser test of same name", Abort);
|
|
QVERIFY(cDec->uses().begin()->first() == RangeInRevision(0, 26, 0, 27));
|
|
}
|
|
|
|
void TestDUChain::testEllipsis()
|
|
{
|
|
QByteArray method("void infinity(int i, ...) { }");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
Declaration* defInfinity = top->localDeclarations().first();
|
|
QCOMPARE(defInfinity->type<FunctionType>()->arguments().count(), 2);
|
|
QCOMPARE(defInfinity->type<FunctionType>()->arguments()[1]->toString(), QString("..."));
|
|
}
|
|
|
|
void TestDUChain::testEllipsisVexing()
|
|
{
|
|
QByteArray method("void infinity(...);");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
Declaration* defInfinity = top->localDeclarations().first();
|
|
QCOMPARE(defInfinity->type<FunctionType>()->arguments().count(), 1);
|
|
QCOMPARE(defInfinity->type<FunctionType>()->arguments()[0]->toString(), QString("..."));
|
|
}
|
|
|
|
void TestDUChain::testContextSearch() {
|
|
{
|
|
QByteArray method("int t; struct C { }; void test() { C c; c.t = 3;}");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QVERIFY(top->localDeclarations()[0]->uses().isEmpty());
|
|
}
|
|
{
|
|
QByteArray method("typedef union { char __size[2]; long int __align; } pthread_attr_t; struct Stru {};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testSeparateVariableDefinition() {
|
|
{
|
|
QByteArray method("struct S {static int testValue; enum { A = 5 }; class C {}; int test(C); }; int S::testValue(A); int S::test(C) {}; ");
|
|
|
|
/**
|
|
* A prefix-context is created that surrounds S::testValue to represent the "S" part of the scope.
|
|
*/
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->qualifiedIdentifier(), QualifiedIdentifier("S"));
|
|
QCOMPARE(top->childContexts().count(), 5); ///There is one 'garbage' context
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 4);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().count(), 1);
|
|
ClassMemberDeclaration* staticDeclaration = dynamic_cast<ClassMemberDeclaration*>(top->childContexts()[0]->localDeclarations()[0]);
|
|
QVERIFY(staticDeclaration);
|
|
QCOMPARE(staticDeclaration->qualifiedIdentifier(), QualifiedIdentifier("S::testValue"));
|
|
QVERIFY(staticDeclaration->isStatic());
|
|
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
Declaration* actualDeclaration = top->childContexts()[2]->localDeclarations()[0];
|
|
QVERIFY(!dynamic_cast<AbstractFunctionDeclaration*>(actualDeclaration));
|
|
QCOMPARE(actualDeclaration->qualifiedIdentifier(), QualifiedIdentifier("S::testValue"));
|
|
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->uses().count(), 1);
|
|
|
|
///@todo declaration/definition relationship
|
|
|
|
|
|
QVERIFY(dynamic_cast<AbstractFunctionDeclaration*>(top->localDeclarations()[1]));
|
|
|
|
}
|
|
|
|
{
|
|
//Declaration + definition
|
|
QByteArray method("extern int x; int x;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
///@todo declaration/definition relationship
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testIntegralTypes()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
QByteArray method("const unsigned int i, k; volatile long double j; int* l; double * const * m; const int& n = l; long long o; long long int p;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 0);
|
|
QCOMPARE(top->localDeclarations().count(), 8);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defI = top->localDeclarations().first();
|
|
QCOMPARE(defI->identifier(), Identifier("i"));
|
|
QCOMPARE(findDeclaration(top, defI->identifier()), defI);
|
|
QVERIFY(defI->type<IntegralType>());
|
|
QCOMPARE(defI->type<IntegralType>()->dataType(), (uint)IntegralType::TypeInt);
|
|
QCOMPARE(defI->type<IntegralType>()->modifiers(), (unsigned long long)(AbstractType::UnsignedModifier | AbstractType::ConstModifier));
|
|
|
|
Declaration* defK = top->localDeclarations()[1];
|
|
QCOMPARE(defK->identifier(), Identifier("k"));
|
|
QCOMPARE(defK->type<IntegralType>()->indexed(), defI->type<IntegralType>()->indexed());
|
|
|
|
Declaration* defJ = top->localDeclarations()[2];
|
|
QCOMPARE(defJ->identifier(), Identifier("j"));
|
|
QCOMPARE(findDeclaration(top, defJ->identifier()), defJ);
|
|
QVERIFY(defJ->type<IntegralType>());
|
|
QCOMPARE(defJ->type<IntegralType>()->dataType(), (uint)IntegralType::TypeDouble);
|
|
QCOMPARE(defJ->type<IntegralType>()->modifiers(), (unsigned long long)AbstractType::LongModifier | (unsigned long long)AbstractType::VolatileModifier);
|
|
|
|
Declaration* defL = top->localDeclarations()[3];
|
|
QCOMPARE(defL->identifier(), Identifier("l"));
|
|
QVERIFY(defL->type<PointerType>());
|
|
QCOMPARE(defL->type<PointerType>()->baseType()->indexed(), typeInt);
|
|
QCOMPARE(defL->type<PointerType>()->modifiers(), (unsigned long long)AbstractType::NoModifiers);
|
|
|
|
Declaration* defM = top->localDeclarations()[4];
|
|
QCOMPARE(defM->identifier(), Identifier("m"));
|
|
PointerType::Ptr firstpointer = defM->type<PointerType>();
|
|
QVERIFY(firstpointer);
|
|
QCOMPARE(firstpointer->modifiers(), (unsigned long long)AbstractType::NoModifiers);
|
|
PointerType::Ptr secondpointer = PointerType::Ptr::dynamicCast(firstpointer->baseType());
|
|
QVERIFY(secondpointer);
|
|
QCOMPARE(secondpointer->modifiers(), (unsigned long long)AbstractType::ConstModifier);
|
|
IntegralType::Ptr base = IntegralType::Ptr::dynamicCast(secondpointer->baseType());
|
|
QVERIFY(base);
|
|
QCOMPARE(base->dataType(), (uint)IntegralType::TypeDouble);
|
|
QCOMPARE(base->modifiers(), (unsigned long long)AbstractType::NoModifiers);
|
|
|
|
Declaration* defN = top->localDeclarations()[5];
|
|
QCOMPARE(defN->identifier(), Identifier("n"));
|
|
QVERIFY(defN->type<ReferenceType>());
|
|
base = IntegralType::Ptr::dynamicCast(defN->type<ReferenceType>()->baseType());
|
|
QVERIFY(base);
|
|
QCOMPARE(base->dataType(), (uint)IntegralType::TypeInt);
|
|
QCOMPARE(base->modifiers(), (unsigned long long)AbstractType::ConstModifier);
|
|
|
|
Declaration* defO = top->localDeclarations()[6];
|
|
QCOMPARE(defO->identifier(), Identifier("o"));
|
|
QVERIFY(defO->type<IntegralType>());
|
|
QCOMPARE(defO->type<IntegralType>()->modifiers(),
|
|
(unsigned long long)AbstractType::LongLongModifier |
|
|
(unsigned long long)AbstractType::LongModifier);
|
|
QCOMPARE(defO->abstractType()->toString(), QString("long long int"));
|
|
|
|
Declaration* defP = top->localDeclarations()[7];
|
|
QCOMPARE(defP->identifier(), Identifier("p"));
|
|
QVERIFY(defP->type<IntegralType>());
|
|
QCOMPARE(defP->type<IntegralType>()->modifiers(),
|
|
defO->type<IntegralType>()->modifiers());
|
|
QCOMPARE(defP->abstractType()->toString(), QString("long long int"));
|
|
|
|
//Even if reference/pointer types have an invalid target, they should still preserve the pointer
|
|
QVERIFY(AbstractType::Ptr(new ReferenceType)->toString().endsWith("&"));
|
|
QVERIFY(AbstractType::Ptr(new PointerType)->toString().endsWith("*"));
|
|
QVERIFY(AbstractType::Ptr(new PtrToMemberType)->toString().endsWith("::*"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testConversionReturn() {
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
QByteArray method("class A {}; class B{ operator A*() const ; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
FunctionType::Ptr funType = top->childContexts()[1]->localDeclarations()[0]->type<KDevelop::FunctionType>();
|
|
QVERIFY(funType);
|
|
QVERIFY(funType->returnType().cast<PointerType>());
|
|
|
|
}
|
|
|
|
void TestDUChain::testTypeof() {
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
{
|
|
QByteArray method("__typeof__(wchar_t) x; typedef typeof(++x) x_t;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(unAliasedType(top->localDeclarations()[1]->abstractType())->toString(), QString("wchar_t"));
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testArrayType()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
QByteArray method("const unsigned int ArraySize = 3; int i[ArraySize];");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 0);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
kDebug() << top->localDeclarations()[0]->abstractType()->toString();
|
|
QVERIFY(top->localDeclarations()[0]->uses().size());
|
|
QVERIFY(top->localDeclarations()[0]->type<ConstantIntegralType>());
|
|
|
|
Declaration* defI = top->localDeclarations().last();
|
|
QCOMPARE(defI->identifier(), Identifier("i"));
|
|
QCOMPARE(findDeclaration(top, defI->identifier()), defI);
|
|
|
|
ArrayType::Ptr array = defI->type<ArrayType>();
|
|
QVERIFY(array);
|
|
IntegralType::Ptr element = IntegralType::Ptr::dynamicCast(array->elementType());
|
|
QVERIFY(element);
|
|
QCOMPARE(element->dataType(), (uint)IntegralType::TypeInt);
|
|
QCOMPARE(array->dimension(), 3);
|
|
|
|
}
|
|
|
|
void TestDUChain::testProblematicUses()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
{
|
|
QByteArray method("struct A { A() : a( 0 ) { } int a; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2); //a uses
|
|
QVERIFY(!top->childContexts()[0]->localDeclarations()[1]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray method("struct A { A() : a( 0 ) { } int a; } r;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2); //a uses
|
|
QVERIFY(!top->childContexts()[0]->localDeclarations()[1]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray method("struct S { int a; }; int c; int q; int a; S* s; void test() { if(s->a < q && a > c) { } if(s->a < q && a > c) { } }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 6);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->size(), 2); //c uses
|
|
QCOMPARE(top->localDeclarations()[2]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[2]->uses().begin()->size(), 2); //q uses
|
|
QCOMPARE(top->localDeclarations()[3]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[3]->uses().begin()->size(), 2); //a uses
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 2); //a uses
|
|
|
|
}
|
|
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("enum { b = 5 }; template<bool b> struct A { enum { Mem }; }; void test(int a) { if(a < 0 && a > -1) { } if(a < 0 && a < -1) { } if(A<(b < 10 && b < 0)>::Mem) { } if(A<(b < 10 && b > 0)>::Mem) { } }");
|
|
|
|
///@todo This works in g++, but not in kdevelops parser. Although it's butt ugly.
|
|
// if(A<b < 10 && b < 0>::Mem) {}
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations()[0]->uses().begin()->size(), 4); //a uses
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 4); //b uses
|
|
|
|
}
|
|
|
|
{
|
|
QByteArray method("struct c { void foo(int x); }; struct f { void func(); }; struct e { f getF(); }; void test() { c* c_; e* e_; c_->foo(e_->getF().func());");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->childContexts().size(), 5);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->uses().size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testBaseUses()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
{
|
|
// 0 1 2 3 4 5 6 7 8
|
|
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("namespace N { struct A { A(int); int m; }; }; struct B : public N::A { B() : N::A(5) { this->N::A::m = 5; } };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(top->problems().isEmpty()); //N::A must be found in the constructor
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().count(), 2);
|
|
QVERIFY(!top->childContexts()[0]->childContexts()[0]->localDeclarations()[1]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 3);
|
|
// the ctor usage
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->uses().values().first().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->uses().values().first().first(), RangeInRevision(0, 81, 0, 82));
|
|
}
|
|
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("class A{ class B {}; }; class C : public A::B { C() : A::B() {} };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->usesCount(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[1]->uses()[0].m_range, RangeInRevision(0, 41, 0, 42));
|
|
QCOMPARE(top->childContexts()[1]->uses()[1].m_range, RangeInRevision(0, 44, 0, 45));
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[1]->usesCount(), 2);
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("template<typename T> class A{ A(){} };\n"
|
|
"template<typename T> class B : public A<T> { B() : A<T>() {} };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
|
|
// uses of class A
|
|
QEXPECT_FAIL("", "Cookie for the one fixing that!", Abort);
|
|
QCOMPARE(top->localDeclarations().first()->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations().first()->uses().begin()->size(), 2);
|
|
// use in class B : public A<T>
|
|
QCOMPARE(top->localDeclarations().first()->uses().begin()->at(0), RangeInRevision(1, 38, 1, 39));
|
|
// use in B() : A<T>()
|
|
QCOMPARE(top->localDeclarations().first()->uses().begin()->at(1), RangeInRevision(1, 51, 1, 52));
|
|
|
|
// use of A's ctor
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().first()->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().first()->uses().begin()->size(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().first()->uses().begin()->first(), RangeInRevision(1, 55, 1, 56));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void TestDUChain::testTypedefUses()
|
|
{
|
|
{
|
|
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("namespace Search { typedef int StateHypothesisIndexwqeqrqwe; StateHypothesisIndexwqeqrqwe i; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->usesCount(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
QVERIFY(top->childContexts()[0]->localDeclarations()[0]->inSymbolTable());
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(unAliasedType(top->childContexts()[0]->localDeclarations()[1]->abstractType())->toString(), QString("int"));
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("class A{}; typedef A B; A c; B d;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QCOMPARE(top->usesCount(), 3);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1); //1 File
|
|
QCOMPARE(top->localDeclarations()[1]->uses().count(), 1); //1 File
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->count(), 2); //Typedef and "A c;"
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->count(), 1); //"B d;"
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testConstructorOperatorUses()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7 8
|
|
// 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("class A{A(int); int operator()( ) {}; }; void test() { A a(1); A b = A(2); b(); }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
// QCOMPARE(top->usesCount(), 3);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[1]->uses().count(), 1);
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->count(), 3);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(0), RangeInRevision(0, 55, 0, 56));
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(1), RangeInRevision(0, 63, 0, 64));
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(2), RangeInRevision(0, 69, 0, 70));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->at(0), RangeInRevision(0, 58, 0, 59));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->at(1), RangeInRevision(0, 70, 0, 71));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->at(0), RangeInRevision(0, 76, 0, 77));
|
|
|
|
}
|
|
void TestDUChain::testDeclareFor()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("int main() { for (int i = 0; i < 10; i++) { if (i == 4) return; int i5[5]; i5[i] = 1; } }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defMain = top->localDeclarations().first();
|
|
QCOMPARE(defMain->identifier(), Identifier("main"));
|
|
QCOMPARE(findDeclaration(top, defMain->identifier()), defMain);
|
|
QVERIFY(defMain->type<FunctionType>());
|
|
QCOMPARE(defMain->type<FunctionType>()->returnType()->indexed(), typeInt);
|
|
QCOMPARE(defMain->type<FunctionType>()->arguments().count(), 0);
|
|
QCOMPARE(defMain->type<FunctionType>()->modifiers(), (unsigned long long)AbstractType::NoModifiers);
|
|
|
|
QCOMPARE(findDeclaration(top, Identifier("i")), noDef);
|
|
|
|
DUContext* main = top->childContexts()[1];
|
|
QVERIFY(main->parentContext());
|
|
QCOMPARE(main->importedParentContexts().count(), 1);
|
|
QCOMPARE(main->childContexts().count(), 2);
|
|
QCOMPARE(main->localDeclarations().count(), 0);
|
|
QCOMPARE(main->localScopeIdentifier(), QualifiedIdentifier("main"));
|
|
|
|
QCOMPARE(findDeclaration(main, Identifier("i")), noDef);
|
|
|
|
DUContext* forCtx = main->childContexts()[1];
|
|
QVERIFY(forCtx->parentContext());
|
|
QCOMPARE(forCtx->importedParentContexts().count(), 1);
|
|
QCOMPARE(forCtx->childContexts().count(), 2);
|
|
QCOMPARE(forCtx->localDeclarations().count(), 1);
|
|
QVERIFY(forCtx->localScopeIdentifier().isEmpty());
|
|
|
|
DUContext* forParamCtx = forCtx->importedParentContexts().first().context(0);
|
|
QVERIFY(forParamCtx->parentContext());
|
|
QCOMPARE(forParamCtx->importedParentContexts().count(), 0);
|
|
QCOMPARE(forParamCtx->childContexts().count(), 0);
|
|
QCOMPARE(forParamCtx->localDeclarations().count(), 1);
|
|
QVERIFY(forParamCtx->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defI = forParamCtx->localDeclarations().first();
|
|
QCOMPARE(defI->identifier(), Identifier("i"));
|
|
QCOMPARE(defI->uses().count(), 1);
|
|
QCOMPARE(defI->uses().begin()->count(), 4);
|
|
|
|
QCOMPARE(findDeclaration(forCtx, defI->identifier()), defI);
|
|
|
|
DUContext* ifCtx = forCtx->childContexts()[1];
|
|
QVERIFY(ifCtx->parentContext());
|
|
QCOMPARE(ifCtx->importedParentContexts().count(), 1);
|
|
QCOMPARE(ifCtx->childContexts().count(), 0);
|
|
QCOMPARE(ifCtx->localDeclarations().count(), 0);
|
|
QVERIFY(ifCtx->localScopeIdentifier().isEmpty());
|
|
|
|
QCOMPARE(findDeclaration(ifCtx, defI->identifier()), defI);
|
|
|
|
}
|
|
|
|
|
|
void TestDUChain::testEnum()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
/* 0 1 2 3 4 5 6 7
|
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789*/
|
|
QByteArray method("enum Enum { Value1 = 5 //Comment\n, value2 //Comment1\n }; enum Enum2 { Value21, value22 = 0x02 }; union { int u1; float u2; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
/* {
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("Value1"));
|
|
QVERIFY(decl);
|
|
AbstractType::Ptr t = decl->abstractType();
|
|
QVERIFY(t);
|
|
IdentifiedType* id = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
QVERIFY(id);
|
|
QCOMPARE(id->declaration(top), decl);
|
|
}*/
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QVERIFY(top->childContexts()[2]->inSymbolTable());
|
|
|
|
///@todo Test for the enum ranges and fix them, they overlap
|
|
kDebug() << top->childContexts()[0]->range().castToSimpleRange().textRange();
|
|
kDebug() << top->localDeclarations()[0]->range().castToSimpleRange().textRange();
|
|
|
|
Declaration* decl = findDeclaration(top, Identifier("Enum"));
|
|
Declaration* enumDecl = decl;
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->internalContext());
|
|
AbstractType::Ptr t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumerationType*>(t.unsafeData()));
|
|
EnumerationType* en = static_cast<EnumerationType*>(t.unsafeData());
|
|
QVERIFY(en->declaration(top));
|
|
QCOMPARE(en->qualifiedIdentifier(), QualifiedIdentifier("Enum"));
|
|
Declaration* EnumDecl = decl;
|
|
|
|
{
|
|
QVERIFY(!top->findLocalDeclarations(Identifier("Value1")).isEmpty());
|
|
|
|
decl = findDeclaration(top, QualifiedIdentifier("Value1"));
|
|
QVERIFY(decl);
|
|
|
|
QCOMPARE(decl->context()->owner(), enumDecl);
|
|
// QCOMPARE(decl->context()->scopeIdentifier(), QualifiedIdentifier("Enum"));
|
|
|
|
|
|
t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumeratorType*>(t.unsafeData()));
|
|
EnumeratorType* en = static_cast<EnumeratorType*>(t.unsafeData());
|
|
QCOMPARE((int)en->value<qint64>(), 5);
|
|
kDebug() << decl->qualifiedIdentifier().toString();
|
|
kDebug() << en->toString();
|
|
QCOMPARE(en->declaration(top), top->childContexts()[0]->localDeclarations()[0]);
|
|
|
|
decl = findDeclaration(top, Identifier("value2"));
|
|
QVERIFY(decl);
|
|
t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumeratorType*>(t.unsafeData()));
|
|
en = static_cast<EnumeratorType*>(t.unsafeData());
|
|
QCOMPARE((int)en->value<qint64>(), 6);
|
|
QCOMPARE(en->declaration(top), top->childContexts()[0]->localDeclarations()[1]);
|
|
QCOMPARE(en->declaration(top)->context()->owner(), EnumDecl);
|
|
}
|
|
decl = findDeclaration(top, Identifier("Enum2"));
|
|
QVERIFY(decl);
|
|
t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumerationType*>(t.unsafeData()));
|
|
en = static_cast<EnumerationType*>(t.unsafeData());
|
|
QVERIFY(en->declaration(top));
|
|
QCOMPARE(en->qualifiedIdentifier(), QualifiedIdentifier("Enum2"));
|
|
Declaration* Enum2Decl = decl;
|
|
|
|
{
|
|
decl = findDeclaration(top, Identifier("Value21"));
|
|
QVERIFY(decl);
|
|
t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumeratorType*>(t.unsafeData()));
|
|
EnumeratorType* en = static_cast<EnumeratorType*>(t.unsafeData());
|
|
QCOMPARE((int)en->value<qint64>(), 0);
|
|
QCOMPARE(en->declaration(top)->context()->owner(), Enum2Decl);
|
|
|
|
decl = findDeclaration(top, Identifier("value22"));
|
|
QVERIFY(decl);
|
|
t = decl->abstractType();
|
|
QVERIFY(dynamic_cast<EnumeratorType*>(t.unsafeData()));
|
|
en = static_cast<EnumeratorType*>(t.unsafeData());
|
|
QCOMPARE((int)en->value<qint64>(), 2);
|
|
QCOMPARE(en->declaration(top)->context()->owner(), Enum2Decl);
|
|
}
|
|
{
|
|
//Verify that the union members were propagated up
|
|
decl = findDeclaration(top, Identifier("u1"));
|
|
QVERIFY(decl);
|
|
|
|
decl = findDeclaration(top, Identifier("u2"));
|
|
QVERIFY(decl);
|
|
}
|
|
}
|
|
|
|
/*! Custom assertion which verifies that @p topcontext contains a
|
|
* single class with a single memberfunction declaration in it.
|
|
* @p memberFun is an output parameter and should have type
|
|
* pointer to ClassFunctionDeclaration */
|
|
#define ASSERT_SINGLE_MEMBER_FUNCTION_IN(topcontext, memberFun) \
|
|
{ \
|
|
QVERIFY(top);\
|
|
QCOMPARE(1, top->childContexts().count());\
|
|
QCOMPARE(1, top->localDeclarations().count()); \
|
|
DUContext* clazzCtx = top->childContexts()[0]; \
|
|
QCOMPARE(1, clazzCtx->localDeclarations().count()); \
|
|
Declaration* member = clazzCtx->localDeclarations()[0]; \
|
|
memberFun = dynamic_cast<ClassFunctionDeclaration*>(member); \
|
|
QVERIFY(memberFun); \
|
|
} (void)(0)
|
|
|
|
/*! Custom assertion which verifies that @p topcontext contains a
|
|
* single class with two memberfunction declarations in it.
|
|
* @p memberFun1 and @p memberFUn2 are output parameter and should
|
|
* have type pointer to ClassFunctionDeclaration */
|
|
#define ASSERT_TWO_MEMBER_FUNCTIONS_IN(topcontext, memberFun1, memberFun2) \
|
|
{ \
|
|
QVERIFY(top);\
|
|
QCOMPARE(1, top->childContexts().count());\
|
|
QCOMPARE(1, top->localDeclarations().count()); \
|
|
DUContext* clazzCtx = top->childContexts()[0]; \
|
|
QCOMPARE(2, clazzCtx->localDeclarations().count()); \
|
|
Declaration* member = clazzCtx->localDeclarations()[0]; \
|
|
memberFun1 = dynamic_cast<ClassFunctionDeclaration*>(member); \
|
|
QVERIFY(memberFun1); \
|
|
member = clazzCtx->localDeclarations()[1]; \
|
|
memberFun2 = dynamic_cast<ClassFunctionDeclaration*>(member); \
|
|
QVERIFY(memberFun2); \
|
|
} (void)(0)
|
|
|
|
void TestDUChain::testVirtualMemberFunction()
|
|
{
|
|
{
|
|
QByteArray text("class Foo { public: virtual void bar(const float i, const int i) = 0; }; \n");
|
|
LockedTopDUContext top = parse(text, DumpAll);
|
|
|
|
ClassFunctionDeclaration* memberFun; // filled by assert macro below
|
|
ASSERT_SINGLE_MEMBER_FUNCTION_IN(top, memberFun);
|
|
QVERIFY(memberFun->isVirtual());
|
|
QVERIFY(memberFun->isAbstract());
|
|
FunctionType::Ptr funType = memberFun->abstractType().cast<FunctionType>();
|
|
QVERIFY(funType);
|
|
QCOMPARE(funType->arguments().size(), 2);
|
|
QCOMPARE(funType->arguments()[0]->toString(), QString("const float"));
|
|
QCOMPARE(funType->arguments()[1]->toString(), QString("const int"));
|
|
}
|
|
{
|
|
QByteArray text("class Foo { public: virtual void bar(); }; \n");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
ClassFunctionDeclaration* memberFun; // filled by assert macro below
|
|
ASSERT_SINGLE_MEMBER_FUNCTION_IN(top, memberFun);
|
|
QVERIFY(memberFun->isVirtual());
|
|
QVERIFY(!memberFun->isAbstract());
|
|
}
|
|
{
|
|
//Forward-declarations with "struct" or "class" are considered equal, so make sure the override is detected correctly.
|
|
QByteArray text("class S; struct A { virtual S* ret(); }; struct S { }; struct B : public A { virtual S* ret(); };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QCOMPARE(top->localDeclarations()[0]->indexedType(), top->localDeclarations()[2]->indexedType());
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QVERIFY(DUChainUtils::getOverridden(top->childContexts()[2]->localDeclarations()[0]));
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testMultipleVirtual()
|
|
{
|
|
QByteArray text("class Foo { public: virtual void bar(); virtual void baz(); }; \n");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
ClassFunctionDeclaration *bar, *baz; // filled by assert macro below
|
|
ASSERT_TWO_MEMBER_FUNCTIONS_IN(top, bar, baz);
|
|
QVERIFY(bar->isVirtual());
|
|
QVERIFY(baz->isVirtual());
|
|
QVERIFY(!baz->isAbstract());
|
|
}
|
|
|
|
void TestDUChain::testMixedVirtualNormal()
|
|
{
|
|
{
|
|
QByteArray text("class Foo { public: virtual void bar(); void baz(); }; \n");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
ClassFunctionDeclaration *bar, *baz; // filled by assert macro below
|
|
ASSERT_TWO_MEMBER_FUNCTIONS_IN(top, bar, baz);
|
|
QVERIFY(bar->isVirtual());
|
|
QVERIFY(!baz->isVirtual());
|
|
QVERIFY(!baz->isAbstract());
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testNonVirtualMemberFunction()
|
|
{
|
|
{
|
|
QByteArray text("class Foo \n { public: void bar(); };\n");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
ClassFunctionDeclaration* memberFun; // filled by assert macro below
|
|
ASSERT_SINGLE_MEMBER_FUNCTION_IN(top, memberFun);
|
|
QVERIFY(!memberFun->isVirtual());
|
|
QVERIFY(!memberFun->isAbstract());
|
|
}
|
|
}
|
|
|
|
/*! Extract memberfunction from @p topcontext in the @p nrofClass 'th class
|
|
* declaration. Assert that it is named @p expectedName. Fill the outputparameter
|
|
* @p memberFun */
|
|
#define FETCH_MEMBER_FUNCTION(nrofClass, topcontext, expectedName, memberFun) \
|
|
{ \
|
|
QVERIFY(top);\
|
|
DUContext* clazzCtx = top->childContexts()[nrofClass]; \
|
|
QCOMPARE(1, clazzCtx->localDeclarations().count()); \
|
|
Declaration* member = clazzCtx->localDeclarations()[0]; \
|
|
memberFun = dynamic_cast<ClassFunctionDeclaration*>(member); \
|
|
QVERIFY(memberFun); \
|
|
QCOMPARE(QString(expectedName), memberFun->toString()); \
|
|
} (void)(0)
|
|
|
|
void TestDUChain::testMemberFunctionModifiers()
|
|
{
|
|
// NOTE this only verifies
|
|
// {no member function modifiers in code} => {no modifiers in duchain}
|
|
// it does not check that (but probably should, with all permutations ;))
|
|
// {member function modifiers in code} => {exactly the same modifiers in duchain}
|
|
// {illegal combinations, eg explicit not on a constructor} => {error/warning}
|
|
{
|
|
QByteArray text("class FuBarr { void foo(); };\n"
|
|
"class ZooLoo { void bar(); };\n\n"
|
|
"class MooFoo \n { public: void loo(); };\n"
|
|
"class GooRoo { void baz(); };\n"
|
|
"class PooYoo { \n void zoo(); };\n");
|
|
// at one point extra '\n' characters would affect these modifiers.
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
ClassFunctionDeclaration *foo, *bar, *loo, *baz, *zoo; // filled below
|
|
FETCH_MEMBER_FUNCTION(0, top, "void foo ()", foo);
|
|
FETCH_MEMBER_FUNCTION(1, top, "void bar ()", bar);
|
|
FETCH_MEMBER_FUNCTION(2, top, "void loo ()", loo);
|
|
FETCH_MEMBER_FUNCTION(3, top, "void baz ()", baz);
|
|
FETCH_MEMBER_FUNCTION(4, top, "void zoo ()", zoo);
|
|
|
|
assertNoMemberFunctionModifiers(foo);
|
|
assertNoMemberFunctionModifiers(bar);
|
|
assertNoMemberFunctionModifiers(loo);
|
|
assertNoMemberFunctionModifiers(baz);
|
|
assertNoMemberFunctionModifiers(zoo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::assertNoMemberFunctionModifiers(ClassFunctionDeclaration* memberFun)
|
|
{
|
|
AbstractType::Ptr t(memberFun->abstractType());
|
|
Q_ASSERT(t);
|
|
bool isConstant = t->modifiers() & AbstractType::ConstModifier;
|
|
bool isVolatile = t->modifiers() & AbstractType::VolatileModifier;
|
|
|
|
kDebug() << memberFun->toString() << "virtual?" << memberFun->isVirtual()
|
|
<< "explicit?" << memberFun->isExplicit()
|
|
<< "inline?" << memberFun->isInline()
|
|
<< "constant?" << isConstant
|
|
<< "volatile?" << isVolatile
|
|
<< "static?" << memberFun->isStatic();
|
|
QVERIFY(!memberFun->isVirtual());
|
|
QVERIFY(!memberFun->isExplicit());
|
|
QVERIFY(!memberFun->isInline());
|
|
QVERIFY(!isConstant);
|
|
QVERIFY(!isVolatile);
|
|
QVERIFY(!memberFun->isStatic());
|
|
}
|
|
|
|
|
|
void TestDUChain::testAssignedContexts()
|
|
{
|
|
{
|
|
QByteArray method("void test() { int i; if(i) { int q; } int c; while(c) { char q; } int w; { float q; } }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->type(), DUContext::Other);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 3);
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[0]->owner());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[1]->owner());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[2]->owner());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[3]->owner());
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testTryCatch() {
|
|
TEST_FILE_PARSE_ONLY
|
|
{
|
|
QByteArray method("void test() { try{ int o = 3; o += 3; } catch (...) { } }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->type(), DUContext::Other);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->usesCount(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testDeclareStruct()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
// {
|
|
// QByteArray method("struct { short i; } instance;");
|
|
//
|
|
// LockedTopDUContext top = parse(method, DumpNone);
|
|
//
|
|
// QVERIFY(!top->parentContext());
|
|
// QCOMPARE(top->childContexts().count(), 1);
|
|
// QCOMPARE(top->localDeclarations().count(), 2);
|
|
// QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
//
|
|
// AbstractType::Ptr t = top->localDeclarations()[0]->abstractType();
|
|
// IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
// QVERIFY(idType);
|
|
// QVERIFY(idType->qualifiedIdentifier().count() == 1);
|
|
// QVERIFY(idType->qualifiedIdentifier().at(0).uniqueToken());
|
|
//
|
|
// Declaration* defStructA = top->localDeclarations().first();
|
|
//
|
|
// QCOMPARE(top->localDeclarations()[1]->abstractType()->indexed(), top->localDeclarations()[0]->abstractType()->indexed());
|
|
//
|
|
// QCOMPARE(idType->declaration(top), defStructA);
|
|
// QVERIFY(defStructA->type<CppClassType>());
|
|
// QVERIFY(defStructA->internalContext());
|
|
// QCOMPARE(defStructA->internalContext()->localDeclarations().count(), 1);
|
|
// Cpp::ClassDeclaration* classDecl = dynamic_cast<Cpp::ClassDeclaration*>(top->localDeclarations()[0]);
|
|
// QVERIFY(classDecl);
|
|
//
|
|
// QCOMPARE(classDecl->classType(), Cpp::ClassDeclarationData::Struct);
|
|
//
|
|
// }
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
{
|
|
QByteArray method("class A { public: union { struct { int x; }; int p; }; struct { int b; }; struct { int c; } cc; }; A test; void test() { test.x = 1; test.b = 1; test.p = 1; test.cc.c = 1; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[2]->localDeclarations().count(), 1);
|
|
QVERIFY(!top->childContexts()[0]->childContexts()[2]->localDeclarations()[0]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[1]->localDeclarations().count(), 1);
|
|
QVERIFY(top->childContexts()[0]->childContexts()[1]->isPropagateDeclarations());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->isPropagateDeclarations());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->inSymbolTable());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[1]->inSymbolTable());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->localScopeIdentifier().isEmpty());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[1]->localScopeIdentifier().isEmpty());
|
|
QVERIFY(!top->childContexts()[0]->childContexts()[1]->localDeclarations()[0]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->childContexts()[0]->localDeclarations().count(), 1);
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->isPropagateDeclarations());
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->childContexts()[0]->isPropagateDeclarations());
|
|
QVERIFY(!top->childContexts()[0]->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->uses().isEmpty());
|
|
QCOMPARE(top->childContexts()[2]->usesCount(), 9);
|
|
|
|
}
|
|
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("typedef struct { short i; } A; A instance;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
AbstractType::Ptr t = top->localDeclarations()[0]->abstractType();
|
|
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
QVERIFY(idType);
|
|
QVERIFY(idType->qualifiedIdentifier().count() == 1);
|
|
QVERIFY(idType->qualifiedIdentifier().at(0).uniqueToken());
|
|
|
|
QVERIFY(top->localDeclarations()[1]->isTypeAlias());
|
|
QCOMPARE(top->localDeclarations()[1]->identifier(), Identifier("A"));
|
|
QCOMPARE(top->localDeclarations()[2]->abstractType()->indexed(), top->localDeclarations()[1]->abstractType()->indexed());
|
|
|
|
QCOMPARE(top->localDeclarations()[1]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->count(), 1);
|
|
|
|
Declaration* defStructA = top->localDeclarations().first();
|
|
QVERIFY(!defStructA->isTypeAlias());
|
|
QVERIFY(defStructA->identifier().uniqueToken());
|
|
|
|
QCOMPARE(idType->declaration(top), defStructA);
|
|
QVERIFY(defStructA->type<CppClassType>());
|
|
QVERIFY(defStructA->internalContext());
|
|
QCOMPARE(defStructA->internalContext()->localDeclarations().count(), 1);
|
|
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(defStructA);
|
|
QVERIFY(classDecl);
|
|
QCOMPARE(classDecl->classType(), ClassDeclarationData::Struct);
|
|
|
|
QVERIFY(!findDeclaration(top, Identifier("i")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("A::i")));
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("typedef struct B A; A instance;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
AbstractType::Ptr t = top->localDeclarations()[0]->abstractType();
|
|
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
QVERIFY(idType);
|
|
QVERIFY(idType->qualifiedIdentifier().count() == 1);
|
|
|
|
QVERIFY(top->localDeclarations()[1]->isTypeAlias());
|
|
QCOMPARE(top->localDeclarations()[1]->identifier(), Identifier("A"));
|
|
QCOMPARE(top->localDeclarations()[2]->abstractType()->indexed(), top->localDeclarations()[1]->abstractType()->indexed());
|
|
|
|
QCOMPARE(top->localDeclarations()[1]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->count(), 1);
|
|
|
|
Declaration* defStructA = top->localDeclarations().first();
|
|
QVERIFY(!defStructA->isTypeAlias());
|
|
QVERIFY(defStructA->isForwardDeclaration());
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct A { short i; A(int b, int c) : i(c) { } virtual void test(int j) = 0; }; A instance;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
AbstractType::Ptr t = top->localDeclarations()[1]->abstractType();
|
|
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
QVERIFY(idType);
|
|
QCOMPARE( idType->qualifiedIdentifier(), QualifiedIdentifier("A") );
|
|
|
|
Declaration* defStructA = top->localDeclarations().first();
|
|
QCOMPARE(defStructA->identifier(), Identifier("A"));
|
|
QCOMPARE(defStructA->uses().count(), 1);
|
|
QCOMPARE(defStructA->uses().begin()->count(), 1);
|
|
QVERIFY(defStructA->type<CppClassType>());
|
|
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(defStructA);
|
|
QVERIFY(classDecl);
|
|
QCOMPARE(classDecl->classType(), ClassDeclarationData::Struct);
|
|
|
|
DUContext* structA = top->childContexts().first();
|
|
QVERIFY(structA->parentContext());
|
|
QCOMPARE(structA->importedParentContexts().count(), 0);
|
|
QCOMPARE(structA->childContexts().count(), 3);
|
|
QCOMPARE(structA->localDeclarations().count(), 3);
|
|
QCOMPARE(structA->localScopeIdentifier(), QualifiedIdentifier("A"));
|
|
|
|
Declaration* defI = structA->localDeclarations().first();
|
|
QCOMPARE(defI->identifier(), Identifier("i"));
|
|
QCOMPARE(defI->uses().count(), 1);
|
|
QCOMPARE(defI->uses().begin()->count(), 1);
|
|
|
|
QCOMPARE(findDeclaration(structA, Identifier("i")), defI);
|
|
QCOMPARE(findDeclaration(structA, Identifier("b")), noDef);
|
|
QCOMPARE(findDeclaration(structA, Identifier("c")), noDef);
|
|
|
|
DUContext* ctorImplCtx = structA->childContexts()[1];
|
|
QVERIFY(ctorImplCtx->parentContext());
|
|
QCOMPARE(ctorImplCtx->importedParentContexts().count(), 1);
|
|
QCOMPARE(ctorImplCtx->childContexts().count(), 1);
|
|
QCOMPARE(ctorImplCtx->localDeclarations().count(), 0);
|
|
QVERIFY(!ctorImplCtx->localScopeIdentifier().isEmpty());
|
|
QVERIFY(ctorImplCtx->owner());
|
|
|
|
DUContext* ctorCtx = ctorImplCtx->importedParentContexts().first().context(0);
|
|
QVERIFY(ctorCtx->parentContext());
|
|
QCOMPARE(ctorCtx->childContexts().count(), 0);
|
|
QCOMPARE(ctorCtx->localDeclarations().count(), 2);
|
|
QCOMPARE(ctorCtx->localScopeIdentifier(), QualifiedIdentifier("A")); ///@todo check if it should really be this way
|
|
|
|
Declaration* defB = ctorCtx->localDeclarations().first();
|
|
QCOMPARE(defB->identifier(), Identifier("b"));
|
|
QCOMPARE(defB->uses().count(), 0);
|
|
|
|
Declaration* defC = ctorCtx->localDeclarations()[1];
|
|
QCOMPARE(defC->identifier(), Identifier("c"));
|
|
QCOMPARE(defC->uses().count(), 1);
|
|
QCOMPARE(defC->uses().begin()->count(), 1);
|
|
|
|
Declaration* defTest = structA->localDeclarations()[2];
|
|
QCOMPARE(defTest->identifier(), Identifier("test"));
|
|
ClassFunctionDeclaration* classFunDecl = dynamic_cast<ClassFunctionDeclaration*>(defTest);
|
|
QVERIFY(classFunDecl);
|
|
QVERIFY(classFunDecl->isAbstract());
|
|
|
|
QCOMPARE(findDeclaration(ctorCtx, Identifier("i")), defI);
|
|
QCOMPARE(findDeclaration(ctorCtx, Identifier("b")), defB);
|
|
QCOMPARE(findDeclaration(ctorCtx, Identifier("c")), defC);
|
|
|
|
DUContext* testCtx = structA->childContexts().last();
|
|
QCOMPARE(testCtx->childContexts().count(), 0);
|
|
QCOMPARE(testCtx->localDeclarations().count(), 1);
|
|
QCOMPARE(testCtx->localScopeIdentifier(), QualifiedIdentifier("test")); ///@todo check if it should really be this way
|
|
|
|
Declaration* defJ = testCtx->localDeclarations().first();
|
|
QCOMPARE(defJ->identifier(), Identifier("j"));
|
|
QCOMPARE(defJ->uses().count(), 0);
|
|
|
|
/*DUContext* insideCtorCtx = ctorCtx->childContexts().first();
|
|
QCOMPARE(insideCtorCtx->childContexts().count(), 0);
|
|
QCOMPARE(insideCtorCtx->localDeclarations().count(), 0);
|
|
QVERIFY(insideCtorCtx->localScopeIdentifier().isEmpty());*/
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct A { short i; }; struct A instance; void test(struct A * a) { a->i = instance.i; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defStructA = top->localDeclarations().first();
|
|
QCOMPARE(defStructA->identifier(), Identifier("A"));
|
|
QCOMPARE(defStructA->uses().count(), 1);
|
|
QCOMPARE(defStructA->uses().begin()->count(), 2);
|
|
QVERIFY(defStructA->type<CppClassType>());
|
|
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(defStructA);
|
|
QVERIFY(classDecl);
|
|
QCOMPARE(classDecl->classType(), ClassDeclarationData::Struct);
|
|
|
|
DUContext* structA = top->childContexts().first();
|
|
QCOMPARE(structA->parentContext(), top.m_top);
|
|
QCOMPARE(structA->importedParentContexts().count(), 0);
|
|
QCOMPARE(structA->childContexts().count(), 0);
|
|
QCOMPARE(structA->localDeclarations().count(), 1);
|
|
QCOMPARE(structA->localScopeIdentifier(), QualifiedIdentifier("A"));
|
|
|
|
Declaration* defI = structA->localDeclarations().first();
|
|
QCOMPARE(defI->identifier(), Identifier("i"));
|
|
QCOMPARE(defI->uses().count(), 1);
|
|
QCOMPARE(defI->uses().begin()->count(), 2);
|
|
|
|
QCOMPARE(findDeclaration(structA, Identifier("i")), defI);
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testDeclareStructInNamespace()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
{
|
|
QByteArray method("namespace A { class B { class C; } ; } namespace A { class A::B::C { }; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().size(), 1);
|
|
|
|
ForwardDeclaration* forwardDecl = dynamic_cast<ForwardDeclaration*>(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]);
|
|
QVERIFY(forwardDecl);
|
|
QVERIFY(forwardDecl->resolve(top));
|
|
|
|
}
|
|
|
|
{
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct A {A(); struct B;}; struct A::B { B(); struct C; }; struct A::B::C { A mem; B mem2; void test(A param); }; void A::B::C::test(A param) {};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
QCOMPARE(top->localDeclarations().count(), 2); //Only one declaration, because the others are nested within helper scope contexts
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[2]->localScopeIdentifier(), QualifiedIdentifier("A::B"));
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->localScopeIdentifier(), QualifiedIdentifier("C"));
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->scopeIdentifier(true), QualifiedIdentifier("A::B::C"));
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[0]->qualifiedIdentifier(), QualifiedIdentifier("A::B::C"));
|
|
QVERIFY(top->childContexts()[2]->inSymbolTable());
|
|
QVERIFY(top->childContexts()[2]->childContexts()[0]->inSymbolTable());
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->inSymbolTable());
|
|
|
|
QualifiedIdentifier search("::A::B::C");
|
|
Declaration* cDecl = findDeclaration(top, search);
|
|
QVERIFY(cDecl);
|
|
QVERIFY(cDecl->logicalInternalContext(top));
|
|
QVERIFY(cDecl);
|
|
QVERIFY(!cDecl->isForwardDeclaration());
|
|
QVERIFY(cDecl->internalContext());
|
|
|
|
QCOMPARE(top->childContexts()[2]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->localDeclarations().count(), 3);
|
|
kDebug() << top->childContexts()[2]->childContexts()[0]->localDeclarations()[0]->abstractType()->toString();
|
|
kDebug() << top->localDeclarations()[0]->abstractType()->toString();
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->localDeclarations()[0]->indexedType(), top->localDeclarations()[0]->indexedType());
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->localDeclarations()[1]->indexedType(), top->childContexts()[1]->localDeclarations()[0]->indexedType());
|
|
kDebug() << top->childContexts()[3]->localDeclarations()[0]->abstractType()->toString();
|
|
kDebug() << top->localDeclarations()[0]->abstractType()->toString();
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations()[0]->indexedType(), top->localDeclarations()[0]->indexedType());
|
|
|
|
}
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
{
|
|
QByteArray method("namespace B {class C {struct A;void test();};};using namespace B;struct C::A {};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().count(), 2);
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->isForwardDeclaration());
|
|
KDevelop::ForwardDeclaration* forward = dynamic_cast<KDevelop::ForwardDeclaration*>(top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]);
|
|
QVERIFY(forward);
|
|
QVERIFY(forward->resolve(top));
|
|
|
|
}
|
|
}
|
|
void TestDUChain::testCStruct()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct A {int i; }; struct A instance; typedef struct { int a; } B, *BPointer;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
|
|
QVERIFY(top->localDeclarations()[0]->kind() == Declaration::Type);
|
|
QVERIFY(top->localDeclarations()[1]->kind() == Declaration::Instance);
|
|
|
|
}
|
|
|
|
void TestDUChain::testCStruct2()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
{
|
|
QByteArray method("struct A {struct C c; }; struct C { int v; };");
|
|
|
|
//Expected result: the elaborated type-specifier "struct C" within the declaration "struct A" should create a new global declaration.
|
|
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 3); //3 declarations because the elaborated type-specifier "struct C" creates a forward-declaration on the global scope
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
kDebug() << "TYPE:" << top->childContexts()[0]->localDeclarations()[0]->abstractType()->toString() << typeid(*top->childContexts()[0]->localDeclarations()[0]->abstractType()).name();
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->indexedType(), top->localDeclarations()[1]->indexedType());
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->kind(), Declaration::Instance);
|
|
//QVERIFY(top->localDeclarations()[0]->kind() == Declaration::Type);
|
|
//QVERIFY(top->localDeclarations()[1]->kind() == Declaration::Instance);
|
|
}
|
|
{
|
|
QByteArray method("struct A {inline struct C c() {}; }; struct C { int v; };");
|
|
|
|
//Expected result: the elaborated type-specifier "struct C" within the declaration "struct A" should create a new global declaration.
|
|
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 3); //3 declarations because the elaborated type-specifier "struct C" creates a forward-declaration on the global scope
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
kDebug() << "TYPE:" << top->childContexts()[0]->localDeclarations()[0]->abstractType()->toString() << typeid(*top->childContexts()[0]->localDeclarations()[0]->abstractType()).name();
|
|
FunctionType::Ptr function(top->childContexts()[0]->localDeclarations()[0]->type<FunctionType>());
|
|
QVERIFY(function);
|
|
kDebug() << "RETURN:" << function->returnType()->toString() << typeid(*function->returnType()).name();
|
|
QCOMPARE(function->returnType()->indexed(), top->localDeclarations()[1]->indexedType());
|
|
//QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->indexedType(), top->localDeclarations()[1]->indexedType());
|
|
|
|
//QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->kind(), Declaration::Instance);
|
|
//QVERIFY(top->localDeclarations()[0]->kind() == Declaration::Type);
|
|
//QVERIFY(top->localDeclarations()[1]->kind() == Declaration::Instance);
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testVariableDeclaration()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct A{}; int c, q;\n"
|
|
"A instance1(c); A instance2(2, 3); A instance3(q);\n"
|
|
"void bla() {int* i = new A(c); }\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 7);
|
|
|
|
// struct A
|
|
Declaration* defStructA = top->localDeclarations().first();
|
|
QCOMPARE(defStructA->identifier(), Identifier("A"));
|
|
|
|
// int c;
|
|
Declaration* defIntC = top->localDeclarations().at(1);
|
|
QCOMPARE(defIntC->uses().count(), 1);
|
|
QCOMPARE(defIntC->uses().begin()->count(), 2);
|
|
|
|
// instances
|
|
for(int i = 3; i < 6; ++i) {
|
|
Declaration* inst = top->localDeclarations().at(i);
|
|
QVERIFY(!inst->isFunctionDeclaration());
|
|
StructureType::Ptr idType = inst->abstractType().cast<StructureType>();
|
|
QVERIFY(idType);
|
|
QCOMPARE( idType->qualifiedIdentifier(), QualifiedIdentifier("A") );
|
|
}
|
|
|
|
// bla
|
|
QVERIFY(top->localDeclarations().at(6)->isFunctionDeclaration());
|
|
}
|
|
|
|
void TestDUChain::testDeclareClass()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("class A { A() {}; A rec; void test(int); }; void A::test(int j) {}");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
DumpDotGraph dump;
|
|
// kDebug() << "dot-graph: \n" << dump.dotGraph(top, false);
|
|
|
|
// kDebug() << "ENDE ENDE ENDE";
|
|
// kDebug() << "dot-graph: \n" << dump.dotGraph(top, false);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defClassA = top->localDeclarations().first();
|
|
QCOMPARE(defClassA->identifier(), Identifier("A"));
|
|
QCOMPARE(defClassA->uses().count(), 1);
|
|
QCOMPARE(defClassA->uses().begin()->count(), 2);
|
|
QVERIFY(defClassA->type<CppClassType>());
|
|
QVERIFY(defClassA->internalContext());
|
|
QCOMPARE(defClassA->internalContext()->range().start.column, 8); //The class-context should start directly behind the name
|
|
// QVERIFY(function);
|
|
// QCOMPARE(function->returnType(), typeVoid);
|
|
// QCOMPARE(function->arguments().count(), 1);
|
|
// QCOMPARE(function->arguments().first(), typeInt);
|
|
|
|
QVERIFY(defClassA->internalContext());
|
|
|
|
QCOMPARE(defClassA->internalContext()->localDeclarations().count(), 3);
|
|
QCOMPARE(defClassA->internalContext()->localDeclarations()[1]->abstractType()->indexed(), defClassA->abstractType()->indexed());
|
|
|
|
DUContext* classA = top->childContexts().first();
|
|
QVERIFY(classA->parentContext());
|
|
QCOMPARE(classA->importedParentContexts().count(), 0);
|
|
QCOMPARE(classA->childContexts().count(), 3);
|
|
QCOMPARE(classA->localDeclarations().count(), 3);
|
|
QCOMPARE(classA->localScopeIdentifier(), QualifiedIdentifier("A"));
|
|
|
|
Declaration* defRec = classA->localDeclarations()[1];
|
|
QVERIFY(defRec->abstractType());
|
|
QCOMPARE(defRec->abstractType()->indexed(), defClassA->abstractType()->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testDeclareFriend()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("class B {}; class A { friend class F; friend class B; }; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
DumpDotGraph dump;
|
|
// kDebug() << "dot-graph: \n" << dump.dotGraph(top, false);
|
|
|
|
// kDebug() << "ENDE ENDE ENDE";
|
|
// kDebug() << "dot-graph: \n" << dump.dotGraph(top, false);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 3); //1 Forward-declaration of F
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
|
|
Declaration* defClassA = top->localDeclarations()[1];
|
|
QCOMPARE(defClassA->identifier(), Identifier("A"));
|
|
QCOMPARE(defClassA->uses().count(), 0);
|
|
QVERIFY(defClassA->type<CppClassType>());
|
|
QVERIFY(defClassA->internalContext());
|
|
|
|
QCOMPARE(top->localDeclarations()[2]->identifier(), Identifier("F"));
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 2); //friend-declaration
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->identifier(), Identifier("friend"));
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[1]->identifier(), Identifier("friend"));
|
|
|
|
QVERIFY(Cpp::isFriend(top->localDeclarations()[1], top->localDeclarations()[2]));
|
|
QVERIFY(Cpp::isFriend(top->localDeclarations()[1], top->localDeclarations()[0]));
|
|
|
|
QVERIFY(top->localDeclarations()[0]->uses().size());
|
|
QVERIFY(top->localDeclarations()[0]->uses().begin()->size());
|
|
|
|
}
|
|
|
|
void TestDUChain::testDeclareNamespace()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("namespace foo { int bar; } int bar; int test() { return foo::bar; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
QCOMPARE(findDeclaration(top, Identifier("foo")), top->localDeclarations()[0]);
|
|
QCOMPARE(top->childContexts()[0]->range(), RangeInRevision(0, 14, 0, 26));
|
|
QVERIFY(top->localDeclarations()[0]->inSymbolTable());
|
|
|
|
QVERIFY(top->localDeclarations()[0]->inSymbolTable());
|
|
QVERIFY(top->localDeclarations()[0]->uses().size());
|
|
|
|
DUContext* fooCtx = top->childContexts().first();
|
|
QVERIFY(fooCtx->inSymbolTable());
|
|
QCOMPARE(fooCtx->childContexts().count(), 0);
|
|
QCOMPARE(fooCtx->localDeclarations().count(), 1);
|
|
QCOMPARE(fooCtx->localScopeIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(fooCtx->scopeIdentifier(), QualifiedIdentifier("foo"));
|
|
|
|
DUContext* testCtx = top->childContexts()[2];
|
|
QCOMPARE(testCtx->childContexts().count(), 0);
|
|
QCOMPARE(testCtx->localDeclarations().count(), 0);
|
|
QCOMPARE(testCtx->localScopeIdentifier(), QualifiedIdentifier("test"));
|
|
QCOMPARE(testCtx->scopeIdentifier(), QualifiedIdentifier("test"));
|
|
|
|
Declaration* bar2 = top->localDeclarations()[1];
|
|
QCOMPARE(bar2->identifier(), Identifier("bar"));
|
|
QCOMPARE(bar2->qualifiedIdentifier(), QualifiedIdentifier("bar"));
|
|
QCOMPARE(bar2->uses().count(), 0);
|
|
|
|
Declaration* bar = fooCtx->localDeclarations().first();
|
|
QCOMPARE(bar->identifier(), Identifier("bar"));
|
|
QCOMPARE(bar->qualifiedIdentifier(), QualifiedIdentifier("foo::bar"));
|
|
QCOMPARE(findDeclaration(testCtx, QualifiedIdentifier("foo::bar")), bar);
|
|
QCOMPARE(bar->uses().count(), 1);
|
|
QCOMPARE(bar->uses().begin()->count(), 1);
|
|
QCOMPARE(findDeclaration(top, bar->identifier()), bar2);
|
|
QCOMPARE(findDeclaration(top, bar->qualifiedIdentifier()), bar);
|
|
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("bar")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::bar")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("foo::bar")), bar);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::foo::bar")), bar);
|
|
|
|
IndexedQualifiedIdentifier fooId(QualifiedIdentifier("foo"));
|
|
|
|
uint itemCount;
|
|
const KDevelop::CodeModelItem* items;
|
|
CodeModel::self().items(top->url(), itemCount, items);
|
|
for(uint a = 0; a < itemCount; ++a) {
|
|
if(items[a].id == fooId) {
|
|
QCOMPARE(items[a].referenceCount, 1u); //Once by the namespace, once by the declaration
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testDeclareNamespace2()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("struct A {}; namespace B { struct A : ::A {}; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
|
|
CppClassType::Ptr outerA = top->localDeclarations()[0]->abstractType().cast<CppClassType>();
|
|
CppClassType::Ptr innerA = top->childContexts()[1]->localDeclarations()[0]->abstractType().cast<CppClassType>();
|
|
|
|
QVERIFY(outerA);
|
|
QVERIFY(innerA);
|
|
|
|
Declaration* klassDecl = innerA->declaration(top);
|
|
ClassDeclaration* cppClassDecl = dynamic_cast<ClassDeclaration*>(klassDecl);
|
|
|
|
QVERIFY(cppClassDecl);
|
|
QCOMPARE(cppClassDecl->baseClassesSize(), (uint)1);
|
|
QCOMPARE(cppClassDecl->baseClasses()->baseClass, outerA->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testSearchAcrossNamespace()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("namespace A { class B{}; } class B{}; namespace A{ B bla; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->abstractType());
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[0]->abstractType()->indexed(), top->childContexts()[0]->localDeclarations()[0]->abstractType()->indexed());
|
|
QVERIFY(!top->childContexts()[2]->localDeclarations()[0]->abstractType().cast<DelayedType>());
|
|
|
|
}
|
|
|
|
void TestDUChain::testSearchAcrossNamespace2()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("namespace A {class B{}; } namespace A { class C{ void member(B);}; } void A::C::member(B b) {B c;}");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->type(), DUContext::Function);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localScopeIdentifier(), QualifiedIdentifier("A::C::member"));
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->abstractType()); //B should be found from that position
|
|
QVERIFY(!top->childContexts()[2]->localDeclarations()[0]->abstractType().cast<DelayedType>());
|
|
QCOMPARE(top->childContexts()[3]->type(), DUContext::Other);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations().count(), 1);
|
|
QVERIFY(top->childContexts()[3]->localDeclarations()[0]->abstractType()); //B should be found from that position
|
|
QCOMPARE(top->childContexts()[3]->localScopeIdentifier(), QualifiedIdentifier("A::C::member"));
|
|
QVERIFY(!top->childContexts()[3]->localDeclarations()[0]->abstractType().cast<DelayedType>());
|
|
|
|
}
|
|
|
|
void TestDUChain::testSearchAcrossNamespace3()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("namespace B { class C { }; } namespace A { class C; } using namespace B; namespace A { C c; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[0]->abstractType()->toString(), QString("A::C"));
|
|
}
|
|
|
|
void TestDUChain::testADL()
|
|
{
|
|
{
|
|
QByteArray nonAdlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"struct A {};"
|
|
"int bar(int& a) {}"
|
|
"int test() { A a; bar(a); }"); // calls ::bar
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 6);
|
|
|
|
// foo::bar is never used
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 0);
|
|
|
|
// ::bar has 1 use
|
|
QCOMPARE(top->localDeclarations().size(), 4);
|
|
QCOMPARE(top->localDeclarations()[2]->qualifiedIdentifier().toString(), QString("bar"));
|
|
QCOMPARE(top->localDeclarations()[2]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[2]->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray nonAdlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"int bar(foo::A& a) {}" // found on normal lookup, hiding foo::bar
|
|
"int test() { A a; bar(a); }"); // calls ::bar
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
|
|
// foo::bar is hidden by successful normal name lookup
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 0);
|
|
|
|
// ::bar has 1 use
|
|
QCOMPARE(top->localDeclarations().size(), 3);
|
|
QCOMPARE(top->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("bar"));
|
|
QCOMPARE(top->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"struct A {};"
|
|
"int bar(int& a) {}"
|
|
"int test() { foo::A a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 6);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
|
|
// ::bar is never used
|
|
QCOMPARE(top->localDeclarations().size(), 4);
|
|
QCOMPARE(top->localDeclarations()[2]->qualifiedIdentifier().toString(), QString("bar"));
|
|
QCOMPARE(top->localDeclarations()[2]->uses().size(), 0);
|
|
}
|
|
|
|
{
|
|
// check that the adl lookup is performed even if no other function with the same name
|
|
// exists in the current namespace
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"int test() { foo::A a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLConstness()
|
|
{
|
|
// make sure a const-argument takes the const-overload while a non-const
|
|
// argument takes the non-const overload
|
|
// important e.g. for range-based for loops
|
|
QByteArray code( "void foo(int&);\n"
|
|
"void foo(const int&);\n"
|
|
"void bar(const int&);\n"
|
|
"void bar(int&);\n"
|
|
"int test() {\n"
|
|
" int i = 0; foo(i); bar(i);\n" // call to non-const
|
|
" const int j = 0; foo(j); bar(j);\n" // call to const
|
|
"}\n");
|
|
|
|
LockedTopDUContext top( parse(code, DumpNone) );
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
|
|
// foo: non-const version
|
|
Declaration* dec = top->localDeclarations().at(0);
|
|
FunctionType::Ptr func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 5);
|
|
|
|
// foo: const version
|
|
dec = top->localDeclarations().at(1);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 6);
|
|
|
|
// bar: const version
|
|
dec = top->localDeclarations().at(2);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 6);
|
|
|
|
// bar: non-const version
|
|
dec = top->localDeclarations().at(3);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 5);
|
|
}
|
|
|
|
void TestDUChain::testADLConstness2()
|
|
{
|
|
// make sure a const-argument takes the const-overload while a non-const
|
|
// argument takes the non-const overload
|
|
// important e.g. for range-based for loops
|
|
QByteArray code( "struct l {};\n"
|
|
"void foo(l&);\n"
|
|
"void foo(const l&);\n"
|
|
"void bar(const l&);\n"
|
|
"void bar(l&);\n"
|
|
"int test() {\n"
|
|
" l i = 0; foo(i); bar(i);\n" // call to non-const
|
|
" const l j = 0; foo(j); bar(j);\n" // call to const
|
|
"}\n");
|
|
|
|
LockedTopDUContext top( parse(code, DumpNone) );
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 6);
|
|
|
|
// foo: non-const version
|
|
Declaration* dec = top->localDeclarations().at(1);
|
|
FunctionType::Ptr func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 6);
|
|
|
|
// foo: const version
|
|
dec = top->localDeclarations().at(2);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 7);
|
|
|
|
// bar: const version
|
|
dec = top->localDeclarations().at(3);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 7);
|
|
|
|
// bar: non-const version
|
|
dec = top->localDeclarations().at(4);
|
|
func = dec->type<FunctionType>();
|
|
QVERIFY(func);
|
|
QCOMPARE(dec->uses().count(), 1);
|
|
QCOMPARE(dec->uses().begin()->count(), 1);
|
|
QCOMPARE(dec->uses().begin()->at(0).start.line, 6);
|
|
}
|
|
|
|
void TestDUChain::testADLClassType()
|
|
{
|
|
{
|
|
// test lookup to base class namespace
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"namespace boo { struct B : public foo::A {}; }"
|
|
"int test() { boo::B b; bar(b); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
// test lookup to indirect base class namespace
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(A& a) {} }"
|
|
"namespace boo { struct B : public foo::A {}; }"
|
|
"namespace zoo { struct C : public boo::B {}; }"
|
|
"int test() { zoo::C c; bar(c); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
// test lookup for inner classes
|
|
QByteArray adlCall("namespace foo { struct A { struct B {}; }; int bar(A::B&) {} }"
|
|
"int test() { foo::A::B b; bar(b); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLFunctionType()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(void *a) {} }"
|
|
"foo::A f() {}"
|
|
"int test() { bar(&f); }"); // calls foo::bar through f's return type
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(void *a) {} }"
|
|
"void f(foo::A) {}"
|
|
"int test() { bar(f); }"); // calls foo::bar through f's argument type
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLFunctionByName()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A {}; int bar(void *a) {} void f(int a) {}}"
|
|
"int test() { bar(&foo::f); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLEnumerationType()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { enum A { enValue }; int bar(A a) {} }"
|
|
"int test() { foo::A a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray adlCall("namespace foo { enum A { enValue }; int bar(A a) {} }"
|
|
"int test() { bar(foo::enValue); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLClassMembers()
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { int member; }; void bar(int A::*p) {} }"
|
|
"int test() { bar(&foo::A::member); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
|
|
QEXPECT_FAIL("", "ADL for class members doesn't work", Abort);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testADLMemberFunction()
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { void mem_fun() {} }; void bar(void (A::*p)()) {} }"
|
|
"int test() { void (foo::A::*p)() = &foo::A::mem_fun; bar(p); }"); // calls foo::bar (avoid testADLMemberFunctionByName)
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
|
|
QEXPECT_FAIL("", "ADL for class members doesn't work", Abort);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testADLMemberFunctionByName()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { void f(int a) {} }; int bar(void *a) {} }"
|
|
"int test() { bar(&foo::A::f); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
// test lookup to base class namespace (rest of tests for associated classes are same as in testClassType)
|
|
// Note: when using int bar(void *) or int bar(void (A::*p)(int)) the overload resolver
|
|
// won't be able to do the conversion from void (boo::B::*)(int), so we use a template (just like in the real)
|
|
// This setup also tests if the OverloadResolver can instantiate templates for pointers to member functions
|
|
// At the current stage, the resolver fails for this.
|
|
// Note 2: it seems also the syntax "void (T::*p)(int)" is not properly parsed at this time, so making this
|
|
// work on this higher level is a dead end for now. For the template declaration below, the function declaration
|
|
// is parsed as "int bar( function void (int) , void p )"
|
|
|
|
// reported as bug
|
|
|
|
QByteArray adlCall("namespace foo { struct A {}; template<class T> int bar(void (T::*p)(int)) {} }"
|
|
"namespace boo { struct B : public foo::A { void f(int a) {} }; }"
|
|
"int test() { bar(&boo::B::f); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
|
|
QEXPECT_FAIL("", "ADL for class members doesn't work", Abort);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLOperators()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { }; A& operator+(const A&, int) {} }"
|
|
"int test() { foo::A a, b; b = a + 1; }"); // calls foo::operator+
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::operator+"));
|
|
|
|
// binary operator +
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { }; A& operator-(const A&) {} }"
|
|
"int test() { foo::A a, b; b = -a; }"); // calls foo::operator-
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::operator-"));
|
|
|
|
// unary operator -
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLNameAlias()
|
|
{
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { }; void bar(A &) {} }"
|
|
"typedef foo::A B;"
|
|
"int test() { B a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A { }; typedef A B; void bar(A &) {} }"
|
|
"int test() { foo::B a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[2]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[2]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[2]->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
// typedef names do not participate with their namespace
|
|
QByteArray nonAdlCall("struct A { }; namespace foo { typedef A B; void bar(A &) {} }"
|
|
"int test() { foo::B a; bar(a); }"); // fails
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
|
|
// foo::bar has 1 use
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[1]->qualifiedIdentifier().toString(), QString("foo::bar"));
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[1]->uses().size(), 0);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLTemplateArguments()
|
|
{
|
|
{
|
|
QByteArray adlCall("struct A { };"
|
|
"namespace foo { template<class T> struct B { }; template<class T> void bar(T &) {} }"
|
|
"int test() { foo::B<A> a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<foo::B<A> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray adlCall("template<class T> struct B { };"
|
|
"namespace foo { struct A { }; template<class T> void bar(T &) {} }"
|
|
"int test() { B<foo::A> a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<foo::A> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray adlCall("template<class T> struct B { };"
|
|
"namespace foo { struct A { }; template<class T> void bar(T &) {} }"
|
|
"int test() { B<B<foo::A> > a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<B<foo::A> > >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray adlCall("template<class T> struct B { };"
|
|
"namespace foo { struct A { }; template<class T> void bar(T &) {} }"
|
|
"int test() { B<foo::A> a; bar(a); }"); // calls foo::bar
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<foo::A> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray adlCall("namespace foo { enum E { value }; template<class T> void bar(T &) {} }"
|
|
"template<class T> struct B { };"
|
|
"int test() { B<foo::E> a; bar(a); }");
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<foo::E> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray nonAdlCall("namespace foo { enum E { value }; template<class T> void bar(T &) {} }"
|
|
"template<int I> struct B { };"
|
|
"int test() { B<foo::value> a; bar(a); }");
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<foo::value> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 0);
|
|
}
|
|
{
|
|
QByteArray nonAdlCall("namespace foo { struct A {}; void f(A& a) {} template<class T> void bar(T &) {} }"
|
|
"template<void (*I)(foo::A&)> struct B { };"
|
|
"int test() { B<&foo::f> a; bar(a); }");
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<&foo::f> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 0);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLTemplateTemplateArguments() {
|
|
{
|
|
QByteArray adlCall("namespace foo { struct A {}; template<class T> void bar(T &) {} }"
|
|
"struct C : public foo::A { };" // foo::A is associated class of C
|
|
"template<class T> struct B { };"
|
|
"int test() { B<C> a; bar(a); }"); // in this ADL call
|
|
|
|
LockedTopDUContext top( parse(adlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<C> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 1);
|
|
QCOMPARE(d->uses().begin()->size(), 1);
|
|
}
|
|
{
|
|
QByteArray nonAdlCall("namespace foo { struct A {}; template<class T> void bar(T &) {} }"
|
|
"template<class T> struct C : public foo::A { };" // foo::A is not an associated class of C ...
|
|
"template<template<class U> class T> struct B { };"
|
|
"int test() { B<C> a; bar(a); }"); // in this ADL call
|
|
|
|
LockedTopDUContext top( parse(nonAdlCall, DumpNone) );
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("foo::bar<B<C> >"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->uses().size(), 0);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testADLEllipsis()
|
|
{
|
|
LockedTopDUContext top( parse(readCodeFile("testADLEllipsis.cpp"), DumpNone) );
|
|
QCOMPARE(top->localDeclarations().size(), 5);
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().begin().value().size(), 1);
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().begin().value().size(), 3);
|
|
QCOMPARE(top->localDeclarations().at(2)->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations().at(2)->uses().begin().value().size(), 1);
|
|
}
|
|
|
|
|
|
void TestDUChain::testAssignmentOperators()
|
|
{
|
|
QString operators("class foo {\n");
|
|
QStringList operatorPrefixes;
|
|
operatorPrefixes << "*" << "+" << "-" << "/" << "&" << "|" << "<<" << ">>" << "^" << "";
|
|
foreach ( const QString& op, operatorPrefixes ) {
|
|
operators.append(" foo& operator" + op + "=(const foo& other) { };\n");
|
|
}
|
|
|
|
operators.append("};\n\nvoid main(int, char**) {\n");
|
|
operators.append(" foo a, b;");
|
|
foreach ( const QString& op, operatorPrefixes ) {
|
|
operators.append(" a " + op + "= b;\n");
|
|
}
|
|
operators.append("}\n");
|
|
|
|
LockedTopDUContext top( parse(operators.toAscii(), DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), operatorPrefixes.size());
|
|
for ( int i = 0; i < operatorPrefixes.size(); i ++ ) {
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[i]->uses().size(), 1);
|
|
}
|
|
}
|
|
|
|
#define V_CHILD_COUNT(context, cnt) QCOMPARE(context->childContexts().count(), cnt)
|
|
#define V_DECLARATION_COUNT(context, cnt) QCOMPARE(context->localDeclarations().count(), cnt)
|
|
|
|
#define V_USE_COUNT(declaration, cnt) QCOMPARE(declaration->uses().count(), 1); QCOMPARE(declaration->uses().begin()->count(), cnt);
|
|
|
|
|
|
DUContext* childContext(DUContext* ctx, const QString& name) {
|
|
foreach(DUContext* child, ctx->childContexts())
|
|
if(child->localScopeIdentifier().toString() == name)
|
|
return child;
|
|
return 0;
|
|
}
|
|
|
|
Declaration* localDeclaration(DUContext* ctx, const QString& name) {
|
|
foreach(Declaration* decl, ctx->localDeclarations())
|
|
if(decl->identifier().toString() == name)
|
|
return decl;
|
|
return 0;
|
|
}
|
|
|
|
void TestDUChain::testUsingDeclaration()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("namespace n1 { class C{}; C c2; } namespace n2{ using n1::C; using n1::c2; C c = c2; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
V_CHILD_COUNT(top, 2);
|
|
QVERIFY(childContext(top, "n1"));
|
|
V_DECLARATION_COUNT(childContext(top, "n1"), 2);
|
|
QVERIFY(childContext(top, "n2"));
|
|
V_DECLARATION_COUNT(childContext(top, "n2"), 3);
|
|
V_USE_COUNT(top->childContexts()[0]->localDeclarations()[0], 3);
|
|
V_USE_COUNT(top->childContexts()[0]->localDeclarations()[1], 2);
|
|
QCOMPARE(localDeclaration(childContext(top, "n2"), "c")->abstractType()->indexed(), top->childContexts()[0]->localDeclarations()[0]->abstractType()->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testUsingDeclarationInTemplate()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("template<class T> class A { T i; }; template<class Q> struct B: private A<Q> { using A<Q>::i; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
Declaration* basicDecl = findDeclaration(top, QualifiedIdentifier("B::i"));
|
|
QVERIFY(basicDecl);
|
|
kDebug() << typeid(*basicDecl).name() << basicDecl->toString();
|
|
QVERIFY(basicDecl->abstractType());
|
|
kDebug() << basicDecl->abstractType()->toString();
|
|
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("B<int>::i"));
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->abstractType());
|
|
QVERIFY(decl->type<IntegralType>());
|
|
|
|
}
|
|
|
|
void TestDUChain::testDeclareUsingNamespace2()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
|
|
QByteArray method("namespace foo2 {int bar2; namespace SubFoo { int subBar2; } }; namespace foo { int bar; using namespace foo2; } namespace GFoo{ namespace renamedFoo2 = foo2; using namespace renamedFoo2; using namespace SubFoo; int gf; } using namespace GFoo; int test() { return bar; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
return;
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
QVERIFY(findDeclaration(top, Identifier("foo")));
|
|
|
|
QCOMPARE( top->childContexts().first()->localDeclarations().count(), 2);
|
|
Declaration* bar2 = top->childContexts().first()->localDeclarations()[0];
|
|
QVERIFY(bar2);
|
|
QCOMPARE(bar2->identifier(), Identifier("bar2"));
|
|
|
|
QCOMPARE( top->childContexts()[1]->localDeclarations().count(), 2);
|
|
Declaration* bar = top->childContexts()[1]->localDeclarations()[0];
|
|
QVERIFY(bar);
|
|
QCOMPARE(bar->identifier(), Identifier("bar"));
|
|
|
|
QCOMPARE( top->childContexts()[2]->localDeclarations().count(), 4);
|
|
Declaration* gf = top->childContexts()[2]->localDeclarations()[3];
|
|
QVERIFY(gf);
|
|
QCOMPARE(gf->identifier(), Identifier("gf"));
|
|
|
|
//QCOMPARE(top->namespaceAliases().count(), 1);
|
|
//QCOMPARE(top->namespaceAliases().first()->nsIdentifier, QualifiedIdentifier("foo"));
|
|
|
|
//QCOMPARE(findDeclaration(top, QualifiedIdentifier("bar2")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::bar")), noDef);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("foo::bar2")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("foo2::bar2")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::foo::bar2")), bar2);
|
|
|
|
//bar2 can be found from GFoo
|
|
QCOMPARE(findDeclaration(top->childContexts()[2], QualifiedIdentifier("bar2")), bar2);
|
|
QCOMPARE(findDeclaration(top->childContexts()[2], QualifiedIdentifier("bar")), noDef);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("gf")), gf);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("bar2")), bar2);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::GFoo::renamedFoo2::bar2")), bar2);
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("subBar2")) != noDef);
|
|
|
|
}
|
|
|
|
void TestDUChain::testGlobalNamespaceAlias()
|
|
{
|
|
QByteArray method("namespace foo { int bar(); } namespace afoo = foo; int test() { afoo::bar(); }");
|
|
|
|
LockedTopDUContext top( parse(method, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 3);
|
|
NamespaceAliasDeclaration* aliasDecl = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(aliasDecl);
|
|
QCOMPARE(aliasDecl->importIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(aliasDecl->identifier(), Identifier("afoo"));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testExternalMemberDeclaration()
|
|
{
|
|
QByteArray method("struct A { static int m; };\n"
|
|
"int A::m = 3;");
|
|
|
|
LockedTopDUContext top( parse(method, DumpAll) );
|
|
|
|
// The declaration of "A::m" is put into a helper-context that makes the scope "A::"
|
|
QCOMPARE(top->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts().size(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().size(), 1);
|
|
// There must be a use for the "A" in "int A::m"
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->size(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(0).castToSimpleRange().textRange(), KTextEditor::Range(1, 4, 1, 5));
|
|
}
|
|
|
|
void TestDUChain::testUsingGlobalNamespaceAlias()
|
|
{
|
|
QByteArray method("namespace foo { int bar(); } namespace afoo = foo; int test() { using namespace afoo; bar(); }");
|
|
|
|
LockedTopDUContext top( parse(method, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 3);
|
|
NamespaceAliasDeclaration* aliasDecl = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(aliasDecl);
|
|
QCOMPARE(aliasDecl->importIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(aliasDecl->identifier(), Identifier("afoo"));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testGlobalNamespaceAliasCycle()
|
|
{
|
|
QByteArray method("namespace foo { int bar(); } namespace A = foo; namespace B = A; namespace A = B; "
|
|
"int test() { foo::bar(); A::bar(); B::bar(); } ");
|
|
|
|
LockedTopDUContext top( parse(method, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 5); // foo, A, B, A, test
|
|
NamespaceAliasDeclaration* aliasDecl1 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(aliasDecl1);
|
|
QCOMPARE(aliasDecl1->importIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(aliasDecl1->identifier(), Identifier("A"));
|
|
NamespaceAliasDeclaration* aliasDecl2 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[2]);
|
|
QVERIFY(aliasDecl2);
|
|
QCOMPARE(aliasDecl2->importIdentifier(), QualifiedIdentifier("foo")); // already resolved
|
|
QCOMPARE(aliasDecl2->identifier(), Identifier("B"));
|
|
NamespaceAliasDeclaration* aliasDecl3 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[3]);
|
|
QVERIFY(aliasDecl3);
|
|
QCOMPARE(aliasDecl3->importIdentifier(), QualifiedIdentifier("foo")); // already resolved
|
|
QCOMPARE(aliasDecl3->identifier(), Identifier("A"));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 3);
|
|
}
|
|
|
|
void TestDUChain::testUsingGlobalNamespaceAliasCycle()
|
|
{
|
|
QByteArray method("namespace foo { int bar(); } namespace A = foo; namespace B = A; namespace A = B; "
|
|
"int testA() { using namespace A; bar(); } "
|
|
"int testB() { using namespace B; bar(); }");
|
|
|
|
LockedTopDUContext top( parse(method, DumpNone) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 6); // foo, A, B, A, testA, testB
|
|
NamespaceAliasDeclaration* aliasDecl1 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(aliasDecl1);
|
|
QCOMPARE(aliasDecl1->importIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(aliasDecl1->identifier(), Identifier("A"));
|
|
NamespaceAliasDeclaration* aliasDecl2 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[2]);
|
|
QVERIFY(aliasDecl2);
|
|
QCOMPARE(aliasDecl2->importIdentifier(), QualifiedIdentifier("foo")); // already resolved
|
|
QCOMPARE(aliasDecl2->identifier(), Identifier("B"));
|
|
NamespaceAliasDeclaration* aliasDecl3 = dynamic_cast<NamespaceAliasDeclaration*>(top->localDeclarations()[3]);
|
|
QVERIFY(aliasDecl3);
|
|
QCOMPARE(aliasDecl3->importIdentifier(), QualifiedIdentifier("foo")); // already resolved
|
|
QCOMPARE(aliasDecl3->identifier(), Identifier("A"));
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 2);
|
|
}
|
|
|
|
void TestDUChain::testLocalNamespaceAlias()
|
|
{
|
|
QByteArray method("namespace foo { int bar(); } int test() { namespace afoo = foo; afoo::bar(); }");
|
|
|
|
LockedTopDUContext top( parse(method, DumpAll) );
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().size(), 1);
|
|
NamespaceAliasDeclaration* aliasDecl = dynamic_cast<NamespaceAliasDeclaration*>(top->childContexts()[2]->localDeclarations()[0]);
|
|
QVERIFY(aliasDecl);
|
|
QCOMPARE(aliasDecl->importIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(aliasDecl->identifier(), Identifier("afoo"));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
|
|
QEXPECT_FAIL("", "Local namespace aliases currently don't work, bug 207548", Abort);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testDeclareUsingNamespace()
|
|
{
|
|
TEST_FILE_PARSE_ONLY
|
|
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("namespace foo { int bar; } using namespace foo; namespace alternativeFoo = foo; int test() { return bar; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(!top->parentContext());
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QVERIFY(top->localScopeIdentifier().isEmpty());
|
|
QVERIFY(findDeclaration(top, Identifier("foo")));
|
|
QCOMPARE(top->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->size(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(0), RangeInRevision(0, 65-22, 0, 68-22));
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->at(1), RangeInRevision(0, 97-22, 0, 100-22));
|
|
|
|
|
|
// QCOMPARE(top->localDeclarations()[0]->range()
|
|
QCOMPARE(top->localDeclarations()[1]->range(), RangeInRevision(0, 33, 0, 42));
|
|
kDebug() << top->localDeclarations()[2]->range().castToSimpleRange().textRange();
|
|
QCOMPARE(top->localDeclarations()[2]->range(), RangeInRevision(0, 58, 0, 72));
|
|
|
|
|
|
DUContext* fooCtx = top->childContexts().first();
|
|
QCOMPARE(fooCtx->childContexts().count(), 0);
|
|
QCOMPARE(fooCtx->localDeclarations().count(), 1);
|
|
QCOMPARE(fooCtx->localScopeIdentifier(), QualifiedIdentifier("foo"));
|
|
QCOMPARE(fooCtx->scopeIdentifier(), QualifiedIdentifier("foo"));
|
|
|
|
Declaration* bar = fooCtx->localDeclarations().first();
|
|
QVERIFY(!bar->isFunctionDeclaration());
|
|
QCOMPARE(bar->identifier(), Identifier("bar"));
|
|
QCOMPARE(bar->qualifiedIdentifier(), QualifiedIdentifier("foo::bar"));
|
|
QCOMPARE(bar->uses().count(), 1);
|
|
QCOMPARE(bar->uses().begin()->count(), 1);
|
|
//kDebug() << findDeclaration(top, bar->identifier(), top->range().start)->qualifiedIdentifier().toString();
|
|
QCOMPARE(findDeclaration(top, bar->identifier(), top->range().start), noDef);
|
|
QCOMPARE(findDeclaration(top, bar->identifier()), bar);
|
|
QCOMPARE(findDeclaration(top, bar->qualifiedIdentifier()), bar);
|
|
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("bar")), bar);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::bar")), bar); //iso c++ 3.4.3 says this must work
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("foo::bar")), bar);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::foo::bar")), bar);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("alternativeFoo::bar")), bar);
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("::alternativeFoo::bar")), bar);
|
|
|
|
DUContext* testCtx = top->childContexts()[2];
|
|
QVERIFY(testCtx->parentContext());
|
|
QCOMPARE(testCtx->importedParentContexts().count(), 1);
|
|
QCOMPARE(testCtx->childContexts().count(), 0);
|
|
QCOMPARE(testCtx->localDeclarations().count(), 0);
|
|
QCOMPARE(testCtx->localScopeIdentifier(), QualifiedIdentifier("test"));
|
|
QCOMPARE(testCtx->scopeIdentifier(), QualifiedIdentifier("test"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testSignalSlotDeclaration() {
|
|
{
|
|
QByteArray text("class C {__qt_signals__: void signal2(); public __qt_slots__: void slot2();}; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
|
|
ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[0]);
|
|
QVERIFY(classFun);
|
|
QVERIFY(classFun->accessPolicy() == ClassMemberDeclaration::Protected);
|
|
QVERIFY(classFun->isSignal());
|
|
|
|
classFun = dynamic_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[1]);
|
|
QVERIFY(classFun);
|
|
QVERIFY(classFun->accessPolicy() == ClassMemberDeclaration::Public);
|
|
QVERIFY(classFun->isSlot());
|
|
|
|
}
|
|
{
|
|
QByteArray text("namespace A { class B;} class Q { public __qt_slots__: void slot(A::B b, const Q* q); }; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QtFunctionDeclaration* qtDecl = dynamic_cast<QtFunctionDeclaration*>(top->childContexts()[1]->localDeclarations()[0]);
|
|
QVERIFY(qtDecl);
|
|
QCOMPARE(qtDecl->normalizedSignature().str(), QString("A::B,const Q*"));
|
|
|
|
}
|
|
{
|
|
// should be valid signals even if the arguments are not found
|
|
QByteArray text("class C {__qt_signals__: void signal2(NotFound); public __qt_slots__: void slot2(NotFound);}; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
|
|
ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[0]);
|
|
QVERIFY(classFun);
|
|
QVERIFY(classFun->accessPolicy() == ClassMemberDeclaration::Protected);
|
|
QVERIFY(classFun->isSignal());
|
|
|
|
classFun = dynamic_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[1]);
|
|
QVERIFY(classFun);
|
|
QVERIFY(classFun->accessPolicy() == ClassMemberDeclaration::Public);
|
|
QVERIFY(classFun->isSlot());
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testSignalSlotUse() {
|
|
{
|
|
QByteArray text("class TE; class QObject { void connect(QObject* from, const char* signal, QObject* to, const char* slot); void connect(QObject* from, const char* signal, const char* slot); }; class A : public QObject { public __qt_slots__: void slot1(); void slot2(TE*); __qt_signals__: void signal1(TE*, char);void signal2(); public: void test() { \nconnect(this, __qt_signal__( signal1(TE*, const char&)), this, __qt_slot__(slot2(TE*))); \nconnect(this, __qt_signal__(signal2()), \n__qt_slot__(slot1())); } };");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 5);
|
|
QtFunctionDeclaration* qtDecl = dynamic_cast<QtFunctionDeclaration*>(top->childContexts()[1]->localDeclarations()[0]);
|
|
QVERIFY(qtDecl);
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[0]->uses().count());
|
|
//kDebug() << top->childContexts()[1]->localDeclarations()[0]->uses().begin()->first().textRange();
|
|
//kDebug() << top->childContexts()[1]->localDeclarations()[1]->uses().begin()->first().textRange();
|
|
//kDebug() << top->childContexts()[1]->localDeclarations()[2]->uses().begin()->first().textRange();
|
|
//kDebug() << top->childContexts()[1]->localDeclarations()[3]->uses().begin()->first().textRange();
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->uses().begin()->first().castToSimpleRange().textRange(), RangeInRevision(3, 12, 3, 17).castToSimpleRange().textRange());
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[1]->uses().count());
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[1]->uses().begin()->first().castToSimpleRange().textRange(), RangeInRevision(1, 75, 1, 80).castToSimpleRange().textRange());
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[2]->uses().count());
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[2]->uses().begin()->first(), RangeInRevision(1, 29, 1, 36));
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[3]->uses().count());
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[3]->uses().begin()->first(), RangeInRevision(2, 28, 2, 35));
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->count(), 4);
|
|
|
|
}
|
|
{
|
|
QByteArray text("class QObject { void connect(QObject* from, const char* signal, QObject* to, const char* slot); void connect(QObject* from, const char* signal, const char* slot); }; struct AA : QObject { __qt_signals__: void signal1(int); void signal2(); };struct T{operator AA*() const; };class A : AA { public __qt_slots__: void slot1(); void slot2(); __qt_signals__: void signal1();public: void test() {T t;connect(t, __qt_signal__(signal2()), this, __qt_slot__(slot2()));connect(this, __qt_signal__(signal1(int)), __qt_slot__(slot1())); } }; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations().count(), 4);
|
|
QVERIFY(top->childContexts()[3]->localDeclarations()[0]->uses().count());
|
|
QVERIFY(top->childContexts()[3]->localDeclarations()[1]->uses().count());
|
|
QVERIFY(!top->childContexts()[3]->localDeclarations()[2]->uses().count()); //signal1() is not used
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 2);
|
|
ClassDeclaration* classAA = dynamic_cast<ClassDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(classAA);
|
|
QCOMPARE(classAA->baseClassesSize(), 1u);
|
|
QCOMPARE(classAA->baseClasses()[0].access, Declaration::Public);
|
|
ClassDeclaration* classA = dynamic_cast<ClassDeclaration*>(top->localDeclarations()[3]);
|
|
QVERIFY(classA);
|
|
QCOMPARE(classA->baseClassesSize(), 1u);
|
|
QCOMPARE(classA->baseClasses()[0].access, Declaration::Private);
|
|
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[0]->uses().count());
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[1]->uses().count());
|
|
|
|
}
|
|
{
|
|
// test signals without full signal signature specification
|
|
QByteArray text("class QObject { void connect(QObject* from, const char* signal, QObject* to, const char* slot);\n"
|
|
" void connect(QObject* from, const char* signal, const char* slot); };\n"
|
|
"struct AA : QObject { __qt_signals__: void signal1(bool arg1 = false); };\n"
|
|
"class A : AA { public __qt_slots__: void slot1();\n"
|
|
" public: void test() { connect(this, __qt_signal__(signal1()), this, __qt_slot__(slot1()));} };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts().at(1)->localDeclarations().size(), 1);
|
|
ClassFunctionDeclaration* sig = dynamic_cast<ClassFunctionDeclaration*>(top->childContexts().at(1)->localDeclarations().first());
|
|
QVERIFY(sig);
|
|
QVERIFY(sig->identifier() == Identifier("signal1"));
|
|
QVERIFY(sig->isSignal());
|
|
QCOMPARE(sig->uses().size(), 1);
|
|
QCOMPARE(sig->uses().begin()->count(), 1);
|
|
QCOMPARE(sig->uses().begin()->first(), RangeInRevision(4, 52, 4, 59));
|
|
}
|
|
{
|
|
QByteArray text("int main() { const char* signal; signal = __qt_signal__(someSignal()); }");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts().at(1)->localDeclarations().size(), 1);
|
|
Declaration* sig =
|
|
dynamic_cast<Declaration*>(top->childContexts().at(1)->localDeclarations().first());
|
|
QVERIFY(sig);
|
|
QVERIFY(sig->identifier() == Identifier("signal"));
|
|
QCOMPARE(sig->uses().size(), 1);
|
|
QCOMPARE(sig->uses().begin()->count(), 1);
|
|
QCOMPARE(sig->uses().begin()->first(), RangeInRevision(0, 33, 0, 39));
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition() {
|
|
// 0 1 2 3 4 5 6 7
|
|
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray text("class B{}; class A { char at(B* b); A(); ~A(); }; \n char A::at(B* b) {B* b; at(b); }; A::A() : i(3) {}; A::~A() {}; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 8);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 3);
|
|
|
|
QCOMPARE(top->childContexts()[4]->type(), DUContext::Function);
|
|
|
|
Declaration* atInA = top->childContexts()[1]->localDeclarations()[0];
|
|
|
|
QVERIFY(dynamic_cast<AbstractFunctionDeclaration*>(atInA));
|
|
|
|
QVERIFY(atInA->internalContext());
|
|
QCOMPARE(atInA->internalContext()->range(), RangeInRevision(0, 29, 0, 33));
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
|
|
QVERIFY(top->localDeclarations()[1]->logicalInternalContext(top));
|
|
QVERIFY(!top->childContexts()[1]->localDeclarations()[0]->isDefinition());
|
|
QVERIFY(!top->childContexts()[1]->localDeclarations()[1]->isDefinition());
|
|
QVERIFY(!top->childContexts()[1]->localDeclarations()[2]->isDefinition());
|
|
|
|
QVERIFY(top->localDeclarations()[2]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[3]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[4]->isDefinition());
|
|
|
|
QVERIFY(top->localDeclarations()[2]->internalContext());
|
|
QVERIFY(top->localDeclarations()[3]->internalContext());
|
|
QVERIFY(top->localDeclarations()[4]->internalContext());
|
|
|
|
QCOMPARE(top->localDeclarations()[2]->internalContext()->owner(), top->localDeclarations()[2]);
|
|
QCOMPARE(top->localDeclarations()[3]->internalContext()->owner(), top->localDeclarations()[3]);
|
|
QCOMPARE(top->localDeclarations()[4]->internalContext()->owner(), top->localDeclarations()[4]);
|
|
|
|
QVERIFY(top->localDeclarations()[1]->logicalInternalContext(top));
|
|
|
|
QVERIFY(dynamic_cast<FunctionDefinition*>(top->localDeclarations()[2]));
|
|
QCOMPARE(static_cast<FunctionDefinition*>(top->localDeclarations()[2])->declaration(), top->childContexts()[1]->localDeclarations()[0]);
|
|
QCOMPARE(top->localDeclarations()[2], FunctionDefinition::definition(top->childContexts()[1]->localDeclarations()[0]));
|
|
|
|
QVERIFY(dynamic_cast<FunctionDefinition*>(top->localDeclarations()[3]));
|
|
QCOMPARE(static_cast<FunctionDefinition*>(top->localDeclarations()[3])->declaration(), top->childContexts()[1]->localDeclarations()[1]);
|
|
QCOMPARE(top->localDeclarations()[3], FunctionDefinition::definition(top->childContexts()[1]->localDeclarations()[1]));
|
|
QCOMPARE(top->childContexts()[5]->owner(), top->localDeclarations()[3]);
|
|
QVERIFY(!top->childContexts()[5]->localScopeIdentifier().isEmpty());
|
|
|
|
QVERIFY(top->localDeclarations()[1]->logicalInternalContext(top));
|
|
QVERIFY(dynamic_cast<FunctionDefinition*>(top->localDeclarations()[4]));
|
|
QCOMPARE(static_cast<FunctionDefinition*>(top->localDeclarations()[4])->declaration(), top->childContexts()[1]->localDeclarations()[2]);
|
|
QCOMPARE(top->localDeclarations()[4], FunctionDefinition::definition(top->childContexts()[1]->localDeclarations()[2]));
|
|
|
|
QVERIFY(top->localDeclarations()[1]->logicalInternalContext(top));
|
|
|
|
QCOMPARE(top->childContexts()[3]->owner(), top->localDeclarations()[2]);
|
|
QCOMPARE(top->childContexts()[3]->importedParentContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[3]->importedParentContexts()[0].context(0), top->childContexts()[2]);
|
|
|
|
QCOMPARE(top->childContexts()[2]->importedParentContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->importedParentContexts()[0].context(0), top->childContexts()[1]);
|
|
|
|
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("at")), noDef);
|
|
|
|
QVERIFY(top->localDeclarations()[2]->internalContext());
|
|
QCOMPARE(top->localDeclarations()[2]->internalContext()->localDeclarations().count(), 1);
|
|
|
|
}
|
|
|
|
Declaration* declaration(Declaration* decl, TopDUContext* top = 0) {
|
|
FunctionDefinition* def = dynamic_cast<FunctionDefinition*>(decl);
|
|
if(!def)
|
|
return 0;
|
|
return def->declaration(top);
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition2() {
|
|
{
|
|
QByteArray text("//????\nclass B{B();}; B::B() {} "); //the ???? tests whether the column-numbers are resistant to special characters
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0], declaration(top->localDeclarations()[1], top->topContext()));
|
|
|
|
QCOMPARE(top->childContexts()[1]->type(), DUContext::Function);
|
|
QCOMPARE(top->childContexts()[1]->range().start.column, 20);
|
|
QCOMPARE(top->childContexts()[1]->range().end.column, 20);
|
|
//Many parts of kdevelop assume that the compound parens are included in the range, so it has to stay like that
|
|
QCOMPARE(top->childContexts()[0]->range(), RangeInRevision(1, 7, 1, 13));
|
|
QCOMPARE(top->childContexts()[2]->range(), RangeInRevision(1, 22, 1, 24));
|
|
|
|
QVERIFY(!top->childContexts()[2]->inSymbolTable());
|
|
|
|
}
|
|
{
|
|
QByteArray text("void test(int a, int cc);"); //the ???? tests whether the column-numbers are resistant to special characters
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[0]->range().start.column, 10);
|
|
QCOMPARE(top->childContexts()[0]->range().end.column, 23);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->range().start.column, 21);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->range().end.column, 23);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->range().start.column, 14);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->range().end.column, 15);
|
|
|
|
}
|
|
|
|
{
|
|
QByteArray text("void test(int, int&);");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition4() {
|
|
QByteArray text("class B{ B(); }; namespace A{class B{B();};} namespace A{ B::B() {} } ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->isDefinition());
|
|
QCOMPARE(declaration(top->childContexts()[2]->localDeclarations()[0]), top->childContexts()[1]->childContexts()[0]->localDeclarations()[0]);
|
|
//Verify that the function-definition context also imports the correct class context
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->internalContext()->imports(top->childContexts()[1]->childContexts()[0]));
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition3() {
|
|
QByteArray text("class B{template<class T> void test(T t); B(int i); int test(int a); int test(char a); template<class T2, class T3> void test(T2 t, T3 t3); int test(Unknown k); int test(Unknown2 k); }; template<class T> void B::test(T t) {}; B::B(int) {}; int B::test(int a){}; int B::test(char a){}; template<class T2, class T3> void B::test(T2 t, T3 t3) {}; int B::test(Unknown k){}; int B::test( Unknown2 k) {}; ");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 17);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 7);
|
|
QCOMPARE(top->localDeclarations().count(), 8);
|
|
|
|
QVERIFY(top->localDeclarations()[0]->isDefinition()); //Class-declarations are considered definitions too.
|
|
QVERIFY(top->localDeclarations()[1]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[2]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[3]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[4]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[5]->isDefinition());
|
|
QVERIFY(top->localDeclarations()[6]->isDefinition());
|
|
|
|
kDebug() << top->childContexts()[0]->localDeclarations()[0]->toString();
|
|
kDebug() << declaration(top->localDeclarations()[1], top->topContext())->toString();
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0], declaration(top->localDeclarations()[1], top->topContext()));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1], declaration(top->localDeclarations()[2], top->topContext()));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[2], declaration(top->localDeclarations()[3], top->topContext()));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[3], declaration(top->localDeclarations()[4], top->topContext()));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[4], declaration(top->localDeclarations()[5], top->topContext()));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[5], declaration(top->localDeclarations()[6], top->topContext()));
|
|
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition5() {
|
|
QByteArray text("class Class {typedef Class ClassDef;void test(ClassDef);Class();}; void Class::test(ClassDef i) {Class c;}");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().count(), 1); //Used from 1 file
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->count(), 2); //Used 2 times
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 1);
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition6() {
|
|
QByteArray text("class Class {Class(); void test();}; void Class::test(Class c) {int i;}");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
//Here we do an update, since there was a bug where updating caused problems here
|
|
parse(text, DumpNone, top);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QList<Declaration*> decls = top->findDeclarations(QualifiedIdentifier("Class"));
|
|
QCOMPARE(decls.size(), 1);
|
|
kDebug() << "qualified identifier:" << top->childContexts()[0]->localDeclarations()[0]->qualifiedIdentifier();
|
|
QVERIFY(!dynamic_cast<FunctionDefinition*>(top->childContexts()[0]->localDeclarations()[0]));
|
|
QVERIFY(dynamic_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[0]));
|
|
QVERIFY(static_cast<ClassFunctionDeclaration*>(top->childContexts()[0]->localDeclarations()[0])->isConstructor());
|
|
kDebug() << top->childContexts()[1]->localDeclarations()[0]->abstractType()->toString();
|
|
QCOMPARE(top->localDeclarations()[1], top->childContexts()[2]->owner());
|
|
QCOMPARE(Cpp::localClassFromCodeContext(top->childContexts()[2]), top->localDeclarations()[0]);
|
|
QCOMPARE(Cpp::localClassFromCodeContext(top->childContexts()[1]), top->localDeclarations()[0]);
|
|
QVERIFY(top->childContexts()[1]->importers().contains(top->childContexts()[2]));
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->abstractType()->indexed(), top->localDeclarations()[0]->abstractType()->indexed());
|
|
}
|
|
|
|
void TestDUChain::testFunctionDefinition7() {
|
|
QByteArray text("class ClassA {};\n\
|
|
template<typename E_T1>\n\
|
|
class ClassE\n\
|
|
{\n\
|
|
public:\n\
|
|
template<typename E_A_T1>\n\
|
|
void E_FuncA(E_A_T1)\n\
|
|
{\n\
|
|
}\n\
|
|
};\n\
|
|
template<typename E_T1>\n\
|
|
ClassE<E_T1>::~ClassE() = default;\n\
|
|
template<>\n\
|
|
template<>\n\
|
|
void ClassE<ClassA>::E_FuncA<ClassA>(ClassA);\n\
|
|
template<>\n\
|
|
template<>\n\
|
|
void ClassE<ClassA>::E_FuncA<ClassA>(ClassA)\n\
|
|
{\n\
|
|
}");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
QVERIFY(dynamic_cast<FunctionDefinition*>(top->localDeclarations()[2]));
|
|
QVERIFY(!dynamic_cast<FunctionDefinition*>(top->localDeclarations()[3]));
|
|
QVERIFY(dynamic_cast<FunctionDefinition*>(top->localDeclarations()[4]));
|
|
}
|
|
|
|
void TestDUChain::testLoopNamespaceImport() {
|
|
QByteArray text("namespace A {int i;} namespace B { using namespace A; } namespace A{ using namespace B; }; using namespace B; void test() { i += 5; }");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 5);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QVERIFY(!top->childContexts()[0]->localDeclarations()[0]->uses().isEmpty());
|
|
|
|
}
|
|
|
|
void TestDUChain::testConstructorUses()
|
|
{
|
|
{
|
|
QByteArray text = "struct A { A(A); A(A,A); }; void test() { A w; A a(A(w), A(w, w), w); }";
|
|
LockedTopDUContext top = parse(text, DumpAll);
|
|
QCOMPARE(top->childContexts().size(), 3);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations()[0]->uses().begin()->size(), 4);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
}
|
|
|
|
{
|
|
// also see https://bugs.kde.org/show_bug.cgi?id=300347
|
|
const QByteArray text = "struct B { B(); }; void test() { B a; B b(); }";
|
|
LockedTopDUContext top = parse(text, DumpAll);
|
|
QCOMPARE(top->childContexts().size(), 3);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().size(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 2);
|
|
|
|
// Grab first use of B(), 'B a' => range points to position after 'a', start == end
|
|
RangeInRevision range = top->childContexts()[0]->localDeclarations()[0]->uses().begin().value()[0];
|
|
QCOMPARE(range, RangeInRevision(0, 36, 0, 36));
|
|
// Grab second use of B(), 'B b()' => range points to '('
|
|
range = top->childContexts()[0]->localDeclarations()[0]->uses().begin().value()[1];
|
|
QCOMPARE(range, RangeInRevision(0, 41, 0, 42));
|
|
}
|
|
|
|
{
|
|
// NOTE: This test is currently broken because only the 2nd case is reported.
|
|
QByteArray text;
|
|
text += "class Q {\n";
|
|
text += "public:\n";
|
|
text += " Q(int var) { }\n";
|
|
text += " Q() { }\n";
|
|
text += "};\n";
|
|
text += "class B : public Q {\n";
|
|
text += "public:\n";
|
|
text += " B(int var) : Q(var) { }\n";
|
|
text += " B() : Q() { }\n";
|
|
text += "};\n";
|
|
text += "int main(int argc, char* argv[]) {\n";
|
|
text += " Q a1(123);\n";
|
|
text += " Q a2 = Q(123);\n";
|
|
text += " Q *a3 = new Q(123);\n";
|
|
text += " Q a4(argc);\n";
|
|
text += " Q a12();\n";
|
|
text += " Q a22 = Q();\n";
|
|
text += " Q *a32 = new Q();\n";
|
|
text += "}\n";
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().size(), 4);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 2);
|
|
|
|
// Q(int var)
|
|
Declaration *ctorDecl = top->childContexts()[0]->localDeclarations()[0];
|
|
QCOMPARE(ctorDecl->uses().size(), 1);
|
|
QList<RangeInRevision> uses = ctorDecl->uses().values().first();
|
|
|
|
QCOMPARE(uses.size(), 5);
|
|
QCOMPARE(uses[0], RangeInRevision(7, 16, 7, 17));
|
|
QCOMPARE(uses[1], RangeInRevision(11, 7, 11, 8));
|
|
QCOMPARE(uses[2], RangeInRevision(12, 11, 12, 12));
|
|
QCOMPARE(uses[3], RangeInRevision(13, 15, 13, 16));
|
|
QCOMPARE(uses[4], RangeInRevision(14, 7, 14, 8));
|
|
|
|
// Q()
|
|
ctorDecl = top->childContexts()[0]->localDeclarations()[1];
|
|
QCOMPARE(ctorDecl->uses().size(), 1);
|
|
uses = ctorDecl->uses().values().first();
|
|
|
|
QCOMPARE(uses.size(), 4);
|
|
QCOMPARE(uses[0], RangeInRevision(8, 9, 8, 10));
|
|
QCOMPARE(uses[1], RangeInRevision(15, 8, 15, 9));
|
|
QCOMPARE(uses[2], RangeInRevision(16, 12, 16, 13));
|
|
QCOMPARE(uses[3], RangeInRevision(17, 16, 17, 17));
|
|
|
|
}
|
|
{
|
|
QByteArray text;
|
|
text += "template<typename T>\n";
|
|
text += "class Q {\n";
|
|
text += "public:\n";
|
|
text += " Q(T var) { }\n";
|
|
text += " Q() { }\n";
|
|
text += "};\n";
|
|
text += "template<typename T>\n";
|
|
text += "class B : public Q<T> {\n";
|
|
text += "public:\n";
|
|
text += " B(T var) : Q<T>(var) { }\n";
|
|
text += " B() : Q<T>() { }\n";
|
|
text += "};\n";
|
|
text += "int main(int argc, char* argv[]) {\n";
|
|
text += " Q<int> a1(123);\n";
|
|
text += " Q<int> a2 = Q<int>(123);\n";
|
|
text += " Q<int> *a3 = new Q<int>(123);\n";
|
|
text += " Q<int> a4(argc);\n";
|
|
text += " Q<int> a12();\n";
|
|
text += " Q<int> a22 = Q<int>();\n";
|
|
text += " Q<int> *a32 = new Q<int>();\n";
|
|
text += "}\n";
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().size(), 6);
|
|
// first one is the template context
|
|
QCOMPARE(top->childContexts()[1]->type(), DUContext::Class);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().size(), 2);
|
|
|
|
// Q(T var)
|
|
Declaration *ctorDecl = top->childContexts()[1]->localDeclarations()[0];
|
|
QEXPECT_FAIL("", "no uses get reported for ctors of template classes", Abort);
|
|
QCOMPARE(ctorDecl->uses().size(), 1);
|
|
///TODO
|
|
/*
|
|
QList<RangeInRevision> uses = ctorDecl->uses().values().first();
|
|
|
|
QCOMPARE(uses.size(), 5);
|
|
QCOMPARE(uses[0], RangeInRevision(7, 16, 7, 17));
|
|
QCOMPARE(uses[1], RangeInRevision(11, 7, 11, 8));
|
|
QCOMPARE(uses[2], RangeInRevision(12, 11, 12, 12));
|
|
QCOMPARE(uses[3], RangeInRevision(13, 15, 13, 16));
|
|
QCOMPARE(uses[4], RangeInRevision(14, 7, 14, 8));
|
|
|
|
// Q()
|
|
ctorDecl = top->childContexts()[1]->localDeclarations()[1];
|
|
QCOMPARE(ctorDecl->uses().size(), 1);
|
|
uses = ctorDecl->uses().values().first();
|
|
|
|
QCOMPARE(uses.size(), 4);
|
|
QCOMPARE(uses[0], RangeInRevision(8, 9, 8, 10));
|
|
QCOMPARE(uses[1], RangeInRevision(15, 8, 15, 9));
|
|
QCOMPARE(uses[2], RangeInRevision(16, 12, 16, 13));
|
|
QCOMPARE(uses[3], RangeInRevision(17, 16, 17, 17));
|
|
*/
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testCodeModel() {
|
|
QByteArray text("class C{}; void test() {}; ");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
uint itemCount;
|
|
const CodeModelItem* items;
|
|
CodeModel::self().items( top->url(), itemCount, items );
|
|
|
|
uint validCount = 0;
|
|
for(uint a = 0; a < itemCount; ++a) {
|
|
if(items[a].id.isValid()) {
|
|
if(items[a].id == QualifiedIdentifier("C"))
|
|
QVERIFY(items[a].kind == CodeModelItem::Class);
|
|
if(items[a].id == QualifiedIdentifier("test"))
|
|
QVERIFY(items[a].kind == CodeModelItem::Function);
|
|
++validCount;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testDoWhile() {
|
|
QByteArray text("void test() { int i; do { i = 2; i -= 3; } while(1); ");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 2);
|
|
kDebug() << top->childContexts()[1]->childContexts()[0] << top->childContexts()[1] << top;
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->usesCount(), 2);
|
|
|
|
}
|
|
|
|
void TestDUChain::testEnumOverride() {
|
|
QByteArray text("class B{class BA{};};class A{enum {B}; B::BA ba; };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->indexedType(), top->childContexts()[1]->localDeclarations()[1]->indexedType());
|
|
|
|
}
|
|
|
|
//Makes sure constructores cannot shadow the class itself
|
|
void TestDUChain::testDeclareSubClass() {
|
|
QByteArray text("class Enclosing { class Class {Class(); class SubClass; class Frog; }; class Beach; }; class Enclosing::Class::SubClass { Class c; Frog f; Beach b; };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().count(), 3);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->localDeclarations().count(), 3); //A virtual context is placed around SubClass
|
|
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->scopeIdentifier(true), QualifiedIdentifier("Enclosing::Class"));
|
|
QVERIFY(top->childContexts()[0]->childContexts()[0]->inSymbolTable());
|
|
|
|
//Verify that "Class c" is matched correctly
|
|
QVERIFY(top->childContexts()[1]->childContexts()[0]->localDeclarations()[0]->abstractType().unsafeData());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[0]->localDeclarations()[0]->type<DelayedType>().unsafeData());
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->localDeclarations()[0]->abstractType()->indexed(), top->childContexts()[0]->localDeclarations()[0]->abstractType()->indexed());
|
|
|
|
//Verify that Frog is found
|
|
QVERIFY(top->childContexts()[1]->childContexts()[0]->localDeclarations()[1]->abstractType().unsafeData());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[0]->localDeclarations()[1]->type<DelayedType>().unsafeData());
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->localDeclarations()[1]->abstractType()->indexed(), top->childContexts()[0]->childContexts()[0]->localDeclarations()[2]->abstractType()->indexed());
|
|
|
|
//Make sure Beach is found
|
|
QVERIFY(top->childContexts()[1]->childContexts()[0]->localDeclarations()[2]->abstractType().unsafeData());
|
|
QVERIFY(!top->childContexts()[1]->childContexts()[0]->localDeclarations()[2]->type<DelayedType>().unsafeData());
|
|
QCOMPARE(top->childContexts()[1]->childContexts()[0]->localDeclarations()[2]->abstractType()->indexed(), top->childContexts()[0]->localDeclarations()[1]->abstractType()->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testBaseClasses() {
|
|
QByteArray text("class A{int aValue; }; class B{int bValue;}; class C : public A{int cValue;}; class D : public A, B {int dValue;}; template<class Base> class F : public Base { int fValue;};");
|
|
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
Declaration* defClassA = top->localDeclarations().first();
|
|
QCOMPARE(defClassA->identifier(), Identifier("A"));
|
|
QVERIFY(defClassA->type<CppClassType>());
|
|
|
|
Declaration* defClassB = top->localDeclarations()[1];
|
|
QCOMPARE(defClassB->identifier(), Identifier("B"));
|
|
QVERIFY(defClassB->type<CppClassType>());
|
|
|
|
ClassDeclaration* defClassC = dynamic_cast<ClassDeclaration*>(top->localDeclarations()[2]);
|
|
QVERIFY(defClassC);
|
|
QCOMPARE(defClassC->identifier(), Identifier("C"));
|
|
QVERIFY(defClassC->type<CppClassType>());
|
|
QCOMPARE( defClassC->baseClassesSize(), 1u );
|
|
|
|
ClassDeclaration* defClassD = dynamic_cast<ClassDeclaration*>(top->localDeclarations()[3]);
|
|
QVERIFY(defClassD);
|
|
QCOMPARE(defClassD->identifier(), Identifier("D"));
|
|
QVERIFY(defClassD->type<CppClassType>());
|
|
QCOMPARE( defClassD->baseClassesSize(), 2u );
|
|
|
|
QVERIFY( findDeclaration( defClassD->internalContext(), Identifier("dValue") ) );
|
|
QVERIFY( !findDeclaration( defClassD->internalContext(), Identifier("cValue") ) );
|
|
QVERIFY( findDeclaration( defClassD->internalContext(), Identifier("aValue") ) );
|
|
QVERIFY( findDeclaration( defClassD->internalContext(), Identifier("bValue") ) );
|
|
|
|
QVERIFY( !findDeclaration( defClassC->internalContext(), Identifier("dValue") ) );
|
|
QVERIFY( findDeclaration( defClassC->internalContext(), Identifier("cValue") ) );
|
|
QVERIFY( !findDeclaration( defClassC->internalContext(), Identifier("bValue") ) );
|
|
QVERIFY( findDeclaration( defClassC->internalContext(), Identifier("aValue") ) );
|
|
|
|
QVERIFY( !findDeclaration( defClassB->internalContext(), Identifier("dValue") ) );
|
|
QVERIFY( !findDeclaration( defClassB->internalContext(), Identifier("cValue") ) );
|
|
QVERIFY( findDeclaration( defClassB->internalContext(), Identifier("bValue") ) );
|
|
QVERIFY( !findDeclaration( defClassB->internalContext(), Identifier("aValue") ) );
|
|
|
|
QVERIFY( !findDeclaration( defClassA->internalContext(), Identifier("dValue") ) );
|
|
QVERIFY( !findDeclaration( defClassA->internalContext(), Identifier("cValue") ) );
|
|
QVERIFY( !findDeclaration( defClassA->internalContext(), Identifier("bValue") ) );
|
|
QVERIFY( findDeclaration( defClassA->internalContext(), Identifier("aValue") ) );
|
|
|
|
///Now test a template-class as base-class
|
|
ClassDeclaration* defClassF = dynamic_cast<ClassDeclaration*>(top->localDeclarations()[4]);
|
|
QVERIFY(defClassF);
|
|
QCOMPARE(defClassF->identifier(), Identifier("F"));
|
|
QVERIFY(defClassF->type<CppClassType>());
|
|
QCOMPARE( defClassF->baseClassesSize(), 1u );
|
|
QVERIFY( defClassF->baseClasses()[0].baseClass.type<DelayedType>().unsafeData() );
|
|
|
|
Declaration* FDDecl = findDeclaration(top, QualifiedIdentifier("F<D>") );
|
|
QVERIFY(FDDecl);
|
|
QVERIFY(FDDecl->internalContext() != defClassF->internalContext());
|
|
|
|
QVERIFY( findDeclaration( FDDecl->internalContext(), Identifier("dValue") ) );
|
|
QVERIFY( !findDeclaration( FDDecl->internalContext(), Identifier("cValue") ) );
|
|
QVERIFY( findDeclaration( FDDecl->internalContext(), Identifier("aValue") ) );
|
|
QVERIFY( findDeclaration( FDDecl->internalContext(), Identifier("bValue") ) );
|
|
QVERIFY( findDeclaration( FDDecl->internalContext(), Identifier("fValue") ) );
|
|
|
|
}
|
|
|
|
void TestDUChain::testTypedefUnsignedInt() {
|
|
QByteArray method("typedef long unsigned int MyInt; MyInt v;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localDeclarations()[0]->abstractType());
|
|
QVERIFY(top->localDeclarations()[1]->abstractType());
|
|
QCOMPARE(top->localDeclarations()[0]->abstractType()->toString(), QString("MyInt"));
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType()->toString(), QString("MyInt"));
|
|
QCOMPARE(unAliasedType(top->localDeclarations()[0]->abstractType())->toString(), QString("long unsigned int"));
|
|
QCOMPARE(unAliasedType(top->localDeclarations()[1]->abstractType())->toString(), QString("long unsigned int"));
|
|
}
|
|
|
|
void TestDUChain::testTypedef() {
|
|
QByteArray method("/*This is A translation-unit*/ \n/*This is class A*/class A { }; \ntypedef A B;//This is a typedef\nvoid test() { };\nconst B c;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
|
|
Declaration* defClassA = top->localDeclarations().first();
|
|
QCOMPARE(defClassA->identifier(), Identifier("A"));
|
|
QVERIFY(defClassA->type<CppClassType>());
|
|
QCOMPARE(QString::fromUtf8(defClassA->comment()), QString("This is class A"));
|
|
|
|
DUContext* classA = top->childContexts().first();
|
|
QVERIFY(classA->parentContext());
|
|
QCOMPARE(classA->importedParentContexts().count(), 0);
|
|
QCOMPARE(classA->localScopeIdentifier(), QualifiedIdentifier("A"));
|
|
|
|
Declaration* defB = findDeclaration(top, Identifier("B"));
|
|
QVERIFY(defB->indexedType() != defClassA->indexedType());
|
|
QVERIFY(defB->isTypeAlias());
|
|
TypeAliasType::Ptr aliasType = defB->type<TypeAliasType>();
|
|
QVERIFY(aliasType);
|
|
QVERIFY(aliasType->type());
|
|
QCOMPARE(aliasType->type()->indexed(), defClassA->indexedType());
|
|
QCOMPARE(aliasType->declaration(top), defB);
|
|
QCOMPARE(defB->kind(), Declaration::Type);
|
|
QCOMPARE(QString::fromUtf8(defB->comment()), QString("This is a typedef"));
|
|
|
|
QCOMPARE(defB->logicalInternalContext(top), defClassA->logicalInternalContext(top));
|
|
|
|
Declaration* defC = findDeclaration(top, QualifiedIdentifier("c"));
|
|
QVERIFY(defC);
|
|
//The "const" has to be moved into the pointed-to type so it is correctly respected during type-conversions and such
|
|
QVERIFY(TypeUtils::unAliasedType(defC->abstractType()));
|
|
QVERIFY(TypeUtils::unAliasedType(defC->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
QVERIFY(defC->abstractType()->modifiers() & AbstractType::ConstModifier);
|
|
|
|
}
|
|
|
|
void TestDUChain::testTypedefFuncptr()
|
|
{
|
|
QByteArray method("typedef int (*func)(char c); func f('c');");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localDeclarations()[0]->abstractType());
|
|
QVERIFY(top->localDeclarations()[1]->abstractType());
|
|
QCOMPARE(top->localDeclarations()[0]->abstractType()->toString(), QString("func"));
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType()->toString(), QString("func"));
|
|
QCOMPARE(unAliasedType(top->localDeclarations()[0]->abstractType())->toString(), QString("function int (char)"));
|
|
QCOMPARE(unAliasedType(top->localDeclarations()[1]->abstractType())->toString(), QString("function int (char)"));
|
|
|
|
AbstractType::Ptr target = TypeUtils::targetTypeKeepAliases( top->localDeclarations()[1]->abstractType(), top);
|
|
const IdentifiedType* idType = dynamic_cast<const IdentifiedType*>( target.unsafeData() );
|
|
QVERIFY(idType);
|
|
QVERIFY(idType->declaration(top));
|
|
|
|
QCOMPARE(top->childContexts().at(0)->localDeclarations().count(), 1);
|
|
Declaration* dec = top->childContexts().at(0)->localDeclarations().first();
|
|
QCOMPARE(dec->toString(), QString("char c"));
|
|
}
|
|
|
|
void TestDUChain::testContextAssignment() {
|
|
QByteArray text("template<class A>class Class { enum{ Bla = A::a }; }; ");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->owner(), top->localDeclarations()[0]);
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[1]->childContexts().count(), 1);
|
|
|
|
QCOMPARE((void*)top->childContexts()[0]->owner(), (void*)0);
|
|
QVERIFY((void*)top->childContexts()[1]->localDeclarations()[0]->internalContext());
|
|
QCOMPARE((void*)top->childContexts()[1]->localDeclarations()[0]->internalContext(), top->childContexts()[1]->childContexts()[0]);
|
|
|
|
}
|
|
|
|
void TestDUChain::testSpecializedTemplates() {
|
|
{
|
|
QByteArray text("struct C{}; template<class T>class AsPointer {typedef T* Ptr;}; template<class T>class AsPointer<T*> {typedef T* Ptr;}; template<class T>class AsPointer<const T*> {typedef T* Ptr2;}; template<class T>class AsPointer<const T> {typedef T* Ptr2;};");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
TemplateDeclaration* base = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(base);
|
|
QCOMPARE(base->specializationsSize(), 3u);
|
|
|
|
TemplateDeclaration* sp3AsTemplate = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[3]);
|
|
//Must be const T*
|
|
QVERIFY(sp3AsTemplate);
|
|
QCOMPARE(sp3AsTemplate->specializedWith().information().templateParametersSize(), 1u);
|
|
kDebug() << "specialized with" << sp3AsTemplate->specializedWith().information().templateParameters()[0].abstractType()->toString();
|
|
QVERIFY(sp3AsTemplate->specializedWith().information().templateParameters()[0].abstractType());
|
|
QVERIFY(sp3AsTemplate->specializedWith().information().templateParameters()[0].type<PointerType>());
|
|
QVERIFY(! (sp3AsTemplate->specializedWith().information().templateParameters()[0].abstractType()->modifiers() & AbstractType::ConstModifier) );
|
|
QVERIFY(sp3AsTemplate->specializedWith().information().templateParameters()[0].type<PointerType>()->baseType());
|
|
QVERIFY(sp3AsTemplate->specializedWith().information().templateParameters()[0].type<PointerType>()->baseType().cast<DelayedType>());
|
|
QVERIFY(sp3AsTemplate->specializedWith().information().templateParameters()[0].type<PointerType>()->baseType().cast<DelayedType>()->identifier().isConstant());
|
|
|
|
|
|
|
|
Declaration* decl2 = findDeclaration(top, QualifiedIdentifier("AsPointer<const C>::Ptr2"));
|
|
Declaration* decl1 = findDeclaration(top, QualifiedIdentifier("AsPointer<C>::Ptr"));
|
|
Declaration* decl3 = findDeclaration(top, QualifiedIdentifier("AsPointer<C*>::Ptr"));
|
|
Declaration* decl4 = findDeclaration(top, QualifiedIdentifier("AsPointer<const C*>::Ptr2"));
|
|
|
|
QVERIFY(decl1);
|
|
QVERIFY(decl2);
|
|
QVERIFY(decl3);
|
|
QVERIFY(decl4);
|
|
|
|
QVERIFY(unAliasedType(decl1->abstractType()).cast<PointerType>());
|
|
QCOMPARE(unAliasedType(decl1->abstractType())->indexed(), unAliasedType(decl2->abstractType())->indexed());
|
|
QCOMPARE(unAliasedType(decl1->abstractType())->indexed(), unAliasedType(decl3->abstractType())->indexed());
|
|
QCOMPARE(unAliasedType(decl1->abstractType())->indexed(), unAliasedType(decl4->abstractType())->indexed());
|
|
|
|
}
|
|
{
|
|
QByteArray text("class A{}; class B{}; class C{}; template<class T,class T2> class E{typedef A Type1;}; template<class T2> class E<A,T2> { typedef B Type2; typedef T2 NotA; }; template<class T2> class E<T2,A> { typedef C Type3; typedef T2 NotA; };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 6);
|
|
|
|
Declaration* EDecl = top->localDeclarations()[3];
|
|
Declaration* E1Decl = top->localDeclarations()[4];
|
|
Declaration* E2Decl = top->localDeclarations()[5];
|
|
|
|
QVERIFY(EDecl->internalContext());
|
|
QVERIFY(EDecl->internalContext()->importedParentContexts().count());
|
|
QVERIFY(EDecl->internalContext()->importedParentContexts()[0].context(top)->type() == DUContext::Template);
|
|
QCOMPARE(EDecl->internalContext()->importedParentContexts()[0].context(top)->localDeclarations().count(), 2);
|
|
|
|
QVERIFY(E1Decl->internalContext());
|
|
QCOMPARE(E1Decl->internalContext()->importedParentContexts().count(), 1);
|
|
QCOMPARE(E1Decl->internalContext()->importedParentContexts()[0].context(top)->type(), DUContext::Template);
|
|
QCOMPARE(E1Decl->internalContext()->importedParentContexts()[0].context(top)->localDeclarations().count(), 1);
|
|
QCOMPARE(E1Decl->internalContext()->localDeclarations().count(), 2);
|
|
QCOMPARE(E1Decl->identifier().templateIdentifiersCount(), 2u);
|
|
QVERIFY(E2Decl->internalContext());
|
|
QCOMPARE(E2Decl->internalContext()->importedParentContexts().count(), 1);
|
|
QCOMPARE(E2Decl->internalContext()->importedParentContexts()[0].context(top)->type(), DUContext::Template);
|
|
QCOMPARE(E2Decl->internalContext()->importedParentContexts()[0].context(top)->localDeclarations().count(), 1);
|
|
QCOMPARE(E2Decl->identifier().templateIdentifiersCount(), 2u);
|
|
|
|
TemplateDeclaration* templateEDecl = dynamic_cast<TemplateDeclaration*>(EDecl);
|
|
TemplateDeclaration* templateE1Decl = dynamic_cast<TemplateDeclaration*>(E1Decl);
|
|
TemplateDeclaration* templateE2Decl = dynamic_cast<TemplateDeclaration*>(E2Decl);
|
|
kDebug() << E1Decl->identifier().toString();
|
|
QVERIFY(templateEDecl);
|
|
QVERIFY(templateE1Decl);
|
|
QVERIFY(templateE2Decl);
|
|
QCOMPARE(templateE1Decl->specializedWith().information().templateParametersSize(), 2u);
|
|
QCOMPARE(templateE2Decl->specializedWith().information().templateParametersSize(), 2u);
|
|
QVERIFY(!templateE1Decl->specializedWith().information().templateParameters()[0].type<DelayedType>());
|
|
kDebug() << typeid(*templateE1Decl->specializedWith().information().templateParameters()[1].abstractType()).name();
|
|
QVERIFY(templateE1Decl->specializedWith().information().templateParameters()[1].type<DelayedType>());
|
|
QVERIFY(templateE2Decl->specializedWith().information().templateParameters()[0].type<DelayedType>());
|
|
QVERIFY(!templateE2Decl->specializedWith().information().templateParameters()[1].type<DelayedType>());
|
|
|
|
QCOMPARE(dynamic_cast<TemplateDeclaration*>(templateE1Decl->specializedFrom().data()), templateEDecl);
|
|
QCOMPARE(dynamic_cast<TemplateDeclaration*>(templateE2Decl->specializedFrom().data()), templateEDecl);
|
|
|
|
Declaration* foundE1Specialization = findDeclaration(top, QualifiedIdentifier("E<A,C>::Type2"));
|
|
QVERIFY(foundE1Specialization);
|
|
Declaration* foundE1Specialization2 = findDeclaration(top, QualifiedIdentifier("E<A,C>::NotA"));
|
|
QVERIFY(foundE1Specialization2);
|
|
QCOMPARE(unAliasedType(foundE1Specialization2->abstractType())->indexed(), top->localDeclarations()[2]->indexedType());
|
|
|
|
Declaration* foundE2Specialization = findDeclaration(top, QualifiedIdentifier("E<C,A>::Type3"));
|
|
QVERIFY(foundE2Specialization);
|
|
Declaration* foundE2Specialization2 = findDeclaration(top, QualifiedIdentifier("E<C,A>::NotA"));
|
|
QVERIFY(foundE2Specialization2);
|
|
QCOMPARE(unAliasedType(foundE2Specialization2->abstractType())->indexed(), top->localDeclarations()[2]->indexedType());
|
|
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("E<C,A>")));
|
|
QCOMPARE(findDeclaration(top, QualifiedIdentifier("E<C,A>"))->identifier(), Identifier("E<C,A>"));
|
|
|
|
}
|
|
{
|
|
// Test template specializations of nested classes
|
|
QByteArray text("struct A { struct B { template<class T> struct C {}; }; };\n"
|
|
"template<> struct A::B::C<int> { typedef int Type; };\n");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
Declaration* specialization = findDeclaration(top, QualifiedIdentifier("A::B::C<int>::Type"));
|
|
QVERIFY(specialization);
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray text("template<class T>\n"
|
|
"class A { void foo(T arg); };\n"
|
|
"template<class T> void A<T>::foo(T arg) {}");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
TemplateDeclaration* base = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[0]);
|
|
QVERIFY(base);
|
|
QCOMPARE(base->specializationsSize(), 0u);
|
|
QCOMPARE(base->instantiations().size(), 1);
|
|
QCOMPARE(base->instantiations().begin().value()->specializationsSize(), 0u);
|
|
// use of class T in A<T>
|
|
QCOMPARE(top->childContexts().size(), 5);
|
|
QCOMPARE(top->childContexts().at(2)->type(), DUContext::Template);
|
|
QCOMPARE(top->childContexts().at(2)->localDeclarations().size(), 1);
|
|
QEXPECT_FAIL("", "The uses of T are not reported when we define the default implementation outside the class body", Abort);
|
|
QCOMPARE(top->childContexts().at(2)->localDeclarations().first()->uses().size(), 1);
|
|
QCOMPARE(top->childContexts().at(2)->localDeclarations().first()->uses().begin()->size(), 2);
|
|
QCOMPARE(top->childContexts().at(2)->localDeclarations().first()->uses().begin()->at(0), RangeInRevision(2, 22, 2, 23));
|
|
QCOMPARE(top->childContexts().at(2)->localDeclarations().first()->uses().begin()->at(1), RangeInRevision(2, 31, 2, 32));
|
|
}
|
|
}
|
|
|
|
int value( const AbstractType::Ptr& type ) {
|
|
const ConstantIntegralType* integral = dynamic_cast<const ConstantIntegralType*>(type.unsafeData());
|
|
if( integral )
|
|
return (int)integral->value<qint64>();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void TestDUChain::testTemplateRecursiveInstantiation()
|
|
{
|
|
{
|
|
QByteArray text("template<bool b> class A { public: bool member; enum { SizeWithFalse = sizeof(A<false>) }; };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
Declaration* aTrueDecl = findDeclaration(top, Identifier("A<true>"));
|
|
Declaration* aFalseDecl = findDeclaration(top, Identifier("A<false>"));
|
|
QVERIFY(aTrueDecl);
|
|
QVERIFY(aFalseDecl);
|
|
QVERIFY(aTrueDecl->internalContext());
|
|
QVERIFY(aFalseDecl->internalContext());
|
|
|
|
QCOMPARE(aFalseDecl->internalContext()->localDeclarations(top).count(), 2);
|
|
QCOMPARE(aTrueDecl->internalContext()->localDeclarations(top).count(), 2);
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testTemplateEnums()
|
|
{
|
|
{
|
|
QByteArray text("template<bool num> struct No {}; No<true> n;");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localDeclarations()[1]->abstractType());
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType()->toString(), QString("No< true >"));
|
|
|
|
}
|
|
{
|
|
QByteArray text("template<int num=5> struct No {}; No<> n;");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localDeclarations()[1]->abstractType());
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType()->toString(), QString("No< int(5) >"));
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->kind(), Declaration::Instance);
|
|
|
|
|
|
QCOMPARE(top->usesCount(), 1);
|
|
Declaration* used = top->usedDeclarationForIndex(top->uses()[0].m_declarationIndex);
|
|
QVERIFY(used);
|
|
QVERIFY(used->abstractType());
|
|
QCOMPARE(used->abstractType()->toString(), QString("No< int(5) >"));
|
|
}
|
|
{
|
|
QByteArray text("template<int num> struct No {}; No<9> n;");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QVERIFY(top->localDeclarations()[1]->abstractType());
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType()->toString(), QString("No< int(9) >"));
|
|
|
|
QCOMPARE(top->usesCount(), 1);
|
|
Declaration* used = top->usedDeclarationForIndex(top->uses()[0].m_declarationIndex);
|
|
QVERIFY(used);
|
|
QVERIFY(used->abstractType());
|
|
QCOMPARE(used->abstractType()->toString(), QString("No< int(9) >"));
|
|
}
|
|
{
|
|
QByteArray text("class A {enum { Val = 5}; }; class B { enum{ Val = 7 }; }; template<class C, int i> class Test { enum { TempVal = C::Val, Num = i, Sum = TempVal + i }; };");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
Declaration* testDecl = top->localDeclarations()[2];
|
|
|
|
TemplateDeclaration* templateTestDecl = dynamic_cast<TemplateDeclaration*>(testDecl);
|
|
QVERIFY(templateTestDecl);
|
|
|
|
Declaration* tempDecl = findDeclaration( top, QualifiedIdentifier("Test<A, 3>::TempVal") );
|
|
QVERIFY(tempDecl);
|
|
AbstractType::Ptr t = tempDecl->abstractType();
|
|
QVERIFY(!DelayedType::Ptr::dynamicCast(t));
|
|
QVERIFY(ConstantIntegralType::Ptr::dynamicCast(t));
|
|
QCOMPARE(value(tempDecl->abstractType()), 5);
|
|
|
|
tempDecl = findDeclaration( top, QualifiedIdentifier("Test<A, 3>::Num") );
|
|
QVERIFY(tempDecl);
|
|
QCOMPARE(value(tempDecl->abstractType()), 3);
|
|
|
|
tempDecl = findDeclaration( top, QualifiedIdentifier("Test<A, 3>::Sum") );
|
|
QVERIFY(tempDecl->abstractType());
|
|
QCOMPARE(value(tempDecl->abstractType()), 8);
|
|
|
|
tempDecl = findDeclaration( top, QualifiedIdentifier("Test<B, 9>::TempVal") );
|
|
QVERIFY(tempDecl->abstractType());
|
|
QCOMPARE(value(tempDecl->abstractType()), 7);
|
|
|
|
tempDecl = findDeclaration( top, QualifiedIdentifier("Test<B, 9>::Num") );
|
|
QVERIFY(tempDecl->abstractType());
|
|
t = tempDecl->abstractType();
|
|
kDebug() << "id" << typeid(*t).name();
|
|
kDebug() << "text:" << tempDecl->abstractType()->toString() << tempDecl->toString();
|
|
QCOMPARE(value(tempDecl->abstractType()), 9);
|
|
|
|
tempDecl = findDeclaration( top, QualifiedIdentifier("Test<B, 9>::Sum") );
|
|
QVERIFY(tempDecl->abstractType());
|
|
QCOMPARE(value(tempDecl->abstractType()), 16);
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testIntegralTemplates()
|
|
{
|
|
QByteArray text("template<class T> class A { T i; }; ");
|
|
LockedTopDUContext top = parse(text, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
Declaration* dec = findDeclaration( top, QualifiedIdentifier( "A<int>::i") );
|
|
QVERIFY(dec);
|
|
AbstractType::Ptr t = dec->abstractType();
|
|
IntegralType* integral = dynamic_cast<IntegralType*>( t.unsafeData() );
|
|
QVERIFY( integral );
|
|
QCOMPARE( integral->dataType(), (uint)IntegralType::TypeInt );
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
dec = findDeclaration( top, QualifiedIdentifier( "A<unsigned int>::i") );
|
|
t = dec->abstractType();
|
|
integral = dynamic_cast<IntegralType*>( t.unsafeData() );
|
|
QVERIFY( integral );
|
|
QCOMPARE( integral->dataType(), (uint)IntegralType::TypeInt );
|
|
QCOMPARE( integral->modifiers(), (unsigned long long)AbstractType::UnsignedModifier );
|
|
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
dec = findDeclaration( top, QualifiedIdentifier( "A<long double>::i") );
|
|
t = dec->abstractType();
|
|
integral = dynamic_cast<IntegralType*>( t.unsafeData() );
|
|
QVERIFY( integral );
|
|
QCOMPARE( integral->dataType(), (uint)IntegralType::TypeDouble );
|
|
QCOMPARE( integral->modifiers(), (unsigned long long)AbstractType::LongModifier );
|
|
|
|
}
|
|
|
|
void TestDUChain::testFunctionTemplates() {
|
|
QByteArray method("template<class T> T test(const T& t) {};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().size(), 3);
|
|
Declaration* defTest = top->localDeclarations()[0];
|
|
QVERIFY(top->childContexts()[0]->type() == DUContext::Template);
|
|
QCOMPARE(top->childContexts()[0]->importers().size(), 1);
|
|
kDebug() << top->childContexts()[0]->importers()[0] << top->childContexts()[1] << top->childContexts()[2];
|
|
QCOMPARE(top->childContexts()[0]->importers()[0], top->childContexts()[1]);
|
|
QCOMPARE(defTest->identifier(), Identifier("test"));
|
|
QVERIFY(defTest->type<FunctionType>());
|
|
QVERIFY( isTemplateDeclaration(defTest) );
|
|
QVERIFY(defTest->internalContext());
|
|
QCOMPARE(defTest->internalContext()->importedParentContexts().size(), 1);
|
|
KDevelop::DUContext* tempCtx = getTemplateContext(defTest);
|
|
QVERIFY(tempCtx);
|
|
|
|
QCOMPARE( defTest->type<FunctionType>()->arguments().count(), 1 );
|
|
QVERIFY( realType(defTest->type<FunctionType>()->arguments()[0], 0).cast<DelayedType>() );
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateFunctions() {
|
|
QByteArray method("class A {}; template<class T> T a(T& q) {};template<class T> struct TC { void test(const T&); };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
parse(method, DumpNone, top);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("a<A>"));
|
|
QVERIFY(d);
|
|
FunctionType::Ptr cppFunction = d->type<FunctionType>();
|
|
QVERIFY(cppFunction);
|
|
QCOMPARE(cppFunction->arguments().count(), 1);
|
|
QCOMPARE(cppFunction->returnType()->indexed(), top->localDeclarations()[0]->abstractType()->indexed());
|
|
QCOMPARE(cppFunction->arguments()[0]->toString(), QString("A&"));
|
|
QVERIFY(d->internalContext());
|
|
QVERIFY(d->internalContext()->type() == DUContext::Other);
|
|
QCOMPARE(d->internalContext()->importedParentContexts().count(), 1);
|
|
QCOMPARE(d->internalContext()->importedParentContexts()[0].context(0)->type(), DUContext::Function);
|
|
QCOMPARE(d->internalContext()->importedParentContexts()[0].context(0)->importedParentContexts().count(), 1);
|
|
QCOMPARE(d->internalContext()->importedParentContexts()[0].context(0)->importedParentContexts().count(), 1);
|
|
QCOMPARE(d->internalContext()->importedParentContexts()[0].context(0)->importedParentContexts()[0].context(0)->type(), DUContext::Template);
|
|
|
|
QList<QPair<Declaration*, int> > visibleDecls = d->internalContext()->allDeclarations(d->internalContext()->range().end, top, false);
|
|
for(int a = 0; a < visibleDecls.size(); ++a) {
|
|
kDebug() << "decl:" << visibleDecls[a].first->toString();
|
|
}
|
|
QCOMPARE(visibleDecls.size(), 2); //Must be q and T
|
|
QCOMPARE(visibleDecls[0].first->identifier().toString(), QString("q"));
|
|
QVERIFY(visibleDecls[0].first->abstractType());
|
|
QCOMPARE(visibleDecls[0].first->abstractType()->toString(), QString("A&"));
|
|
QVERIFY(visibleDecls[1].first->abstractType());
|
|
QCOMPARE(visibleDecls[1].first->abstractType()->toString(), QString("A"));
|
|
|
|
Declaration* found = findDeclaration(d->internalContext(), Identifier("q"));
|
|
QVERIFY(found);
|
|
QVERIFY(found->abstractType());
|
|
QCOMPARE(found->abstractType()->toString(), QString("A&"));
|
|
|
|
Declaration* instTC = findDeclaration(top, QualifiedIdentifier("TC<int>"));
|
|
QVERIFY(instTC);
|
|
QVERIFY(instTC->internalContext());
|
|
QList<Declaration*> decls = instTC->internalContext()->findLocalDeclarations(Identifier("test"));
|
|
QCOMPARE(decls.count(), 1);
|
|
Declaration* testDecl = decls.first();
|
|
QVERIFY(testDecl);
|
|
QVERIFY(testDecl->abstractType());
|
|
QVERIFY(testDecl->internalContext());
|
|
QVERIFY(testDecl->type<KDevelop::FunctionType>());
|
|
QCOMPARE(testDecl->internalContext()->localDeclarations(top).count(), 1);
|
|
kDebug() << testDecl->abstractType()->toString();
|
|
QCOMPARE(testDecl->type<KDevelop::FunctionType>()->arguments().count(), 1);
|
|
|
|
DUContext* argContext = KDevelop::DUChainUtils::getArgumentContext(testDecl);
|
|
QVERIFY(argContext);
|
|
QCOMPARE(argContext->type(), DUContext::Function);
|
|
QCOMPARE(argContext->localDeclarations(top).count(), 1);
|
|
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateDependentClass() {
|
|
QByteArray method("class A {}; template<class T> class B { class Q{ typedef T Type; }; }; B<A>::Q::Type t;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("t"));
|
|
QVERIFY(d);
|
|
kDebug() << d->toString();
|
|
QCOMPARE(unAliasedType(d->abstractType())->indexed(), top->localDeclarations()[0]->abstractType()->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testMetaProgramming() {
|
|
QByteArray method("template<int value> class Factorial{ enum { Value = value * Factorial<value-1>::Value };}; template<> class Factorial<0> { enum { Value = 1 };};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
TemplateDeclaration* templateBase = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[0]);
|
|
TemplateDeclaration* templateSpecialization = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(templateBase);
|
|
QVERIFY(templateSpecialization);
|
|
QVERIFY(templateBase->specializationsSize() == 1);
|
|
QCOMPARE(templateSpecialization->specializedFrom().data(), top->localDeclarations()[0]);
|
|
QCOMPARE(templateSpecialization->specializedWith().information().templateParametersSize(), 1u);
|
|
QVERIFY(templateSpecialization->specializedWith().information().templateParameters()[0].abstractType());
|
|
QVERIFY(templateSpecialization->specializedWith().information().templateParameters()[0].type<ConstantIntegralType>());
|
|
QCOMPARE(templateSpecialization->specializedWith().information().templateParameters()[0].type<ConstantIntegralType>()->value<int>(), 0);
|
|
kDebug() << "searching";
|
|
Declaration* factorial0Container = findDeclaration(top, QualifiedIdentifier("Factorial<0>"));
|
|
QCOMPARE(factorial0Container, top->localDeclarations()[1]);
|
|
QVERIFY(factorial0Container);
|
|
QCOMPARE(factorial0Container->internalContext()->childContexts().count(), 1);
|
|
QCOMPARE(factorial0Container->internalContext()->childContexts()[0]->localDeclarations().count(), 1);
|
|
QVERIFY(factorial0Container->internalContext()->childContexts()[0]->localDeclarations()[0]->type<ConstantIntegralType>());
|
|
|
|
Declaration* factorial0 = findDeclaration(top, QualifiedIdentifier("Factorial<0>::Value"));
|
|
QVERIFY(factorial0);
|
|
QVERIFY(factorial0->type<ConstantIntegralType>());
|
|
QCOMPARE(factorial0->type<ConstantIntegralType>()->value<int>(), 1);
|
|
|
|
Declaration* factorial2 = findDeclaration(top, QualifiedIdentifier("Factorial<2>::Value"));
|
|
QVERIFY(factorial2);
|
|
QVERIFY(factorial2->type<ConstantIntegralType>());
|
|
QCOMPARE(factorial2->type<ConstantIntegralType>()->value<int>(), 2);
|
|
|
|
Declaration* factorial3 = findDeclaration(top, QualifiedIdentifier("Factorial<3>::Value"));
|
|
QVERIFY(factorial3);
|
|
QVERIFY(factorial3->type<ConstantIntegralType>());
|
|
QCOMPARE(factorial3->type<ConstantIntegralType>()->value<int>(), 6);
|
|
|
|
Declaration* factorial4 = findDeclaration(top, QualifiedIdentifier("Factorial<4>::Value"));
|
|
QVERIFY(factorial4);
|
|
QVERIFY(factorial4->type<ConstantIntegralType>());
|
|
QCOMPARE(factorial4->type<ConstantIntegralType>()->value<int>(), 24);
|
|
|
|
}
|
|
|
|
void TestDUChain::testMetaProgramming3() {
|
|
QByteArray method("template<int value, int than>class bigger_than {enum {Result = ((value > than) ? 2 : ((value == than) ? 0 : -2))};};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
|
|
kDebug() << "test 1";
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("bigger_than<5, 3>::Result"));
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->type<ConstantIntegralType>());
|
|
QCOMPARE(decl->type<ConstantIntegralType>()->value<int>(), 2);
|
|
kDebug() << "test 2";
|
|
decl = findDeclaration(top, QualifiedIdentifier("bigger_than<5, 5>::Result"));
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->type<ConstantIntegralType>());
|
|
QCOMPARE(decl->type<ConstantIntegralType>()->value<int>(), 0);
|
|
|
|
decl = findDeclaration(top, QualifiedIdentifier("bigger_than<5, 6>::Result"));
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->type<ConstantIntegralType>());
|
|
QCOMPARE(decl->type<ConstantIntegralType>()->value<int>(), -2);
|
|
|
|
}
|
|
|
|
|
|
void TestDUChain::testMetaProgramming2() {
|
|
QByteArray method("template<int N, int R>class Permutations {public:enum { value = N*(Permutations<N-1,R-1>::value) };};template<int N>class Permutations<N, 0> {public:enum { value = 1 };};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
TemplateDeclaration* templateBase = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[0]);
|
|
TemplateDeclaration* templateSpecialization = dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[1]);
|
|
QVERIFY(templateBase);
|
|
QVERIFY(templateSpecialization);
|
|
QVERIFY(templateBase->specializationsSize() == 1);
|
|
QCOMPARE(templateSpecialization->specializedFrom().data(), top->localDeclarations()[0]);
|
|
QCOMPARE(templateSpecialization->specializedWith().information().templateParametersSize(), 2u);
|
|
QVERIFY(templateSpecialization->specializedWith().information().templateParameters()[1].abstractType());
|
|
QVERIFY(templateSpecialization->specializedWith().information().templateParameters()[1].type<ConstantIntegralType>());
|
|
QCOMPARE(templateSpecialization->specializedWith().information().templateParameters()[1].type<ConstantIntegralType>()->value<int>(), 0);
|
|
|
|
Declaration* permutations0 = findDeclaration(top, QualifiedIdentifier("Permutations<5, 0>::value"));
|
|
QVERIFY(permutations0);
|
|
QVERIFY(permutations0->type<ConstantIntegralType>());
|
|
QCOMPARE(permutations0->type<ConstantIntegralType>()->value<int>(), 1);
|
|
|
|
Declaration* permutations2 = findDeclaration(top, QualifiedIdentifier("Permutations<2, 1>::value"));
|
|
QVERIFY(permutations2);
|
|
QVERIFY(permutations2->type<ConstantIntegralType>());
|
|
QCOMPARE(permutations2->type<ConstantIntegralType>()->value<int>(), 2);
|
|
|
|
Declaration* permutations3 = findDeclaration(top, QualifiedIdentifier("Permutations<4, 2>::value"));
|
|
QVERIFY(permutations3);
|
|
QVERIFY(permutations3->type<ConstantIntegralType>());
|
|
QCOMPARE(permutations3->type<ConstantIntegralType>()->value<int>(), 12);
|
|
|
|
Declaration* permutations4 = findDeclaration(top, QualifiedIdentifier("Permutations<10, 5>::value"));
|
|
QVERIFY(permutations4);
|
|
QVERIFY(permutations4->type<ConstantIntegralType>());
|
|
kDebug() << permutations4->abstractType()->toString();
|
|
QCOMPARE(permutations4->type<ConstantIntegralType>()->value<int>(), 30240);
|
|
|
|
}
|
|
void TestDUChain::testTemplateInternalSearch() {
|
|
QByteArray method("class A {}; template<class T> class B { B mem(); const B mem2;}; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[2]->localDeclarations().count(), 2);
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[1]->type<DelayedType>());
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->type<FunctionType>());
|
|
QVERIFY(top->childContexts()[2]->localDeclarations()[0]->type<FunctionType>()->returnType().cast<DelayedType>());
|
|
|
|
Declaration* d = findDeclaration(top, QualifiedIdentifier("B<A>::mem"));
|
|
QVERIFY(d);
|
|
kDebug() << d->toString();
|
|
FunctionType::Ptr fType = d->type<FunctionType>();
|
|
QVERIFY(fType);
|
|
QVERIFY(fType->returnType());
|
|
kDebug() << fType->toString();
|
|
QCOMPARE(fType->returnType()->toString(), QString("B< A >"));
|
|
|
|
d = findDeclaration(top, QualifiedIdentifier("B<A>::mem2"));
|
|
QVERIFY(d);
|
|
QCOMPARE(d->abstractType()->toString(), QString("const B< A >"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateImplicitInstantiations()
|
|
{
|
|
{
|
|
QByteArray method("class A { template<typename T> static void foo(T){} };\n"
|
|
"void test() { A::foo(5); A::foo('x'); A::foo(\"asdfasdfadf\");\n }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().size(), 1);
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().size(), 1);
|
|
TemplateDeclaration* tpl = dynamic_cast<TemplateDeclaration*>(top->childContexts().first()->localDeclarations().first());
|
|
QVERIFY(tpl);
|
|
QCOMPARE(tpl->instantiations().size(), 3);
|
|
}
|
|
{
|
|
QByteArray method("template<typename T> void foo(T){}\n"
|
|
"void test() { foo(5); foo('x'); foo(\"asdfasdfadf\"); }\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
TemplateDeclaration* tpl = dynamic_cast<TemplateDeclaration*>(top->localDeclarations().first());
|
|
QVERIFY(tpl);
|
|
QCOMPARE(tpl->instantiations().size(), 3);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testSourceCodeInsertion()
|
|
{
|
|
{
|
|
QByteArray method("namespace A {\nclass B {};\n}\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
InsertArtificialCodeRepresentation repr(top->url(), QString::fromUtf8(method));
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(repr.text().trimmed().split('\n').count(), 3);
|
|
{
|
|
Cpp::SourceCodeInsertion ins(top);
|
|
ins.insertForwardDeclaration(top->childContexts()[0]->localDeclarations()[0]);
|
|
|
|
ins.changes().setReplacementPolicy(KDevelop::DocumentChangeSet::StopOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = ins.changes().applyAllChanges();
|
|
QVERIFY(result);
|
|
kDebug() << repr.text();
|
|
// QVERIFY(repr.text().trimmed().remove(' ').remove('\n').contains(QString("int testVar;").remove(' ')));
|
|
|
|
//Only one newline should be added
|
|
QCOMPARE(repr.text().trimmed().split('\n').count(), 4);
|
|
}
|
|
|
|
top = parse(repr.text().toUtf8(), DumpNone, top);
|
|
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
|
|
}
|
|
|
|
{
|
|
QByteArray method("");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
InsertArtificialCodeRepresentation repr(top->url(), QString::fromUtf8(method));
|
|
|
|
{
|
|
Cpp::SourceCodeInsertion ins(top);
|
|
ins.insertFunctionDeclaration(Identifier("test"), AbstractType::Ptr(new IntegralType(IntegralType::TypeVoid)), QList<Cpp::SourceCodeInsertion::SignatureItem>(), false, "{ this is the body; }");
|
|
ins.changes().setReplacementPolicy(KDevelop::DocumentChangeSet::StopOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = ins.changes().applyAllChanges();
|
|
kDebug() << result.m_failureReason;
|
|
QVERIFY(result);
|
|
kDebug() << repr.text();
|
|
QVERIFY(repr.text().trimmed().remove(' ').remove('\n').contains(QString("void test() { this is the body; }").remove(' ')));
|
|
|
|
//Only one newline should be added
|
|
QCOMPARE(repr.text().split('\n').count(), 2);
|
|
}
|
|
|
|
top = parse(repr.text().toUtf8(), DumpNone, top);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
|
|
{
|
|
Cpp::SourceCodeInsertion ins(top);
|
|
ins.insertVariableDeclaration(Identifier("testVar"), AbstractType::Ptr(new IntegralType(IntegralType::TypeInt)));
|
|
ins.changes().setReplacementPolicy(KDevelop::DocumentChangeSet::StopOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = ins.changes().applyAllChanges();
|
|
QVERIFY(result);
|
|
kDebug() << repr.text();
|
|
QVERIFY(repr.text().trimmed().remove(' ').remove('\n').contains(QString("int testVar;").remove(' ')));
|
|
|
|
//Only one newline should be added
|
|
QCOMPARE(repr.text().split('\n').count(), 3);
|
|
}
|
|
|
|
top = parse(repr.text().toUtf8(), DumpNone, top);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->identifier(), Identifier("test"));
|
|
QCOMPARE(top->localDeclarations()[1]->identifier(), Identifier("testVar"));
|
|
|
|
{
|
|
Cpp::SourceCodeInsertion ins(top);
|
|
ins.setInsertBefore(top->localDeclarations()[1]->range().start.castToSimpleCursor());
|
|
ins.insertForwardDeclaration(top->localDeclarations()[1]);
|
|
ins.changes().setReplacementPolicy(KDevelop::DocumentChangeSet::StopOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = ins.changes().applyAllChanges();
|
|
QVERIFY(result);
|
|
kDebug() << repr.text();
|
|
// QVERIFY(repr.text().trimmed().remove(' ').remove('\n').contains(QString("int testVar;").remove(' ')));
|
|
|
|
//Only one newline should be added
|
|
QCOMPARE(repr.text().trimmed().split('\n').count(), 3);
|
|
}
|
|
|
|
top = parse(repr.text().toUtf8(), DumpNone, top);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
///@todo Wrong order (Minor issue when updating without smart-ranges)
|
|
QCOMPARE(top->localDeclarations()[0]->identifier(), Identifier("test"));
|
|
QCOMPARE(top->localDeclarations()[1]->identifier(), Identifier("testVar"));
|
|
QCOMPARE(top->localDeclarations()[2]->identifier(), Identifier("testVar"));
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testSimplifiedTypeString()
|
|
{
|
|
{
|
|
QByteArray method("namespace A { struct B { B(); }; };");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->childContexts()[0]->localDeclarations().size(), 1);
|
|
|
|
QualifiedIdentifier constructorId = top->childContexts()[0]->childContexts()[0]->localDeclarations()[0]->qualifiedIdentifier();
|
|
QCOMPARE(constructorId.toString(), QString("A::B::B"));
|
|
QCOMPARE(stripPrefixes(top->childContexts()[0], constructorId).toString(), QString("B::B"));
|
|
QCOMPARE(stripPrefixes(top, constructorId).toString(), QString("A::B::B"));
|
|
|
|
}
|
|
{
|
|
QByteArray method("namespace A { namespace B { struct C {}; C* foo(const C& ref, const C value); } };");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QList<Declaration*> decls = top->findDeclarations(QualifiedIdentifier("A::B::foo"));
|
|
QCOMPARE(decls.size(), 1);
|
|
FunctionDeclaration* fooDecl = dynamic_cast<FunctionDeclaration*>(decls.first());
|
|
QVERIFY(fooDecl);
|
|
|
|
FunctionType::Ptr fooType = fooDecl->type<FunctionType>();
|
|
QVERIFY(fooType);
|
|
QCOMPARE(fooType->arguments().size(), 2);
|
|
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top), QString("A::B::C*"));
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[0]), QString("B::C*"));
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[0]->childContexts()[0]), QString("C*"));
|
|
|
|
// test stripping of const-ref
|
|
AbstractType::Ptr refType = fooType->arguments().at(0);
|
|
QVERIFY(refType.cast<ReferenceType>());
|
|
QVERIFY(refType.cast<ReferenceType>()->baseType());
|
|
QVERIFY(refType.cast<ReferenceType>()->baseType()->modifiers() & AbstractType::ConstModifier);
|
|
|
|
QCOMPARE(Cpp::shortenedTypeString(refType, top), QString("const A::B::C&"));
|
|
QCOMPARE(Cpp::shortenedTypeString(refType, top->childContexts()[0]), QString("const B::C&"));
|
|
QCOMPARE(Cpp::shortenedTypeString(refType, top->childContexts()[0]->childContexts()[0]), QString("const C&"));
|
|
|
|
// test stripping of const value
|
|
AbstractType::Ptr valType = fooType->arguments().at(1);
|
|
QVERIFY(valType->modifiers() & AbstractType::ConstModifier);
|
|
|
|
QCOMPARE(Cpp::shortenedTypeString(valType, top), QString("const A::B::C"));
|
|
QCOMPARE(Cpp::shortenedTypeString(valType, top->childContexts()[0]), QString("const B::C"));
|
|
QCOMPARE(Cpp::shortenedTypeString(valType, top->childContexts()[0]->childContexts()[0]), QString("const C"));
|
|
}
|
|
{
|
|
// a bit artificial, but similar to what you could reach with #include
|
|
QByteArray method("namespace A { namespace B { namespace C { struct D {}; D* foo(); } } }\nnamespace A { using namespace B::C; };");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QList<Declaration*> decls = top->findDeclarations(QualifiedIdentifier("A::B::C::foo"));
|
|
QCOMPARE(decls.size(), 1);
|
|
FunctionDeclaration* fooDecl = dynamic_cast<FunctionDeclaration*>(decls.first());
|
|
QVERIFY(fooDecl);
|
|
|
|
FunctionType::Ptr fooType = fooDecl->type<FunctionType>();
|
|
QVERIFY(fooType);
|
|
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top), QString("A::B::C::D*"));
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[0]), QString("B::C::D*"));
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[0]->childContexts()[0]), QString("C::D*"));
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[0]->childContexts()[0]->childContexts()[0]), QString("D*"));
|
|
|
|
// now the interesting part: the namespace with the "using namespace B::C"
|
|
QCOMPARE(Cpp::shortenedTypeString(fooType->returnType(), top->childContexts()[1]), QString("D*"));
|
|
}
|
|
{
|
|
QByteArray method("typedef int *honk, **honk2; honk k;");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
|
|
QVERIFY(top->localDeclarations()[0]->abstractType().cast<TypeAliasType>());
|
|
QVERIFY(top->localDeclarations()[1]->abstractType().cast<TypeAliasType>());
|
|
QVERIFY(top->localDeclarations()[2]->abstractType().cast<TypeAliasType>());
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->abstractType().cast<TypeAliasType>()->qualifiedIdentifier(), QualifiedIdentifier("honk"));
|
|
QCOMPARE(top->localDeclarations()[0]->abstractType().cast<TypeAliasType>()->type()->toString(), QString("int*"));
|
|
|
|
QCOMPARE(top->localDeclarations()[1]->abstractType().cast<TypeAliasType>()->qualifiedIdentifier(), QualifiedIdentifier("honk2"));
|
|
///@todo Make this work as well, the init-declarators need to have separate types
|
|
// QCOMPARE(top->localDeclarations()[1]->abstractType().cast<TypeAliasType>()->type()->toString(), QString("int**"));
|
|
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[2]->abstractType(), top).remove(' '), QString("honk").remove(' '));
|
|
}
|
|
{
|
|
QByteArray method("typedef int const * const honkolo; honkolo k;");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
|
|
QVERIFY(top->localDeclarations()[0]->abstractType().cast<TypeAliasType>());
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[0]->abstractType().cast<TypeAliasType>()->type(), top).remove(' '), QString("const int *const").remove(' '));
|
|
}
|
|
{
|
|
QByteArray method("class C; typedef C* honk; honk k;");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[2]->abstractType(), top).remove(' '), QString("honk").remove(' '));
|
|
}
|
|
{
|
|
QByteArray method("const int i;\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[0]->abstractType(), top).remove(' '), QString("const int").remove(' '));
|
|
}
|
|
|
|
{
|
|
QByteArray method("template<class T> class Template { class Member; Member mem; }; Template< Template< int >* >::Member q;\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
InsertArtificialCodeRepresentation repr(top->url(), QString::fromUtf8(method));
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[1]->abstractType(), top).remove(' '), QString("Template<Template<int>*>::Member").remove(' '));
|
|
}
|
|
{
|
|
///@todo Add more tests for this
|
|
QByteArray method("template<typename T> struct F; template<class T> class Tc; Tc<const F<int*>*> t; const Tc<const F<int*>*>**const*& Test1; Tc<F<int*>*>* test();\n");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
InsertArtificialCodeRepresentation repr(top->url(), QString::fromUtf8(method));
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[2]->abstractType(), top).remove(' '), QString("Tc<const F<int*>*>").remove(' '));
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[3]->abstractType(), top).remove(' '), QString("constTc<const F<int*>*>**const*&").remove(' '));
|
|
FunctionType::Ptr funType = top->localDeclarations()[4]->abstractType().cast<FunctionType>();
|
|
QVERIFY(funType);
|
|
QVERIFY(funType->returnType());
|
|
|
|
//For loop is needed to test the updating, as there was a problem with that
|
|
for(int a = 0; a < 3; ++a) {
|
|
kDebug() << "run" << a;
|
|
top.m_writeLock.unlock();
|
|
parse(method, DumpNone, top);
|
|
top.m_writeLock.lock();
|
|
repr.setText(QString::fromUtf8(method));
|
|
Cpp::SourceCodeInsertion ins(top);
|
|
ins.insertFunctionDeclaration(Identifier("test"), funType->returnType(), QList<Cpp::SourceCodeInsertion::SignatureItem>(), false, "{ this is the body; }");
|
|
ins.changes().setReplacementPolicy(KDevelop::DocumentChangeSet::StopOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = ins.changes().applyAllChanges();
|
|
kDebug() << result.m_failureReason;
|
|
QVERIFY(result);
|
|
kDebug() << repr.text();
|
|
QVERIFY(repr.text().trimmed().remove(' ').remove('\n').contains(QString("Tc< F< int* >* >* test() { this is the body; }").remove(' ')));
|
|
top.m_writeLock.unlock();
|
|
parse(repr.text().toUtf8(), DumpNone, top);
|
|
top.m_writeLock.lock();
|
|
QVERIFY(top->localDeclarations().count() == 6);
|
|
|
|
FunctionType::Ptr funType2 = top->localDeclarations()[5]->abstractType().cast<FunctionType>();
|
|
QVERIFY(funType2);
|
|
QVERIFY(funType2->returnType());
|
|
QVERIFY(funType2->returnType()->equals(funType->returnType().unsafeData()));
|
|
QCOMPARE(Cpp::simplifiedTypeString(funType2->returnType(), top).remove(' '), QString("Tc< F< int* >* >*").remove(' '));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testTemplateReference() {
|
|
QByteArray method("class A; template<class T> class CC; void test(CC<const A*>& item); const A& a;const A*** b;CC<const A> cca;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 6);
|
|
QVERIFY(top->localDeclarations()[2]->abstractType());
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
AbstractType::Ptr argType = top->childContexts()[1]->localDeclarations()[0]->abstractType();
|
|
QVERIFY(argType.cast<ReferenceType>());
|
|
QCOMPARE(argType->toString().remove(' '), QString("CC<constA*>&"));
|
|
{
|
|
// QWidget* navigationWidget = top->childContexts()[1]->createNavigationWidget(top->childContexts()[1]->localDeclarations()[0]);
|
|
// QVERIFY(navigationWidget);
|
|
// KDevelop::AbstractNavigationWidget* nWidget = dynamic_cast<KDevelop::AbstractNavigationWidget*>(navigationWidget);
|
|
// QVERIFY(nWidget);
|
|
// QVERIFY(nWidget->context());
|
|
// QString html = nWidget->context()->html();
|
|
// kDebug() << "html:" << html;
|
|
}
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->childContexts()[1]->localDeclarations()[0]->abstractType(), top).remove(' '), QString("CC<constA*>&"));
|
|
QVERIFY(top->localDeclarations()[3]->abstractType());
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[3]->abstractType(), top).remove(' '), QString("constA&"));
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[4]->abstractType(), top).remove(' '), QString("constA***"));
|
|
AbstractType::Ptr type = top->localDeclarations()[5]->abstractType();
|
|
QVERIFY(type);
|
|
QCOMPARE(type->toString().remove(' '), QString("CC<constA>"));
|
|
QCOMPARE(Cpp::simplifiedTypeString(top->localDeclarations()[5]->abstractType(), top).remove(' '), QString("CC<constA>"));
|
|
}
|
|
|
|
typedef QList<QList<Declaration*> > ClassInstantiations;
|
|
struct DeclarationTestData
|
|
{
|
|
DeclarationTestData() : useCount(0), specializedFrom(0) {};
|
|
|
|
//Declaration
|
|
int useCount;
|
|
|
|
//TemplateDeclaration
|
|
ClassInstantiations instantiations;
|
|
QList<DeclarationTestData> instantiationsTestData;
|
|
Declaration* specializedFrom;
|
|
QList<Declaration*> specializations;
|
|
};
|
|
InstantiationInformation instantiationInfoForDeclarations(const QList<Declaration*> &templateParams)
|
|
{
|
|
InstantiationInformation info;
|
|
int paramCount = templateParams.size();
|
|
for(int i = 0; i < paramCount; ++i)
|
|
{
|
|
if (templateParams[i])
|
|
info.addTemplateParameter(templateParams[i]->abstractType());
|
|
else
|
|
{
|
|
//Null param signifies the end of the template declarations for a given scope
|
|
InstantiationInformation topInfo = instantiationInfoForDeclarations(templateParams.mid(i+1));
|
|
topInfo.previousInstantiationInformation = info.indexed();
|
|
return topInfo;
|
|
}
|
|
}
|
|
return info;
|
|
}
|
|
bool validDeclaration(Declaration *decl, DeclarationTestData testData)
|
|
{
|
|
qDebug() << "Validating Declaration:" << decl->toString();
|
|
bool ret = true;
|
|
if (decl->uses().size() != testData.useCount)
|
|
{
|
|
qDebug() << "Declaration use count doesn't match test data";
|
|
qDebug() << "Actual:" << decl->uses().size() << "| Test data:" << testData.useCount;
|
|
ret = false;
|
|
}
|
|
|
|
if (TemplateDeclaration *templateDecl = dynamic_cast<TemplateDeclaration*>(decl))
|
|
{
|
|
if (templateDecl->specializedFrom().data() != testData.specializedFrom)
|
|
{
|
|
qDebug() << "Declaration's specializedFrom doesn't match test data";
|
|
qDebug() << "The declaration" << decl->toString();
|
|
if (templateDecl->specializedFrom().declaration())
|
|
qDebug() << "specializedFrom" << templateDecl->specializedFrom().declaration()->toString();
|
|
qDebug() << "Actual:" << templateDecl->specializedFrom().data() << "| Test data:" << testData.specializedFrom;
|
|
ret = false;
|
|
}
|
|
|
|
if (templateDecl->specializationsSize() != (uint)testData.specializations.size())
|
|
{
|
|
qDebug() << "Declaration's number of specializations doesn't match test data";
|
|
qDebug() << "Actual:" << templateDecl->specializationsSize() << "| Test data:" << testData.specializations.size();
|
|
ret = false;
|
|
}
|
|
for (uint i = 0; i < templateDecl->specializationsSize(); ++i)
|
|
{
|
|
if (!testData.specializations.contains(templateDecl->specializations()[i].data()))
|
|
{
|
|
qDebug() << "Declaration had specialization not found in test data";
|
|
qDebug() << "Specialization not found:" << templateDecl->specializations()[i].data();
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
TemplateDeclaration::InstantiationsHash actualInstantiations = templateDecl->instantiations();
|
|
if (actualInstantiations.size() != testData.instantiations.size())
|
|
{
|
|
qDebug() << "Declaration's number of instantiations doesn't match test data";
|
|
qDebug() << "Actual:" << actualInstantiations.size() << "| Test data:" << testData.instantiations.size();
|
|
ret = false;
|
|
}
|
|
for(int i = 0; i < testData.instantiations.size(); ++i)
|
|
{
|
|
IndexedInstantiationInformation testInfo = instantiationInfoForDeclarations(testData.instantiations[i]).indexed();
|
|
if (!actualInstantiations.contains(testInfo))
|
|
{
|
|
qDebug() << "Declaration did not have an instantiation found in test data";
|
|
qDebug() << "Instantiation not found in declaration:" << testInfo.information().toString();
|
|
ret = false;
|
|
}
|
|
TemplateDeclaration *instantiation = actualInstantiations[testInfo];
|
|
if (!instantiation)
|
|
{
|
|
qDebug() << "Invalid declaration for instantiation:" << testInfo.information().toString();
|
|
ret = false;
|
|
}
|
|
else if (testData.instantiationsTestData.size())
|
|
{
|
|
if (!validDeclaration(dynamic_cast<Declaration*>(instantiation), testData.instantiationsTestData[i]))
|
|
{
|
|
qDebug() << "Instantiated declaration did not pass validation";
|
|
qDebug() << "Invalid declaration:" << instantiation;
|
|
ret = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void TestDUChain::testTemplatesSuper()
|
|
{
|
|
QByteArray test = "\
|
|
class ClassA {}; //Decl 0, Ctxt 0\n\
|
|
class ClassB {};\n\
|
|
class ClassC {};\n\
|
|
class ClassD {};\n\
|
|
template<typename E_T1, typename E_T2>\n\
|
|
class ClassE\n\
|
|
{\n\
|
|
public:\n\
|
|
template<typename E_A_T1, typename E_A_T2>\n\
|
|
void E_FuncA(E_A_T1, E_A_T2)\n\
|
|
{\n\
|
|
}\n\
|
|
void E_FuncB(E_T1, E_T2)\n\
|
|
{\n\
|
|
}\n\
|
|
};\n\
|
|
template<>\n\
|
|
template<>\n\
|
|
void ClassE<ClassA, ClassB>::E_FuncA<ClassA, ClassA>(ClassA, ClassA);\n\
|
|
template<>\n\
|
|
template<>\n\
|
|
void ClassE<ClassA, ClassB>::E_FuncA<ClassA, ClassA>(ClassA, ClassA)\n\
|
|
{\n\
|
|
}\n\
|
|
template<>\n\
|
|
void ClassE<ClassA, ClassB>::E_FuncB(ClassA, ClassB);\n\
|
|
template<>\n\
|
|
void ClassE<ClassA, ClassB>::E_FuncB(ClassA, ClassB)\n\
|
|
{\n\
|
|
}\n\
|
|
int main()\n\
|
|
{\n\
|
|
ClassE<ClassA, ClassB> foo;\n\
|
|
foo.E_FuncA(ClassA(), ClassA());\n\
|
|
foo.E_FuncB(ClassA(), ClassB());\n\
|
|
ClassE<ClassC, ClassD> foo2;\n\
|
|
foo2.E_FuncA(ClassA(), ClassA());\n\
|
|
foo2.E_FuncB(ClassC(), ClassD());\n\
|
|
}";
|
|
LockedTopDUContext top = parse(test, DumpNone);
|
|
int currentTopDecl = 0;
|
|
//First gather all the visible declarations
|
|
Declaration *ClassA = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<ClassDeclaration*>(ClassA));
|
|
Declaration *ClassB = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<ClassDeclaration*>(ClassB));
|
|
Declaration *ClassC = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<ClassDeclaration*>(ClassC));
|
|
Declaration *ClassD = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<ClassDeclaration*>(ClassD));
|
|
Declaration *ClassE = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<ClassDeclaration*>(ClassE));
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(ClassE));
|
|
//Declarations in ClassE context
|
|
int currentClassEDecl = 0;
|
|
Declaration *E_FuncA = ClassE->internalContext()->localDeclarations()[currentClassEDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_FuncA));
|
|
Q_ASSERT(dynamic_cast<ClassFunctionDeclaration*>(E_FuncA));
|
|
Declaration *E_FuncB = ClassE->internalContext()->localDeclarations()[currentClassEDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_FuncB));
|
|
Q_ASSERT(dynamic_cast<ClassFunctionDeclaration*>(E_FuncB));
|
|
Declaration *E_A_B_FuncA_A_A_Decl = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_A_B_FuncA_A_A_Decl));
|
|
Q_ASSERT(dynamic_cast<FunctionDeclaration*>(E_A_B_FuncA_A_A_Decl));
|
|
Declaration *E_A_B_FuncA_A_A = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_A_B_FuncA_A_A));
|
|
Q_ASSERT(dynamic_cast<FunctionDeclaration*>(E_A_B_FuncA_A_A));
|
|
Q_ASSERT(dynamic_cast<FunctionDefinition*>(E_A_B_FuncA_A_A));
|
|
Declaration *E_A_B_FuncBDecl = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_A_B_FuncBDecl));
|
|
Declaration *E_A_B_FuncB = top->localDeclarations()[currentTopDecl++];
|
|
Q_ASSERT(dynamic_cast<TemplateDeclaration*>(E_A_B_FuncB));
|
|
|
|
Declaration *FuncMain = top->localDeclarations()[currentTopDecl++];
|
|
QVERIFY(FuncMain);
|
|
|
|
|
|
//Test for ClassE DUChain correctness
|
|
DeclarationTestData ClassE_A_B_testData; ClassE_A_B_testData.useCount = 1;
|
|
DeclarationTestData ClassE_C_D_testData; ClassE_C_D_testData.useCount = 1;
|
|
DeclarationTestData ClassE_testData;
|
|
ClassE_testData.useCount = 0;
|
|
ClassE_testData.instantiations << (QList<Declaration*>() << ClassA << ClassB)
|
|
<< (QList<Declaration*>() << ClassC << ClassD);
|
|
ClassE_testData.instantiationsTestData << ClassE_A_B_testData
|
|
<< ClassE_C_D_testData;
|
|
QVERIFY(validDeclaration(ClassE, ClassE_testData));
|
|
|
|
//Test for ClassE<ClassA::ClassB>::E_FuncA<ClassA::ClassA> explicit specialization forward-declaration
|
|
//FIXME: FunctionDeclarations that aren't FunctionDefinitions are actually forward declarations, but aren't treated as such
|
|
//According to the current (incorrect) model this decl should be the Declaration of E_A_B_FuncADef
|
|
//However, it shouldn't be tested, as that's not technically correct anyhow
|
|
//To be correct, E_A_B_FuncA_A_A_Decl should have a function to attempt to resolve it to E_A_B_FuncA_A_A_Def
|
|
//and E_A_B_FuncA_A_A_Def needn't directly know of E_A_B_FuncA_A_A_Decl
|
|
//This is because there could be multiple declarations or even no declarations for E_A_B_FuncA_A_A_Def
|
|
DeclarationTestData E_A_B_FuncA_A_A_Decl_testData;
|
|
QVERIFY(validDeclaration(E_A_B_FuncA_A_A_Decl, E_A_B_FuncA_A_A_Decl_testData));
|
|
|
|
//Test for ClassE::E_FuncA
|
|
DeclarationTestData E_A_B_FuncA_A_A_testData;
|
|
E_A_B_FuncA_A_A_testData.useCount = 1;
|
|
E_A_B_FuncA_A_A_testData.specializedFrom = E_FuncA;
|
|
DeclarationTestData E_C_D_FuncA_A_A_testData;
|
|
E_C_D_FuncA_A_A_testData.useCount = 1;
|
|
DeclarationTestData E_C_D_FuncA_testData;
|
|
DeclarationTestData E_A_B_FuncA_testData;
|
|
DeclarationTestData E_FuncA_testData;
|
|
E_FuncA_testData.specializations << E_A_B_FuncA_A_A;
|
|
E_FuncA_testData.instantiations << (QList<Declaration*>() << ClassA << ClassB << 0 << ClassA << ClassA)
|
|
<< (QList<Declaration*>() << ClassC << ClassD << 0 << ClassA << ClassA)
|
|
//These two instantiations shouldn't exist technically
|
|
<< (QList<Declaration*>() << ClassA << ClassB << 0)
|
|
<< (QList<Declaration*>() << ClassC << ClassD << 0);
|
|
E_FuncA_testData.instantiationsTestData << E_A_B_FuncA_A_A_testData
|
|
<< E_C_D_FuncA_A_A_testData
|
|
<< E_A_B_FuncA_testData
|
|
<< E_C_D_FuncA_testData;
|
|
QVERIFY(validDeclaration(E_FuncA, E_FuncA_testData));
|
|
//Test for ClassE<ClassA::ClassB>::E_FuncA<ClassA::ClassA> explicit specialization definition specifically
|
|
//even though it is automatically tested above... just because
|
|
QVERIFY(validDeclaration(E_A_B_FuncA_A_A, E_A_B_FuncA_A_A_testData));
|
|
|
|
DeclarationTestData E_A_B_FuncBDecl_testData;
|
|
QVERIFY(validDeclaration(E_A_B_FuncBDecl, E_A_B_FuncBDecl_testData));
|
|
|
|
//Test for ClassE::FuncA
|
|
DeclarationTestData E_A_B_FuncB_testData;
|
|
E_A_B_FuncB_testData.useCount = 1;
|
|
E_A_B_FuncB_testData.specializedFrom = E_FuncB;
|
|
DeclarationTestData E_C_D_FuncB_testData;
|
|
E_C_D_FuncB_testData.useCount = 1;
|
|
DeclarationTestData E_FuncB_testData;
|
|
E_FuncB_testData.specializations << E_A_B_FuncB;
|
|
E_FuncB_testData.instantiations << (QList<Declaration*>() << ClassA << ClassB << 0)
|
|
<< (QList<Declaration*>() << ClassC << ClassD << 0);
|
|
E_FuncB_testData.instantiationsTestData << E_A_B_FuncB_testData
|
|
<< E_C_D_FuncB_testData;
|
|
QVERIFY(validDeclaration(E_FuncB, E_FuncB_testData));
|
|
//Test for ClassE<ClassA::ClassB>::E_FuncB explicit specialization definition specifically
|
|
//even though it is automatically tested above... just because
|
|
QVERIFY(validDeclaration(E_A_B_FuncB, E_A_B_FuncB_testData));
|
|
}
|
|
|
|
|
|
void TestDUChain::testTemplates() {
|
|
QByteArray method("template<class T> T test(const T& t) {}; template<class T, class T2> class A {T2 a; typedef T Template1; }; class B{int b;}; class C{int c;}; template<class T>class A<B,T>{}; typedef A<B,C> D;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
|
|
Declaration* defTest = top->localDeclarations()[0];
|
|
QCOMPARE(defTest->identifier(), Identifier("test"));
|
|
QVERIFY(defTest->type<FunctionType>());
|
|
QVERIFY( isTemplateDeclaration(defTest) );
|
|
|
|
Declaration* defClassA = top->localDeclarations()[1];
|
|
QCOMPARE(defClassA->identifier(), Identifier("A"));
|
|
QVERIFY(defClassA->type<CppClassType>());
|
|
QVERIFY( isTemplateDeclaration(defClassA) );
|
|
|
|
Declaration* defClassB = top->localDeclarations()[2];
|
|
QCOMPARE(defClassB->identifier(), Identifier("B"));
|
|
QVERIFY(defClassB->type<CppClassType>());
|
|
QVERIFY( !isTemplateDeclaration(defClassB) );
|
|
|
|
Declaration* defClassC = top->localDeclarations()[3];
|
|
QCOMPARE(defClassC->identifier(), Identifier("C"));
|
|
QVERIFY(defClassC->type<CppClassType>());
|
|
QVERIFY( !isTemplateDeclaration(defClassC) );
|
|
|
|
DUContext* classA = defClassA->internalContext();
|
|
QVERIFY(classA);
|
|
QVERIFY(classA->parentContext());
|
|
QCOMPARE(classA->importedParentContexts().count(), 1); //The template-parameter context is imported
|
|
QCOMPARE(classA->localScopeIdentifier(), QualifiedIdentifier("A"));
|
|
|
|
DUContext* classB = defClassB->internalContext();
|
|
QVERIFY(classB);
|
|
QVERIFY(classB->parentContext());
|
|
QCOMPARE(classB->importedParentContexts().count(), 0);
|
|
QCOMPARE(classB->localScopeIdentifier(), QualifiedIdentifier("B"));
|
|
|
|
DUContext* classC = defClassC->internalContext();
|
|
QVERIFY(classC);
|
|
QVERIFY(classC->parentContext());
|
|
QCOMPARE(classC->importedParentContexts().count(), 0);
|
|
QCOMPARE(classC->localScopeIdentifier(), QualifiedIdentifier("C"));
|
|
|
|
///Test getting the typedef for the unset template
|
|
{
|
|
Declaration* typedefDecl = findDeclaration(classA, Identifier("Template1"));
|
|
QVERIFY(typedefDecl);
|
|
QVERIFY(typedefDecl->isTypeAlias());
|
|
QVERIFY(typedefDecl->abstractType());
|
|
QVERIFY(unAliasedType(typedefDecl->abstractType()));
|
|
DelayedType::Ptr delayed = unAliasedType(typedefDecl->abstractType()).cast<DelayedType>();
|
|
QVERIFY(delayed);
|
|
QCOMPARE(delayed->identifier(), IndexedTypeIdentifier("T"));
|
|
}
|
|
|
|
///Test creating a template instance of class A<B,C>
|
|
{
|
|
Identifier ident("A");
|
|
ident.appendTemplateIdentifier(IndexedTypeIdentifier("B"));
|
|
ident.appendTemplateIdentifier(IndexedTypeIdentifier("C"));
|
|
Declaration* instanceDefClassA = findDeclaration(top, ident);
|
|
Declaration* instanceTypedefD = findDeclaration(top, Identifier("D"));
|
|
QVERIFY(instanceTypedefD);
|
|
QVERIFY(instanceDefClassA);
|
|
QVERIFY(unAliasedType(instanceTypedefD->abstractType()));
|
|
QCOMPARE(unAliasedType(instanceTypedefD->abstractType())->toString(), instanceDefClassA->abstractType()->toString() );
|
|
//QCOMPARE(instanceTypedefD->abstractType().data(), instanceDefClassA->abstractType().data() ); Re-enable once specializations are re-used
|
|
Cpp::TemplateDeclaration* templateDecl = dynamic_cast<Cpp::TemplateDeclaration*>(instanceDefClassA);
|
|
QVERIFY(templateDecl);
|
|
QVERIFY(instanceDefClassA != defClassA);
|
|
QVERIFY(instanceDefClassA->context() == defClassA->context());
|
|
QVERIFY(instanceDefClassA->internalContext() != defClassA->internalContext());
|
|
QCOMPARE(instanceDefClassA->identifier(), Identifier("A<B,C>"));
|
|
QCOMPARE(instanceDefClassA->identifier().toString(), QString("A< B, C >"));
|
|
QVERIFY(instanceDefClassA->abstractType());
|
|
AbstractType::Ptr t = instanceDefClassA->abstractType();
|
|
IdentifiedType* identifiedType = dynamic_cast<IdentifiedType*>(t.unsafeData());
|
|
QVERIFY(identifiedType);
|
|
QVERIFY(identifiedType->declaration(top));
|
|
kDebug() << identifiedType->declaration(top)->toString() << identifiedType->declaration(top)->range().castToSimpleRange().textRange() << instanceDefClassA->toString() << instanceDefClassA->range().castToSimpleRange().textRange();
|
|
QCOMPARE(identifiedType->declaration(top), instanceDefClassA);
|
|
QCOMPARE(identifiedType->qualifiedIdentifier().toString(), Identifier("A<B,C>").toString());
|
|
QVERIFY(instanceDefClassA->internalContext());
|
|
QVERIFY(instanceDefClassA->internalContext() != defClassA->internalContext());
|
|
QVERIFY(instanceDefClassA->context() == defClassA->context());
|
|
QVERIFY(instanceDefClassA->internalContext()->importedParentContexts().size() == 1);
|
|
QVERIFY(defClassA->internalContext()->importedParentContexts().size() == 1);
|
|
QCOMPARE(instanceDefClassA->internalContext()->importedParentContexts().front().context(0)->type(), DUContext::Template);
|
|
QVERIFY(defClassA->internalContext()->importedParentContexts().front().context(0) != instanceDefClassA->internalContext()->importedParentContexts().front().context(0)); //The template-context has been instantiated
|
|
|
|
QualifiedIdentifier ident2(ident);
|
|
ident2.push(Identifier("Template1"));
|
|
|
|
Declaration* template1InstanceDecl1 = findDeclaration(instanceDefClassA->internalContext(), Identifier("Template1"));
|
|
QVERIFY(!template1InstanceDecl1);
|
|
|
|
Declaration* template1InstanceDecl2 = findDeclaration(instanceDefClassA->internalContext(), Identifier("a"));
|
|
QVERIFY(!template1InstanceDecl2);
|
|
|
|
Declaration* template1InstanceDecl = findDeclaration(top, ident2);
|
|
QVERIFY(!template1InstanceDecl);
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateParameters() {
|
|
return;
|
|
QByteArray method("template<class T, class N = T, int q = 5> class A {};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->type(), DUContext::Template);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 3);
|
|
|
|
Declaration* param1 = top->childContexts()[0]->localDeclarations()[0];
|
|
QVERIFY(param1->type<CppTemplateParameterType>());
|
|
|
|
Declaration* param2 = top->childContexts()[0]->localDeclarations()[1];
|
|
QVERIFY(param2->type<CppTemplateParameterType>());
|
|
TemplateParameterDeclaration* param2Decl = dynamic_cast<TemplateParameterDeclaration*>(param2);
|
|
QVERIFY(param2Decl);
|
|
QVERIFY(!param2Decl->defaultParameter().isEmpty());
|
|
|
|
Declaration* param3 = top->childContexts()[0]->localDeclarations()[2];
|
|
QVERIFY(param3->type<IntegralType>());
|
|
TemplateParameterDeclaration* param3Decl = dynamic_cast<TemplateParameterDeclaration*>(param3);
|
|
QVERIFY(param3Decl);
|
|
QVERIFY(!param3Decl->defaultParameter().isEmpty());
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateDefaultParameters() {
|
|
QByteArray method("struct S {} ; namespace std { template<class T> class Template1 { }; } template<class _TT, typename TT2 = std::Template1<_TT> > class Template2 { typedef TT2 T1; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
kDebug() << "searching";
|
|
// Declaration* memberDecl = findDeclaration(top, QualifiedIdentifier("Template2<S>::T1"));
|
|
Declaration* memberDecl = findDeclaration(top, QualifiedIdentifier("Template2<S>::TT2"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(memberDecl->abstractType());
|
|
QVERIFY(!memberDecl->type<DelayedType>());
|
|
QCOMPARE(memberDecl->abstractType()->toString(), QString("std::Template1< S >"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplates3() {
|
|
QByteArray method("typedef int quakka; template<class T> struct Test { typedef T Value; const Value cv; const T cv2; ; typedef Value& ValueRef; typedef const ValueRef ConstValueRef; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
Declaration* qDecl = findDeclaration(top, QualifiedIdentifier("quakka"));
|
|
QVERIFY(qDecl);
|
|
QCOMPARE(qDecl->abstractType()->toString(), QString("quakka"));
|
|
|
|
Declaration* cvDecl = findDeclaration(top, QualifiedIdentifier("Test<quakka>::cv"));
|
|
QVERIFY(cvDecl);
|
|
QVERIFY(cvDecl->abstractType());
|
|
|
|
AbstractType::Ptr type = cvDecl->abstractType();
|
|
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(type.unsafeData());
|
|
QVERIFY(idType);
|
|
QVERIFY(idType->declaration(top));
|
|
|
|
QVERIFY(cvDecl->abstractType()->modifiers() & AbstractType::ConstModifier);
|
|
QVERIFY(TypeUtils::unAliasedType(cvDecl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
|
|
QCOMPARE(unAliasedType(cvDecl->abstractType())->toString(), QString("const int"));
|
|
Declaration* cv2Decl = findDeclaration(top, QualifiedIdentifier("Test<quakka>::cv2"));
|
|
QVERIFY(cv2Decl);
|
|
QVERIFY(cv2Decl->abstractType());
|
|
QVERIFY(cv2Decl->abstractType()->modifiers() & AbstractType::ConstModifier);
|
|
QCOMPARE(cv2Decl->abstractType()->toString(), QString("const quakka"));
|
|
QCOMPARE(unAliasedType(cv2Decl->abstractType())->toString(), QString("const int"));
|
|
QVERIFY(TypeUtils::unAliasedType(cv2Decl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
|
|
{
|
|
Declaration* cvrDecl = findDeclaration(top, QualifiedIdentifier("Test<quakka>::ConstValueRef"));
|
|
QVERIFY(cvrDecl);
|
|
|
|
AbstractType::Ptr type = cvrDecl->abstractType();
|
|
IdentifiedType* idType = dynamic_cast<IdentifiedType*>(type.unsafeData());
|
|
QVERIFY(idType);
|
|
QVERIFY(idType->declaration(top));
|
|
|
|
QVERIFY(cvrDecl->abstractType());
|
|
QVERIFY(unAliasedType(cvrDecl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
QCOMPARE(realType(cvrDecl->abstractType(), 0)->toString(), QString("const int"));
|
|
QCOMPARE(targetType(cvrDecl->abstractType(), 0)->toString(), QString("const int"));
|
|
TypeAliasType::Ptr alias = cvrDecl->abstractType().cast<TypeAliasType>();
|
|
QVERIFY(alias);
|
|
QVERIFY(alias->type());
|
|
QCOMPARE(targetTypeKeepAliases(Cpp::shortenTypeForViewing(cvrDecl->abstractType()), 0, 0)->toString(), QString("const quakka"));
|
|
//When the target is a typedef type, the duchain does not know whether it should write "const" before or behind, so it puts it behind "quakka"
|
|
QCOMPARE(Cpp::shortenTypeForViewing(cvrDecl->abstractType())->toString(), QString("quakka const&"));
|
|
QVERIFY(TypeUtils::unAliasedType(cvrDecl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
}
|
|
{
|
|
Declaration* cvrDecl = findDeclaration(top, QualifiedIdentifier("Test<quakka*>::ConstValueRef"));
|
|
QVERIFY(cvrDecl);
|
|
QVERIFY(cvrDecl->abstractType());
|
|
QVERIFY(unAliasedType(cvrDecl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
QCOMPARE(realType(cvrDecl->abstractType(), 0)->toString(), QString("quakka* const"));
|
|
TypeAliasType::Ptr alias = cvrDecl->abstractType().cast<TypeAliasType>();
|
|
QVERIFY(alias);
|
|
QVERIFY(alias->type());
|
|
QCOMPARE(Cpp::shortenTypeForViewing(cvrDecl->abstractType())->toString(), QString("quakka* const&"));
|
|
QVERIFY(TypeUtils::unAliasedType(cvrDecl->abstractType())->modifiers() & AbstractType::ConstModifier);
|
|
|
|
}
|
|
{
|
|
QByteArray method("template<class T> struct Cnt { typedef T Val; }; struct Item; template<class Value> struct Freqto { struct Item { typedef Value Value2; }; struct Pattern : public Cnt<Item> { }; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[3]->childContexts().count(), 2);
|
|
|
|
//The import should have been delayed, since it needs 'Item'
|
|
QVERIFY(top->childContexts()[3]->childContexts()[1]->owner());
|
|
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(top->childContexts()[3]->childContexts()[1]->owner());
|
|
QVERIFY(classDecl);
|
|
QCOMPARE(classDecl->baseClassesSize(), 1u);
|
|
QVERIFY(top->childContexts()[3]->childContexts()[1]->importedParentContexts().isEmpty());
|
|
QVERIFY(classDecl->baseClasses()[0].baseClass.type<DelayedType>());
|
|
kDebug() << classDecl->baseClasses()[0].baseClass.abstractType()->toString();
|
|
Declaration* val2Decl = findDeclaration(top, QualifiedIdentifier("Freqto<int>::Pattern::Val::Value2"));
|
|
QVERIFY(val2Decl);
|
|
QCOMPARE(unAliasedType(val2Decl->abstractType())->toString(), QString("int"));
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testTemplates4()
|
|
{
|
|
{
|
|
QByteArray method("template<class A> class Temp { typedef A Mem; }; class B {class A { typedef int AMember; }; }; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
Declaration* memDecl = findDeclaration(top->childContexts()[2], QualifiedIdentifier("Temp<A>::Mem"));;
|
|
QVERIFY(memDecl);
|
|
QCOMPARE(unAliasedType(memDecl->abstractType())->toString(), QString("B::A"));
|
|
QVERIFY(findDeclaration(top->childContexts()[2], QualifiedIdentifier("Temp<A>::Mem::AMember")));
|
|
|
|
}
|
|
{
|
|
QByteArray method("template<class T> struct Cnt { typedef T Val; }; struct Item; template<class Value> struct Freqto { struct Item { typedef Value Value2; }; struct Pattern : public Cnt<Item> { }; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[3]->childContexts().count(), 2);
|
|
|
|
//The import should have been delayed, since it needs 'Item'
|
|
QVERIFY(top->childContexts()[3]->childContexts()[1]->owner());
|
|
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(top->childContexts()[3]->childContexts()[1]->owner());
|
|
QVERIFY(classDecl);
|
|
QCOMPARE(classDecl->baseClassesSize(), 1u);
|
|
QVERIFY(top->childContexts()[3]->childContexts()[1]->importedParentContexts().isEmpty());
|
|
QVERIFY(classDecl->baseClasses()[0].baseClass.type<DelayedType>());
|
|
kDebug() << classDecl->baseClasses()[0].baseClass.abstractType()->toString();
|
|
Declaration* val2Decl = findDeclaration(top, QualifiedIdentifier("Freqto<int>::Pattern::Val::Value2"));
|
|
QVERIFY(val2Decl);
|
|
QCOMPARE(unAliasedType(val2Decl->abstractType())->toString(), QString("int"));
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testTemplates2() {
|
|
QByteArray method("struct S {} ; template<class TT> class Base { struct Alloc { typedef TT& referenceType; }; }; template<class T> struct Class : public Base<T> { typedef typename Base<T>::Alloc Alloc; typedef typename Alloc::referenceType reference; reference member; }; Class<S*&> instance;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(top->childContexts().count() > 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QVERIFY(!top->childContexts()[1]->localDeclarations()[0]->type<TypeAliasType>());
|
|
QVERIFY(top->childContexts().count() == 5);
|
|
QVERIFY(top->childContexts()[4]->localDeclarations().count() > 1);
|
|
|
|
QVERIFY(top->childContexts()[4]->localDeclarations()[0]->type<TypeAliasType>());
|
|
QVERIFY(top->childContexts()[4]->localDeclarations()[1]->type<TypeAliasType>());
|
|
QVERIFY(top->childContexts()[4]->localDeclarations()[0]->type<TypeAliasType>()->type().cast<DelayedType>());
|
|
QVERIFY(top->childContexts()[4]->localDeclarations()[1]->type<TypeAliasType>()->type().cast<DelayedType>());
|
|
QVERIFY(top->childContexts()[4]->localDeclarations()[2]->type<DelayedType>());
|
|
|
|
Declaration* memberDecl;
|
|
|
|
kDebug() << "checking member";
|
|
|
|
memberDecl = findDeclaration(top, QualifiedIdentifier("Class<S>::member"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(unAliasedType(memberDecl->abstractType()));
|
|
QCOMPARE(unAliasedType(memberDecl->abstractType())->toString(), QString("S&"));
|
|
|
|
memberDecl = findDeclaration(top, QualifiedIdentifier("instance"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(memberDecl->abstractType());
|
|
QCOMPARE(memberDecl->abstractType()->toString(), QString("Class< S*& >"));
|
|
|
|
// memberDecl = findDeclaration(top, QualifiedIdentifier("Class<S>::Alloc<S>::referenceType"));
|
|
// QVERIFY(memberDecl);
|
|
// QVERIFY(memberDecl->abstractType());
|
|
// QCOMPARE(memberDecl->abstractType()->toString(), QString("S&"/*));
|
|
|
|
memberDecl = findDeclaration(top, QualifiedIdentifier("Class<S*>::member"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(unAliasedType(memberDecl->abstractType()));
|
|
QCOMPARE(unAliasedType(memberDecl->abstractType())->toString(), QString("S*&"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testSpecializationSelection()
|
|
{
|
|
QByteArray method("template<class T1> struct Foo { void normal() {} };\n"
|
|
"template<class T1> struct Foo<const T1> { void typeIsConst() {} };\n"
|
|
"template<class T1> struct Foo<volatile T1> { void typeIsVolatile() {} };\n"
|
|
"template<class T1> struct Foo<const volatile T1> { void typeIsConstVolatile() {} };\n"
|
|
"template<class T1> struct Foo<T1*> { void typeIsPtr() {} };\n"
|
|
"template<class T1> struct Foo<T1**> { void typeIsPtrPtr() {} };\n"
|
|
"template<class T1> struct Foo<const T1*> { void typeIsConstPtr() {} };\n"
|
|
"template<class T1> struct Foo<const T1**> { void typeIsConstPtrPtr() {} };\n"
|
|
"template<class T1> struct Foo<T1&&> { void typeIsRValue() {} };\n"
|
|
"template<class T1> struct Foo<const T1&&> { void typeIsConstRValue() {} };\n"
|
|
"template<class T1> struct Foo<T1[]> { void typeIsArray() {} };\n"
|
|
"template<class T1> struct Foo<const T1[]> { void typeIsConstArray() {} };\n"
|
|
"template<class T1> struct Foo<const T1*&&> { void typeIsConstPtrRValue() {} };\n"
|
|
"template<class T1> struct Foo<const T1* const &&> { void typeIsConstPtrConstRValue() {} };\n");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int>::normal")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int>::typeIsConst")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<volatile int>::typeIsVolatile")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const volatile int>::typeIsConstVolatile")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int*>::typeIsPtr")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int*>::typeIsConstPtr")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int&&>::typeIsRValue")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int&&>::typeIsConstRValue")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int***>::typeIsPtrPtr")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int**>::typeIsConstPtrPtr")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int[]>::typeIsArray")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int[]>::typeIsConstArray")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int*&&>::typeIsConstPtrRValue")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<const int*const&&>::typeIsConstPtrConstRValue")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<Foo<int>>::normal")));
|
|
}
|
|
|
|
void TestDUChain::testSpecializationSelection2()
|
|
{
|
|
QByteArray method("template<class T1> struct Simple {};\n"
|
|
"template<class T1> struct Simple<T1&> {};\n"
|
|
"template<class T1, class T2> struct Foo { void normal() {} };\n"
|
|
"template<class T1> struct Foo<int, T1> { void normal2() {} };\n"
|
|
"template<class T1> struct Foo<T1&, int> { void normal3() {} };\n"
|
|
"template<class T1> struct Foo<Simple<T1>, int> { void normal4() {} };\n"
|
|
"template<class T1> struct Foo<int, Simple<T1&>> { void normal5() {} };\n");
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<char, int>::normal")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int, int>::normal2")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int&, int>::normal3")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<Simple<int>, int>::normal4")));
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Foo<int, Simple<int&>>::normal5")));
|
|
}
|
|
|
|
void TestDUChain::testTemplatesRebind() {
|
|
QByteArray method("struct A {}; struct S {typedef A Value;} ; template<class TT> class Base { template<class T> struct rebind { typedef Base<T> other; }; typedef TT Type; }; template<class T> class Class { typedef Base<T>::rebind<T>::other::Type MemberType; MemberType member; Base<T>::template rebind<T>::other::Type member2; T::Value value; };");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->childContexts().count(), 6);
|
|
QCOMPARE(top->childContexts()[3]->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[3]->childContexts()[1]->localDeclarations().count(), 1);
|
|
{
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Base<S>")));
|
|
QVERIFY(!findDeclaration(top, QualifiedIdentifier("Base<S>"))->type<DelayedType>());
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Base<S>::rebind<A>")));
|
|
QVERIFY(!findDeclaration(top, QualifiedIdentifier("Base<S>::rebind<A>::other"))->type<DelayedType>());
|
|
QVERIFY(findDeclaration(top, QualifiedIdentifier("Base<S>::rebind<A>::other::Type")));
|
|
QVERIFY(!findDeclaration(top, QualifiedIdentifier("Base<S>::rebind<A>::other::Type"))->type<DelayedType>());
|
|
|
|
Declaration* memberDecl = findDeclaration(top, QualifiedIdentifier("Base<S>::rebind<A>::other::Type"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(memberDecl->abstractType());
|
|
QVERIFY(memberDecl->abstractType());
|
|
QVERIFY(unAliasedType(memberDecl->abstractType()));
|
|
QCOMPARE(unAliasedType(memberDecl->abstractType())->toString(), QString("A"));
|
|
}
|
|
|
|
Declaration* memberDecl = findDeclaration(top, QualifiedIdentifier("Class<S>::member"));
|
|
QVERIFY(memberDecl);
|
|
QVERIFY(memberDecl->abstractType());
|
|
QVERIFY(unAliasedType(memberDecl->abstractType()));
|
|
QCOMPARE(unAliasedType(memberDecl->abstractType())->toString(), QString("S"));
|
|
|
|
Declaration* member3Decl = findDeclaration(top, QualifiedIdentifier("Class<S>::value"));
|
|
QVERIFY(member3Decl);
|
|
QVERIFY(member3Decl->abstractType());
|
|
QVERIFY(unAliasedType(member3Decl->abstractType()));
|
|
QCOMPARE(unAliasedType(member3Decl->abstractType())->toString(), QString("A"));
|
|
|
|
Declaration* member2Decl = findDeclaration(top, QualifiedIdentifier("Class<S>::member2"));
|
|
QVERIFY(member2Decl);
|
|
QVERIFY(unAliasedType(member2Decl->abstractType()));
|
|
QCOMPARE(unAliasedType(member2Decl->abstractType())->toString(), QString("S"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplatesRebind2() {
|
|
QByteArray method("struct A {}; struct S {typedef A Value;} ;template<class T> class Test { Test(); }; template<class T> class Class { typedef typename T::Value Value; typename T::Value value; typedef Test<Value> ValueClass; Test<const Value> ValueClass2;};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QList<Declaration*> constructors = TypeUtils::getConstructors( top->localDeclarations()[2]->abstractType().cast<CppClassType>(), top );
|
|
QCOMPARE(constructors.size(), 1);
|
|
OverloadResolver resolution( DUContextPointer(top->localDeclarations()[2]->internalContext()), TopDUContextPointer(top) );
|
|
QVERIFY(resolution.resolveConstructor( OverloadResolver::ParameterList() ));
|
|
|
|
QVERIFY(top->childContexts().count() >= 6);
|
|
QCOMPARE(top->childContexts()[5]->localDeclarations().count(), 4);
|
|
AbstractType::Ptr valueType = top->childContexts()[5]->localDeclarations()[0]->abstractType();
|
|
QVERIFY(containsDelayedType(valueType));
|
|
QVERIFY(containsDelayedType(top->childContexts()[5]->localDeclarations()[1]->abstractType()));
|
|
QVERIFY(containsDelayedType(top->childContexts()[5]->localDeclarations()[2]->abstractType()));
|
|
QVERIFY(containsDelayedType(top->childContexts()[5]->localDeclarations()[3]->abstractType()));
|
|
|
|
Declaration* valueAliasDecl = findDeclaration(top, QualifiedIdentifier("Class<S>::Value"));
|
|
QVERIFY(valueAliasDecl);
|
|
TypeAliasType::Ptr alias = valueAliasDecl->type<TypeAliasType>();
|
|
QVERIFY(alias);
|
|
QVERIFY(alias->type());
|
|
QVERIFY(!alias->type().cast<DelayedType>());
|
|
QCOMPARE(unAliasedType(alias.cast<AbstractType>())->toString(), QString("A"));
|
|
kDebug() << "aliased type:" << alias->type()->toString();
|
|
kDebug() << "typedef type:" << alias->toString();
|
|
kDebug() << "un-aliased type:" << unAliasedType(alias.cast<AbstractType>())->toString();
|
|
|
|
Declaration* member5Decl = findDeclaration(top, QualifiedIdentifier("Class<S>::ValueClass2"));
|
|
QVERIFY(member5Decl);
|
|
AbstractType::Ptr type = unAliasedType(member5Decl->abstractType());
|
|
QVERIFY(type);
|
|
QCOMPARE(type->toString(), QString("Test< S::Value >")); ///@todo This will fail once we parse "const" correctly, change it to "Test< const A >" then
|
|
|
|
Declaration* member4Decl = findDeclaration(top, QualifiedIdentifier("Class<S>::ValueClass"));
|
|
QVERIFY(member4Decl);
|
|
QVERIFY(unAliasedType(member4Decl->abstractType()));
|
|
QCOMPARE(unAliasedType(member4Decl->abstractType())->toString(), QString("Test< S::Value >"));
|
|
|
|
Declaration* member3Decl = findDeclaration(top, QualifiedIdentifier("Class<S>::value"));
|
|
QVERIFY(member3Decl);
|
|
QVERIFY(unAliasedType(member3Decl->abstractType()));
|
|
QCOMPARE(unAliasedType(member3Decl->abstractType())->toString(), QString("A"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testForwardDeclaration()
|
|
{
|
|
QByteArray method("class Test; Test t; class Test {int i; class SubTest; }; Test::SubTest t2; class Test::SubTest{ int i;};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(top->inSymbolTable());
|
|
QCOMPARE(top->localDeclarations().count(), 4); //Test::SubTest is in a prefix context
|
|
QCOMPARE(top->childContexts().count(), 2); //Test::SubTest is in a prefix context
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1); //Test::SubTest is in a prefix context
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->localDeclarations()[0]));
|
|
QVERIFY(top->localDeclarations()[0]->inSymbolTable());
|
|
QVERIFY(top->localDeclarations()[1]->inSymbolTable());
|
|
QVERIFY(top->localDeclarations()[2]->inSymbolTable());
|
|
QVERIFY(top->localDeclarations()[3]->inSymbolTable());
|
|
QVERIFY(!top->localDeclarations()[2]->isForwardDeclaration());
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->additionalIdentity(), top->localDeclarations()[2]->additionalIdentity());
|
|
QVERIFY(!dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[0]));
|
|
QVERIFY(!dynamic_cast<TemplateDeclaration*>(top->localDeclarations()[2]));
|
|
|
|
CppClassType::Ptr type1 = top->localDeclarations()[0]->type<CppClassType>();
|
|
kDebug() << typeid(*top->localDeclarations()[1]->abstractType()).name();
|
|
CppClassType::Ptr type2 = top->localDeclarations()[1]->type<CppClassType>();
|
|
CppClassType::Ptr type3 = top->localDeclarations()[2]->type<CppClassType>();
|
|
CppClassType::Ptr type4 = top->localDeclarations()[3]->type<CppClassType>();
|
|
CppClassType::Ptr type5 = top->childContexts()[1]->localDeclarations()[0]->type<CppClassType>();
|
|
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->kind(), Declaration::Type);
|
|
QCOMPARE(top->localDeclarations()[1]->kind(), Declaration::Instance);
|
|
QCOMPARE(top->localDeclarations()[2]->kind(), Declaration::Type);
|
|
QCOMPARE(top->localDeclarations()[3]->kind(), Declaration::Instance);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->kind(), Declaration::Type);
|
|
QVERIFY(type1);
|
|
QVERIFY(type2);
|
|
QVERIFY(type3);
|
|
QVERIFY(type4);
|
|
QVERIFY(type5);
|
|
|
|
Declaration* TestDecl = top->localDeclarations()[2];
|
|
QVERIFY(TestDecl->internalContext());
|
|
QCOMPARE(TestDecl->internalContext()->localDeclarations().count(), 2);
|
|
|
|
CppClassType::Ptr subType = TestDecl->internalContext()->localDeclarations()[1]->type<CppClassType>();
|
|
QVERIFY(subType);
|
|
|
|
QCOMPARE(subType->declaration(0)->abstractType()->indexed(), type5->indexed());
|
|
QCOMPARE(type1->indexed(), type2->indexed());
|
|
QCOMPARE(type1->declaration(top), type2->declaration(top));
|
|
QVERIFY(type1->equals(type3.unsafeData()));
|
|
QVERIFY(type3->equals(type1.unsafeData()));
|
|
QCOMPARE(type1->declaration(0)->abstractType()->indexed(), type3->indexed());
|
|
kDebug() << typeid(*type3->declaration(top)).name();
|
|
kDebug() << typeid(*type1->declaration(top)).name();
|
|
QCOMPARE(type1->declaration(top)->logicalInternalContext(0), type3->declaration(top)->internalContext());
|
|
QCOMPARE(type2->declaration(top)->logicalInternalContext(0), type3->declaration(top)->internalContext());
|
|
|
|
kDebug() << subType->qualifiedIdentifier().toString(); //declaration(0)->toString();
|
|
kDebug() << type5->qualifiedIdentifier().toString(); //declaration(0)->toString();
|
|
|
|
}
|
|
|
|
void TestDUChain::testCaseUse()
|
|
{
|
|
QByteArray method("enum Bla { Val }; char* c; int a; void test() { switch(a) { case Val: a += 1; break; } delete c; } ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
QVERIFY(top->localDeclarations()[0]->internalContext());
|
|
QCOMPARE(top->localDeclarations()[0]->internalContext()->localDeclarations().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->internalContext()->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->internalContext()->localDeclarations()[0]->uses().begin()->count(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().begin()->count(), 1);
|
|
|
|
}
|
|
|
|
void TestDUChain::testSizeofUse()
|
|
{
|
|
QByteArray method("class C{}; const unsigned int i = sizeof(C);");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
|
|
|
|
}
|
|
|
|
void TestDUChain::testDefinitionUse()
|
|
{
|
|
QByteArray method("class A{}; class C : public A{ void test(); }; C::test() {} ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 3);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
|
|
QCOMPARE(top->localDeclarations()[1]->uses().count(), 1);
|
|
}
|
|
|
|
void TestDUChain::testOperatorUses()
|
|
{
|
|
{
|
|
QByteArray method("template<class T> struct Fruk { Fruk<T>& operator[](int); }; Fruk<int> f; void test(){ const int mog; Fruk q (f[mog]); }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().count(), 4);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts()[3]->localDeclarations()[0]->uses().size(), 1);
|
|
|
|
}
|
|
{
|
|
QByteArray method("struct S { bool operator() () const {} };void test() { S s; s(); S()(); } ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->size(), 2);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 2);
|
|
|
|
}
|
|
{
|
|
QByteArray method("struct S { S operator() () const {}; S(int) {}; };void test() { S s(1); s(); S(1)()(); } ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->localDeclarations()[0]->uses().begin()->size(), 3);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[0]->uses().begin()->size(), 3);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().size(), 1);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->size(), 2);
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->at(0).castToSimpleRange().textRange(), KTextEditor::Range(0, 68, 0, 69));
|
|
QCOMPARE(top->childContexts()[0]->localDeclarations()[1]->uses().begin()->at(1).castToSimpleRange().textRange(), KTextEditor::Range(0, 79, 0, 80));
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct foo { bool operator==(const foo&){} };\n"
|
|
"int main() { foo t1; foo t2;\n"
|
|
// not valid in global context, hence put it into main
|
|
"bool b1 = t1 == t2;\n"
|
|
"bool b2 = t1.operator==(t2); }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().count(), 1);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->size(), 2);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->at(0), RangeInRevision(2, 13, 2, 15));
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->at(1), RangeInRevision(3, 13, 3, 23));
|
|
|
|
}
|
|
{
|
|
// 0 1 2 3 4 5
|
|
// 012345678901234567890123456789012345678901234567890123456789
|
|
QByteArray method("struct foo { foo& operator=(const foo&){} };\n"
|
|
"int main() { foo t1; foo t2 = t1;\n"
|
|
// not valid in global context, hence put it into main
|
|
"t1.operator=(t2); return 0; }");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().size(), 1);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().count(), 1);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->size(), 2);
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->at(0), RangeInRevision(1, 28, 1, 29));
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().first()->uses().begin()->at(1), RangeInRevision(2, 3, 2, 12));
|
|
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testForwardDeclaration2()
|
|
{
|
|
QByteArray method("class Test; Test t; class Test {int i; class SubTest; }; class Test; Test::SubTest t2; class Test::SubTest{ int i;};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts()[1]->scopeIdentifier(), QualifiedIdentifier("Test")); //This is the prefix-context around Test::SubTest
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->localDeclarations()[0]));
|
|
|
|
CppClassType::Ptr type1 = top->localDeclarations()[0]->type<CppClassType>();
|
|
CppClassType::Ptr type2 = top->localDeclarations()[1]->type<CppClassType>();
|
|
CppClassType::Ptr type3 = top->localDeclarations()[2]->type<CppClassType>();
|
|
CppClassType::Ptr type4 = top->localDeclarations()[4]->type<CppClassType>();
|
|
CppClassType::Ptr type5 = top->childContexts()[1]->localDeclarations()[0]->type<CppClassType>();
|
|
CppClassType::Ptr type12 = top->localDeclarations()[3]->type<CppClassType>();
|
|
|
|
QCOMPARE(top->localDeclarations()[0]->kind(), Declaration::Type);
|
|
QCOMPARE(top->localDeclarations()[1]->kind(), Declaration::Instance);
|
|
QCOMPARE(top->localDeclarations()[2]->kind(), Declaration::Type);
|
|
QCOMPARE(top->localDeclarations()[3]->kind(), Declaration::Type);
|
|
QCOMPARE(top->localDeclarations()[4]->kind(), Declaration::Instance);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations()[0]->kind(), Declaration::Type);
|
|
|
|
QVERIFY(type1);
|
|
QVERIFY(type12);
|
|
QVERIFY(type2);
|
|
QVERIFY(type3);
|
|
QVERIFY(type4);
|
|
QVERIFY(type5);
|
|
|
|
Declaration* TestDecl = top->localDeclarations()[2];
|
|
QVERIFY(TestDecl->internalContext());
|
|
QCOMPARE(TestDecl->internalContext()->localDeclarations().count(), 2);
|
|
|
|
CppClassType::Ptr subType = TestDecl->internalContext()->localDeclarations()[1]->type<CppClassType>();
|
|
QVERIFY(subType);
|
|
|
|
QCOMPARE(type1->declaration(0)->abstractType()->indexed(), type2->declaration(0)->abstractType()->indexed());
|
|
QCOMPARE(type2->declaration(0)->abstractType()->indexed(), type3->indexed());
|
|
QCOMPARE(type1->declaration(0)->abstractType()->indexed(), type12->declaration(0)->abstractType()->indexed());
|
|
kDebug() << type4->qualifiedIdentifier().toString();
|
|
kDebug() << type4->declaration(0)->toString();
|
|
QCOMPARE(type4->declaration(0)->abstractType()->indexed(), type5->indexed());
|
|
QCOMPARE(type3->declaration(top)->internalContext()->scopeIdentifier(true), QualifiedIdentifier("Test"));
|
|
QCOMPARE(type5->declaration(top)->internalContext()->scopeIdentifier(true), QualifiedIdentifier("Test::SubTest"));
|
|
QCOMPARE(type3->declaration(top)->qualifiedIdentifier(), QualifiedIdentifier("Test"));
|
|
QCOMPARE(type5->declaration(top)->qualifiedIdentifier(), QualifiedIdentifier("Test::SubTest"));
|
|
|
|
///@todo think about this
|
|
QCOMPARE(type5->declaration(top)->identifier(), Identifier("SubTest"));
|
|
QVERIFY(subType->equals(type5.unsafeData()));
|
|
QVERIFY(type5->equals(subType.unsafeData()));
|
|
kDebug() << type5->toString() << type4->toString();
|
|
kDebug() << type4->qualifiedIdentifier().toString() << type5->qualifiedIdentifier().toString();
|
|
QVERIFY(type4->equals(type5.unsafeData()));
|
|
QVERIFY(type5->equals(type4.unsafeData()));
|
|
kDebug() << subType->toString();
|
|
QCOMPARE(subType->declaration(0)->abstractType()->indexed(), type5->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testForwardDeclaration3()
|
|
{
|
|
QByteArray method("namespace B {class Test;} B::Test t; namespace B { class Test {int i; class SubTest; };} B::Test::SubTest t2; namespace B {class Test::SubTest{ int i;};}");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 5);
|
|
QCOMPARE(top->childContexts().count(), 3);
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->childContexts()[0]->localDeclarations()[0]));
|
|
|
|
ForwardDeclaration* forwardDecl = static_cast<ForwardDeclaration*>(top->childContexts()[0]->localDeclarations()[0]);
|
|
kDebug() << forwardDecl->toString();
|
|
QVERIFY(forwardDecl->resolve(0));
|
|
QCOMPARE(forwardDecl->resolve(0), top->childContexts()[1]->localDeclarations()[0]);
|
|
|
|
CppClassType::Ptr type1 = top->childContexts()[0]->localDeclarations()[0]->type<CppClassType>();
|
|
CppClassType::Ptr type2 = top->localDeclarations()[1]->type<CppClassType>();
|
|
CppClassType::Ptr type3 = top->childContexts()[1]->localDeclarations()[0]->type<CppClassType>();
|
|
CppClassType::Ptr type4 = top->localDeclarations()[3]->type<CppClassType>();
|
|
CppClassType::Ptr type5 = top->childContexts()[2]->childContexts()[0]->localDeclarations()[0]->type<CppClassType>();
|
|
|
|
QCOMPARE(top->childContexts()[2]->localScopeIdentifier(), QualifiedIdentifier("B"));
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->type(), DUContext::Helper);
|
|
QCOMPARE(top->childContexts()[2]->childContexts()[0]->localScopeIdentifier(), QualifiedIdentifier("Test"));
|
|
|
|
|
|
|
|
QVERIFY(type1);
|
|
QVERIFY(type2);
|
|
QVERIFY(type3);
|
|
QVERIFY(type4);
|
|
QVERIFY(type5);
|
|
|
|
Declaration* TestDecl = top->childContexts()[1]->localDeclarations()[0];
|
|
QVERIFY(TestDecl->internalContext());
|
|
QCOMPARE(TestDecl->internalContext()->localDeclarations().count(), 2);
|
|
CppClassType::Ptr subType = TestDecl->internalContext()->localDeclarations()[1]->type<CppClassType>();
|
|
QVERIFY(subType);
|
|
|
|
QCOMPARE(type1->indexed(), type2->indexed());
|
|
QCOMPARE(type2->declaration(top)->abstractType()->indexed(), type3->indexed());
|
|
QCOMPARE(subType->declaration(top)->abstractType()->indexed(), type4->declaration(top)->abstractType()->indexed());
|
|
kDebug() << type4->declaration(top)->qualifiedIdentifier().toString() << type5->qualifiedIdentifier().toString();
|
|
QCOMPARE(type4->declaration(top)->abstractType()->indexed(), type5->indexed());
|
|
|
|
}
|
|
|
|
void TestDUChain::testForwardDeclaration4()
|
|
{
|
|
QByteArray method("class Forward;\n"
|
|
"class Test\n"
|
|
"{\n"
|
|
" virtual Test a(Forward) const=0;\n"
|
|
" virtual Forward b(Forward) const=0;\n"
|
|
" virtual Forward c(Forward);\n"
|
|
" virtual Test d(Forward);\n"
|
|
"};");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 2);
|
|
QCOMPARE(top->childContexts().count(), 1);
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->localDeclarations()[0]));
|
|
|
|
ForwardDeclaration* forwardDecl = static_cast<ForwardDeclaration*>(top->localDeclarations()[0]);
|
|
|
|
QCOMPARE(forwardDecl->uses().size(), 1);
|
|
QCOMPARE(forwardDecl->uses().begin()->size(), 6);
|
|
QCOMPARE(forwardDecl->uses().begin()->at(0), RangeInRevision(3, 19, 3, 26));
|
|
QCOMPARE(forwardDecl->uses().begin()->at(1), RangeInRevision(4, 12, 4, 19));
|
|
QCOMPARE(forwardDecl->uses().begin()->at(2), RangeInRevision(4, 22, 4, 29));
|
|
QCOMPARE(forwardDecl->uses().begin()->at(3), RangeInRevision(5, 12, 5, 19));
|
|
QCOMPARE(forwardDecl->uses().begin()->at(4), RangeInRevision(5, 22, 5, 29));
|
|
QCOMPARE(forwardDecl->uses().begin()->at(5), RangeInRevision(6, 19, 6, 26));
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateForwardDeclaration()
|
|
{
|
|
QByteArray method("class B{}; template<class T = B>class Test; Test<B> t; template<class T = B>class Test {}; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
|
|
QVERIFY(top->localDeclarations()[1]->internalContext());
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->localDeclarations()[1]));
|
|
|
|
CppClassType::Ptr type1 = top->localDeclarations()[1]->type<CppClassType>();
|
|
CppClassType::Ptr type2 = top->localDeclarations()[2]->type<CppClassType>();
|
|
CppClassType::Ptr type3 = top->localDeclarations()[3]->type<CppClassType>();
|
|
|
|
QVERIFY(type1);
|
|
QVERIFY(type2);
|
|
QVERIFY(type3);
|
|
|
|
TemplateDeclaration* temp1Decl = dynamic_cast<TemplateDeclaration*>(type1->declaration(top));
|
|
QVERIFY(temp1Decl);
|
|
TemplateDeclaration* temp2Decl = dynamic_cast<TemplateDeclaration*>(type2->declaration(top));
|
|
QVERIFY(temp2Decl);
|
|
TemplateDeclaration* temp3Decl = dynamic_cast<TemplateDeclaration*>(type3->declaration(top));
|
|
QVERIFY(temp3Decl);
|
|
|
|
TemplateDeclaration* temp1DeclResolved = dynamic_cast<TemplateDeclaration*>(type1->declaration(top));
|
|
QVERIFY(temp1DeclResolved);
|
|
TemplateDeclaration* temp2DeclResolved = dynamic_cast<TemplateDeclaration*>(type2->declaration(top));
|
|
QVERIFY(temp2DeclResolved);
|
|
|
|
QVERIFY(dynamic_cast<Declaration*>(temp1DeclResolved)->type<CppClassType>());
|
|
QVERIFY(dynamic_cast<Declaration*>(temp2DeclResolved)->type<CppClassType>());
|
|
|
|
QCOMPARE(temp2Decl->instantiatedFrom(), temp1Decl);
|
|
QCOMPARE(temp2DeclResolved->instantiatedFrom(), temp1DeclResolved);
|
|
|
|
QVERIFY(type2->declaration(0)->abstractType().unsafeData());
|
|
QVERIFY(type2->declaration(0)->type<CppClassType>().unsafeData());
|
|
QCOMPARE(temp2DeclResolved->instantiatedFrom(), temp3Decl);
|
|
|
|
QualifiedIdentifier t("Test<>");
|
|
kDebug() << "searching" << t;
|
|
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("Test<>"));
|
|
QVERIFY(decl);
|
|
QCOMPARE(decl->abstractType()->toString(), QString("Test< B >"));
|
|
|
|
}
|
|
|
|
void TestDUChain::testTemplateForwardDeclaration2()
|
|
{
|
|
QByteArray method("class B{}; template<class T = B, class Q = B, class R = B>class Test; Test<B> t; template<class T, class Q, class R>class Test { T a; Q b; R c;}; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().count(), 4);
|
|
|
|
QVERIFY(top->localDeclarations()[1]->internalContext());
|
|
|
|
QVERIFY(dynamic_cast<ForwardDeclaration*>(top->localDeclarations()[1]));
|
|
|
|
CppClassType::Ptr type1 = top->localDeclarations()[1]->type<CppClassType>();
|
|
CppClassType::Ptr type2 = top->localDeclarations()[2]->type<CppClassType>();
|
|
CppClassType::Ptr type3 = top->localDeclarations()[3]->type<CppClassType>();
|
|
|
|
QVERIFY(type1);
|
|
QVERIFY(type2);
|
|
QVERIFY(type3);
|
|
|
|
QCOMPARE(type1->declaration(0)->abstractType()->indexed(), type3->indexed());
|
|
|
|
TemplateDeclaration* temp1Decl = dynamic_cast<TemplateDeclaration*>(type1->declaration(top));
|
|
QVERIFY(temp1Decl);
|
|
TemplateDeclaration* temp2Decl = dynamic_cast<TemplateDeclaration*>(type2->declaration(top));
|
|
QVERIFY(temp2Decl);
|
|
Declaration* temp2DeclForward = dynamic_cast<Declaration*>(type2->declaration(top));
|
|
QVERIFY(temp2DeclForward);
|
|
TemplateDeclaration* temp3Decl = dynamic_cast<TemplateDeclaration*>(type3->declaration(top));
|
|
QVERIFY(temp3Decl);
|
|
QCOMPARE(temp2Decl->instantiatedFrom(), temp1Decl);
|
|
QCOMPARE(dynamic_cast<TemplateDeclaration*>(temp2DeclForward)->instantiatedFrom(), temp3Decl);
|
|
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("Test<>"));
|
|
QVERIFY(decl);
|
|
QVERIFY(decl->internalContext());
|
|
Declaration* aDecl = findDeclaration(decl->logicalInternalContext(0), QualifiedIdentifier("a"));
|
|
QVERIFY(aDecl);
|
|
Declaration* bDecl = findDeclaration(decl->logicalInternalContext(0), QualifiedIdentifier("b"));
|
|
QVERIFY(bDecl);
|
|
Declaration* cDecl = findDeclaration(decl->logicalInternalContext(0), QualifiedIdentifier("c"));
|
|
QVERIFY(cDecl);
|
|
|
|
}
|
|
|
|
void TestDUChain::testUses()
|
|
{
|
|
QByteArray method(
|
|
"class GenericArgument\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" GenericArgument() {}\n"
|
|
" GenericArgument( const char*, const void* ) {}\n"
|
|
"};\n"
|
|
"\n"
|
|
"template <class T>\n"
|
|
"class Argument : public GenericArgument\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" Argument( const char* name, const T &value )\n"
|
|
" : GenericArgument( name, static_cast<const void*>( &value ) )\n"
|
|
" {}\n"
|
|
"};\n"
|
|
"\n"
|
|
"class A\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" A()\n"
|
|
" {\n"
|
|
" A::invokeMethod( this, \"hello\", Argument<bool>( \"test\", true ) );\n"
|
|
" }\n"
|
|
"\n"
|
|
" void invokeMethod( A*, const char*, int foo = 0, const GenericArgument &arg = GenericArgument() ) {}\n"
|
|
" void invokeMethod( A*, const char*, const GenericArgument& ) {}\n"
|
|
"};\n"
|
|
);
|
|
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().size(), 4);
|
|
QCOMPARE(top->childContexts().at(0)->type(), DUContext::Class);
|
|
QCOMPARE(top->childContexts().at(1)->type(), DUContext::Template);
|
|
QCOMPARE(top->childContexts().at(2)->type(), DUContext::Class);
|
|
QCOMPARE(top->childContexts().at(3)->type(), DUContext::Class);
|
|
|
|
QList<Declaration*> decls = top->findDeclarations(QualifiedIdentifier("A::invokeMethod"));
|
|
QCOMPARE(decls.count(), 2);
|
|
|
|
// only declaration 2 is used, check this now
|
|
QCOMPARE(decls.at( 0 )->uses().count(), 0);
|
|
QCOMPARE(decls.at( 1 )->uses().count(), 1);
|
|
|
|
}
|
|
|
|
void TestDUChain::testCtorTypes()
|
|
{
|
|
QByteArray method(
|
|
"class A\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" A() {}\n"
|
|
" A( int ) {}\n"
|
|
" A( int* ) {}\n"
|
|
" A( int, int ) {}\n"
|
|
"};\n"
|
|
);
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QVector< Declaration* > ctors = top->childContexts().first()->localDeclarations();
|
|
|
|
QList< QPair<IndexedType, IndexedString> > encountered;
|
|
QMap< QPair<IndexedType, IndexedString>, int > encountered2;
|
|
|
|
for ( int i = 0; i < ctors.size(); ++i ) {
|
|
for ( int j = i + 1; j < ctors.size(); ++j ) {
|
|
kDebug() << "comparing type of " << ctors[i]->toString() << "with" << ctors[j]->toString();
|
|
QVERIFY(ctors[i]->indexedType() != ctors[j]->indexedType());
|
|
}
|
|
QList< Declaration* > decs = top->childContexts().first()->findLocalDeclarations(
|
|
ctors[i]->identifier(), CursorInRevision::invalid(), 0, ctors[i]->abstractType(), DUContext::OnlyFunctions);
|
|
QCOMPARE(decs.count(), 1);
|
|
|
|
QPair<IndexedType, IndexedString> key = qMakePair(ctors[i]->indexedType(), ctors[i]->identifier().identifier());
|
|
QVERIFY(!encountered.contains(key));
|
|
encountered << key;
|
|
|
|
// everything works, but this fails:
|
|
QVERIFY(!encountered2.contains(key));
|
|
encountered2.insert(key, 0);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testConst()
|
|
{
|
|
{
|
|
QByteArray method("class A{}; const char* a; const char& b; char* const & c; char* const d; const A e; const A* f; A* const g;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 8);
|
|
PointerType::Ptr a = top->localDeclarations()[1]->type<PointerType>();
|
|
QVERIFY(a);
|
|
QVERIFY(!(a->modifiers() & AbstractType::ConstModifier));
|
|
IntegralType::Ptr a2 = a->baseType().cast<IntegralType>();
|
|
QVERIFY(a2);
|
|
QVERIFY(a2->modifiers() & AbstractType::ConstModifier);
|
|
|
|
ReferenceType::Ptr b = top->localDeclarations()[2]->type<ReferenceType>();
|
|
QVERIFY(b);
|
|
QVERIFY(!(b->modifiers() & AbstractType::ConstModifier));
|
|
IntegralType::Ptr b2 = b->baseType().cast<IntegralType>();
|
|
QVERIFY(b2);
|
|
QVERIFY(b2->modifiers() & AbstractType::ConstModifier);
|
|
|
|
ReferenceType::Ptr c = top->localDeclarations()[3]->type<ReferenceType>();
|
|
QVERIFY(c);
|
|
QVERIFY(!(c->modifiers() & AbstractType::ConstModifier));
|
|
PointerType::Ptr c2 = c->baseType().cast<PointerType>();
|
|
QVERIFY(c2);
|
|
QVERIFY(c2->modifiers() & AbstractType::ConstModifier);
|
|
IntegralType::Ptr c3 = c2->baseType().cast<IntegralType>();
|
|
QVERIFY(c3);
|
|
QVERIFY(!(c3->modifiers() & AbstractType::ConstModifier));
|
|
|
|
PointerType::Ptr d = top->localDeclarations()[4]->type<PointerType>();
|
|
QVERIFY(d);
|
|
QVERIFY(d->modifiers() & AbstractType::ConstModifier);
|
|
IntegralType::Ptr d2 = d->baseType().cast<IntegralType>();
|
|
QVERIFY(d2);
|
|
QVERIFY(!(d2->modifiers() & AbstractType::ConstModifier));
|
|
|
|
CppClassType::Ptr e = top->localDeclarations()[5]->type<CppClassType>();
|
|
QVERIFY(e);
|
|
QVERIFY(e->modifiers() & AbstractType::ConstModifier);
|
|
|
|
PointerType::Ptr f = top->localDeclarations()[6]->type<PointerType>();
|
|
QVERIFY(f);
|
|
QVERIFY(!(f->modifiers() & AbstractType::ConstModifier));
|
|
CppClassType::Ptr f2 = f->baseType().cast<CppClassType>();
|
|
QVERIFY(f2);
|
|
QVERIFY(f2->modifiers() & AbstractType::ConstModifier);
|
|
|
|
PointerType::Ptr g = top->localDeclarations()[7]->type<PointerType>();
|
|
QVERIFY(g);
|
|
QVERIFY(g->modifiers() & AbstractType::ConstModifier);
|
|
CppClassType::Ptr g2 = g->baseType().cast<CppClassType>();
|
|
QVERIFY(g2);
|
|
QVERIFY(!(g2->modifiers() & AbstractType::ConstModifier));
|
|
}
|
|
{
|
|
QByteArray method("class A; template<class T> class B; B<const A*> ca;B<A* const> cb;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 4);
|
|
QCOMPARE(top->localDeclarations()[2]->abstractType()->toString().trimmed(), QString("B< const A* >"));
|
|
QCOMPARE(top->localDeclarations()[3]->abstractType()->toString().trimmed(), QString("B< A* const >"));
|
|
}
|
|
{
|
|
QByteArray method("class A; A* a = const_cast<A*>(bla);");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
}
|
|
{
|
|
QByteArray method("class C;const C& c;");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
QVERIFY(top->localDeclarations()[1]->type<ReferenceType>());
|
|
QVERIFY(top->localDeclarations()[1]->type<ReferenceType>()->baseType());
|
|
QVERIFY(top->localDeclarations()[1]->type<ReferenceType>()->baseType()->modifiers() & AbstractType::ConstModifier);
|
|
kDebug() << top->localDeclarations()[1]->type<ReferenceType>()->toString();
|
|
}}
|
|
|
|
void TestDUChain::testDeclarationId()
|
|
{
|
|
QByteArray method("template<class T> class C { template<class T2> class C2{}; }; ");
|
|
|
|
LockedTopDUContext top = parse(method, DumpNone);
|
|
|
|
QVERIFY(top->inSymbolTable());
|
|
QCOMPARE(top->localDeclarations().count(), 1);
|
|
QVERIFY(top->localDeclarations()[0]->internalContext());
|
|
QVERIFY(top->localDeclarations()[0]->inSymbolTable());
|
|
QCOMPARE(top->localDeclarations()[0]->internalContext()->localDeclarations().count(), 1);
|
|
|
|
QCOMPARE(top->childContexts().count(), 2);
|
|
QCOMPARE(top->childContexts()[1]->localDeclarations().count(), 1);
|
|
QVERIFY(top->childContexts()[1]->localDeclarations()[0]->inSymbolTable());
|
|
//kDebug() << "pointer of C2:" << top->childContexts()[1]->localDeclarations()[0];
|
|
Declaration* decl = findDeclaration(top, QualifiedIdentifier("C<int>::C2<float>"));
|
|
QVERIFY(decl);
|
|
kDebug() << decl->toString();
|
|
kDebug() << decl->qualifiedIdentifier().toString();
|
|
DeclarationId id = decl->id();
|
|
QVERIFY(top->localDeclarations()[0]->internalContext());
|
|
// kDebug() << "id:" << id.m_direct << id.m_specialization << "indirect:" << id.indirect.m_identifier.index << id.indirect.m_additionalIdentity << "direct:" << *((uint*)(&id.direct)) << *(((uint*)(&id.direct))+1);
|
|
Declaration* declAgain = id.getDeclaration(top);
|
|
QVERIFY(!id.isDirect());
|
|
QVERIFY(declAgain);
|
|
QCOMPARE(declAgain->qualifiedIdentifier().toString(), decl->qualifiedIdentifier().toString());
|
|
QCOMPARE(declAgain, decl);
|
|
//kDebug() << declAgain->qualifiedIdentifier().toString();
|
|
//kDebug() << declAgain->toString();
|
|
QCOMPARE(declAgain, decl);
|
|
|
|
}
|
|
|
|
void TestDUChain::testFileParse()
|
|
{
|
|
//QSKIP("Unwanted", SkipSingle);
|
|
|
|
//QFile file("/opt/kde4/src/kdevelop/languages/cpp/duchain/tests/files/membervariable.cpp");
|
|
QFile file("/opt/kde4/src/kdevelop/languages/csharp/parser/csharp_parser.cpp");
|
|
//QFile file("/opt/kde4/src/kdevelop/plugins/outputviews/makewidget.cpp");
|
|
//QFile file("/opt/kde4/src/kdelibs/kate/part/katecompletionmodel.h");
|
|
|
|
//QFile file("/opt/kde4/src/kdevelop/lib/kdevbackgroundparser.cpp");
|
|
//QFile file("/opt/qt-copy/src/gui/kernel/qwidget.cpp");
|
|
QVERIFY( file.open( QIODevice::ReadOnly ) );
|
|
|
|
QByteArray fileData = file.readAll();
|
|
file.close();
|
|
QString contents = QString::fromUtf8( fileData.constData() );
|
|
rpp::Preprocessor preprocessor;
|
|
rpp::pp pp(&preprocessor);
|
|
|
|
QByteArray preprocessed = stringFromContents(pp.processFile("anonymous", fileData));
|
|
|
|
LockedTopDUContext top = parse(preprocessed, DumpNone);
|
|
|
|
}
|
|
|
|
void TestDUChain::testAutoTypeIntegral_data()
|
|
{
|
|
QTest::addColumn<QString>("code");
|
|
QTest::addColumn<uint>("datatype");
|
|
QTest::addColumn<bool>("constness");
|
|
QTest::addColumn<QString>("string");
|
|
|
|
QTest::newRow("int") << "auto x = 1;" << (uint) IntegralType::TypeInt << false << "int";
|
|
QTest::newRow("double") << "auto x = 1.0;" << (uint) IntegralType::TypeDouble << false << "double";
|
|
QTest::newRow("bool") << "auto x = false;" << (uint) IntegralType::TypeBoolean << false << "bool";
|
|
QTest::newRow("const-int-var") << "int a = 1; const auto x = a;" << (uint) IntegralType::TypeInt << true << "const int";
|
|
}
|
|
|
|
void TestDUChain::testAutoTypeIntegral()
|
|
{
|
|
QFETCH(QString, code);
|
|
QFETCH(uint, datatype);
|
|
QFETCH(bool, constness);
|
|
QFETCH(QString, string);
|
|
|
|
LockedTopDUContext top = parse(code.toLocal8Bit(), DumpAll);
|
|
QVERIFY(top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
QVERIFY(top->localDeclarations().count() >= 1);
|
|
Declaration* dec = top->findLocalDeclarations(Identifier("x")).first();
|
|
QVERIFY(dec);
|
|
IntegralType::Ptr type = dec->abstractType().cast<IntegralType>();
|
|
QVERIFY(type);
|
|
QCOMPARE(type->dataType(), datatype);
|
|
QCOMPARE((bool) (type->modifiers() & AbstractType::ConstModifier), constness);
|
|
QCOMPARE(type->toString(), string);
|
|
}
|
|
|
|
void TestDUChain::testAutoTypes()
|
|
{
|
|
LockedTopDUContext top = parse("struct Foo{}; int main() {\n"
|
|
" auto v1 = new Foo;"
|
|
" auto v2 = Foo;"
|
|
" int tmp1 = 0; auto v3 = &tmp1;"
|
|
// TODO: support this, when including <initializer_list>
|
|
// " auto v4 = {1,2};"
|
|
// " auto v5 = {1.0,2.0};"
|
|
"}\n", DumpAll);
|
|
QVERIFY(top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
DUContext* ctx = top->childContexts().last();
|
|
{
|
|
Declaration* dec = ctx->findDeclarations(Identifier("v1")).first();
|
|
PointerType::Ptr type = dec->abstractType().cast<PointerType>();
|
|
QVERIFY(type);
|
|
StructureType::Ptr structType = type->baseType().cast<StructureType>();
|
|
QVERIFY(structType);
|
|
QCOMPARE(structType->qualifiedIdentifier().toString(), QString("Foo"));
|
|
}
|
|
{
|
|
Declaration* dec = ctx->findDeclarations(Identifier("v2")).first();
|
|
StructureType::Ptr type = dec->abstractType().cast<StructureType>();
|
|
QEXPECT_FAIL("", "It's a delayed type, not a structure type...", Continue);
|
|
QVERIFY(type);
|
|
//TODO: QCOMPARE(type->qualifiedIdentifier().toString(), QString("Foo"));
|
|
}
|
|
{
|
|
Declaration* dec = ctx->findDeclarations(Identifier("v3")).first();
|
|
PointerType::Ptr type = dec->abstractType().cast<PointerType>();
|
|
QVERIFY(type);
|
|
IntegralType::Ptr intType = type->baseType().cast<IntegralType>();
|
|
QVERIFY(intType);
|
|
QCOMPARE(intType->dataType(), (uint) IntegralType::TypeInt);
|
|
}
|
|
}
|
|
|
|
void TestDUChain::testCommentAfterFunctionCall()
|
|
{
|
|
// testcase for bug https://bugs.kde.org/show_bug.cgi?id=241793
|
|
|
|
LockedTopDUContext top = parse("class View;\n"
|
|
"void setView(View* m_view) {\n"
|
|
" setView(0);\n"
|
|
" setView(m_view); //\n"
|
|
"}\n", DumpAll);
|
|
QVERIFY(top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts().size(), 2);
|
|
|
|
QCOMPARE(top->childContexts().first()->localDeclarations().size(), 1);
|
|
Declaration* m_view = top->childContexts().first()->localDeclarations().first();
|
|
|
|
QVERIFY(top->childContexts().last()->localDeclarations().isEmpty());
|
|
QCOMPARE(m_view->uses().size(), 1);
|
|
}
|
|
|
|
void TestDUChain::testNestedNamespace()
|
|
{
|
|
// see bug: https://bugs.kde.org/show_bug.cgi?id=273658
|
|
|
|
// 1 2 3
|
|
// 123456789012345678901234567890
|
|
LockedTopDUContext top = parse( "namespace v8 {\n"
|
|
" struct Isolate { int bar(); };\n"
|
|
" namespace internal {\n"
|
|
" struct Isolate { int foo(); };\n"
|
|
" void function() {\n"
|
|
" Isolate a;\n" // this should be v8::internal::Isolate, but kdevelop thinks it is v8::Isolate
|
|
" a.foo();\n"
|
|
" }\n"
|
|
" }\n"
|
|
"}\n", DumpNone );
|
|
QVERIFY(top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top->problems().isEmpty());
|
|
|
|
// namespace v8
|
|
QCOMPARE(top->childContexts().size(), 1);
|
|
QCOMPARE(top->localDeclarations().size(), 1);
|
|
|
|
DUContext* v8Ctx = top->childContexts().at(0);
|
|
QCOMPARE(v8Ctx->localDeclarations().size(), 2);
|
|
|
|
Declaration* v8IsolateDec = v8Ctx->localDeclarations().first();
|
|
QCOMPARE(v8IsolateDec->qualifiedIdentifier().toString(), QString("v8::Isolate"));
|
|
|
|
DUContext* v8InternalCtx = v8Ctx->childContexts().last();
|
|
QCOMPARE(v8InternalCtx->localDeclarations().size(), 2);
|
|
|
|
Declaration* v8InternalIsolateDec = v8InternalCtx->localDeclarations().first();
|
|
QCOMPARE(v8InternalIsolateDec->qualifiedIdentifier().toString(), QString("v8::internal::Isolate"));
|
|
|
|
DUContext* v8InternalFunctionCtx = v8InternalCtx->childContexts().last();
|
|
QCOMPARE(v8InternalFunctionCtx->localDeclarations().size(), 1);
|
|
|
|
Declaration* aDec = v8InternalFunctionCtx->localDeclarations().first();
|
|
QVERIFY(aDec->abstractType()->equals(v8InternalIsolateDec->abstractType().constData()));
|
|
|
|
QEXPECT_FAIL("", "uses are still associated incorreclty, probably to be fixed in TypeASTVisitor::visitSimpleTypeSpecifier", Abort);
|
|
QVERIFY(v8IsolateDec->uses().isEmpty());
|
|
QVERIFY(!v8InternalIsolateDec->uses().isEmpty());
|
|
QCOMPARE(v8InternalIsolateDec->uses().size(), 1);
|
|
QCOMPARE(v8InternalIsolateDec->uses().begin()->size(), 1);
|
|
QCOMPARE(v8InternalIsolateDec->uses().begin()->first().start.line, 5);
|
|
}
|
|
|
|
void TestDUChain::testPointerToMember()
|
|
{
|
|
// 1 2 3
|
|
// 123456789012345678901234567890
|
|
LockedTopDUContext top = parse( "struct AA {"
|
|
"\n int j;"
|
|
"\n};"
|
|
"\nstruct BB{"
|
|
"\n int AA::* pj;"
|
|
"\n};"
|
|
"\nvoid f(int AA::* par){"
|
|
"\n BB b;"
|
|
"\n int AA::* BB::* ppj=&BB::pj;"
|
|
"\n b.*ppj=par;"
|
|
"\n}",DumpAll
|
|
);
|
|
QVERIFY(top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top->problems().isEmpty());
|
|
QCOMPARE(top->childContexts().size(),4);
|
|
QCOMPARE(top->localDeclarations().size(),3);
|
|
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().begin()->size(),3);
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().begin()->size(),3);
|
|
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(0),RangeInRevision(4,6,4,8));
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(1),RangeInRevision(6,11,6,13));
|
|
QCOMPARE(top->localDeclarations().at(0)->uses().begin()->at(2),RangeInRevision(8,6,8,8));
|
|
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(0),RangeInRevision(7,2,7,4));
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(1),RangeInRevision(8,12,8,14));
|
|
QCOMPARE(top->localDeclarations().at(1)->uses().begin()->at(2),RangeInRevision(8,23,8,25));
|
|
|
|
{
|
|
DUContext* ctx = top->childContexts().at(1);
|
|
Declaration* dec = ctx->localDeclarations().first();
|
|
PtrToMemberType::Ptr type = dec->abstractType().cast<PtrToMemberType>();
|
|
QVERIFY(type);
|
|
StructureType::Ptr structType = type->classType().cast<StructureType>();
|
|
QVERIFY(structType);
|
|
QCOMPARE(structType->qualifiedIdentifier().toString(), QString("AA"));
|
|
}
|
|
{
|
|
DUContext* ctx = top->childContexts().at(3);
|
|
Declaration* dec = ctx->localDeclarations().at(1);
|
|
PtrToMemberType::Ptr type = dec->abstractType().cast<PtrToMemberType>();
|
|
|
|
{
|
|
QVERIFY(type);
|
|
StructureType::Ptr structType = type->classType().cast<StructureType>();
|
|
QVERIFY(structType);
|
|
QCOMPARE(structType->qualifiedIdentifier().toString(), QString("BB"));
|
|
}
|
|
|
|
PtrToMemberType::Ptr ptype = type->baseType().cast<PtrToMemberType>();
|
|
{
|
|
QVERIFY(ptype);
|
|
StructureType::Ptr structType = ptype->classType().cast<StructureType>();
|
|
QVERIFY(structType);
|
|
QCOMPARE(structType->qualifiedIdentifier().toString(), QString("AA"));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void TestDUChain::testMemberPtrCrash()
|
|
{
|
|
QByteArray code(
|
|
"template<typename T>\n"
|
|
"class A{};\n"
|
|
"class B{};\n"
|
|
"class C{};\n"
|
|
"A<B C::*> x;\n");
|
|
LockedTopDUContext top = parse(code, DumpNone);
|
|
}
|
|
|
|
void TestDUChain::testDeclarationHasUses()
|
|
{
|
|
QByteArray method(
|
|
"int a,b,c,d;\n"
|
|
"void f() {"
|
|
" if(a) {"
|
|
" b++;"
|
|
" }"
|
|
"}"
|
|
);
|
|
LockedTopDUContext top = parse(method, DumpAll);
|
|
|
|
QCOMPARE(top->childContexts().first()->findDeclarations(KDevelop::QualifiedIdentifier("a")).first()->hasUses(), true);
|
|
QCOMPARE(top->childContexts().first()->findDeclarations(KDevelop::QualifiedIdentifier("b")).first()->hasUses(), true);
|
|
QCOMPARE(top->childContexts().first()->findDeclarations(KDevelop::QualifiedIdentifier("c")).first()->hasUses(), false);
|
|
QCOMPARE(top->childContexts().first()->findDeclarations(KDevelop::QualifiedIdentifier("d")).first()->hasUses(), false);
|
|
}
|
|
|
|
void TestDUChain::testInitListRegressions()
|
|
{
|
|
{
|
|
// as see in /usr/include/c++/4.6.1/bits/stl_bvector.h
|
|
QByteArray code(
|
|
"#define __CHAR_BIT__ 8\n"
|
|
"typedef unsigned long _Bit_type;\n"
|
|
"enum { _S_word_bit = int(__CHAR_BIT__ * sizeof(_Bit_type)) };\n"
|
|
);
|
|
|
|
LockedTopDUContext top = parse(code, DumpAll);
|
|
QVERIFY(top);
|
|
QVERIFY(top->problems().isEmpty());
|
|
}
|
|
}
|
|
void TestDUChain::testBug269352()
|
|
{
|
|
// see also: https://bugs.kde.org/show_bug.cgi?id=269352
|
|
QByteArray code(
|
|
"class X {}; class Y {};\n"
|
|
"template <typename> class A;\n"
|
|
"template <typename, typename> struct B;\n"
|
|
"template <typename T1>\n"
|
|
"struct B<T1, Y> : B<A<T1>, X> {};\n"
|
|
// crucial: same typename like class above above
|
|
"template <typename A> struct B<A, X> {};\n"
|
|
);
|
|
|
|
LockedTopDUContext top = parse(code, DumpNone);
|
|
QVERIFY(top);
|
|
QVERIFY(top->problems().isEmpty());
|
|
Declaration *structB = top->localDeclarations()[3];
|
|
TemplateDeclaration *structBTemplate = dynamic_cast<TemplateDeclaration*>(structB);
|
|
QVERIFY(structBTemplate);
|
|
QEXPECT_FAIL("", "There should be zero instantiations, only the specializations", Continue);
|
|
QVERIFY(structBTemplate->instantiations().size() == 0);
|
|
//For now, at least there shouldn't be more than 1
|
|
QVERIFY(structBTemplate->instantiations().size() < 2);
|
|
QVERIFY(structBTemplate->specializationsSize() == 2);
|
|
Declaration *structBSpec = top->localDeclarations()[4];
|
|
TemplateDeclaration *structBSpecTemplate = dynamic_cast<TemplateDeclaration*>(structBSpec);
|
|
QVERIFY(structBSpecTemplate);
|
|
QVERIFY(structBSpecTemplate->instantiations().size() == 0);
|
|
QVERIFY(structBSpecTemplate->specializationsSize() == 0);
|
|
Declaration *structBSpec2 = top->localDeclarations()[5];
|
|
TemplateDeclaration *structBSpecTemplate2 = dynamic_cast<TemplateDeclaration*>(structBSpec2);
|
|
QVERIFY(structBSpecTemplate2);
|
|
QVERIFY(structBSpecTemplate2->instantiations().size() == 0);
|
|
QVERIFY(structBSpecTemplate2->specializationsSize() == 0);
|
|
}
|
|
|
|
void TestDUChain::testRenameClass()
|
|
{
|
|
QByteArray codeBefore(
|
|
"class A { enum { Foo = 1 }; };"
|
|
);
|
|
|
|
TopDUContext* top = parse(codeBefore, DumpDUChain);
|
|
{
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top);
|
|
QVERIFY(top->problems().isEmpty());
|
|
}
|
|
|
|
QByteArray codeAfter(
|
|
"class B { enum { Foo = 1 }; };"
|
|
);
|
|
|
|
parse(codeAfter, DumpDUChain, top);
|
|
DUChainReadLocker lock;
|
|
QVERIFY(top);
|
|
QVERIFY(top->problems().isEmpty());
|
|
QCOMPARE(top->localDeclarations().size(), 1);
|
|
QCOMPARE(top->localDeclarations().first()->identifier().toString(), QString("B"));
|
|
QCOMPARE(top->childContexts().size(), 1);
|
|
QCOMPARE(top->childContexts().first()->localScopeIdentifier().toString(), QString("B"));
|
|
}
|
|
|
|
void TestDUChain::testQProperty()
|
|
{
|
|
LockedTopDUContext top = parse(
|
|
"class QString {};\n"
|
|
"class A {\n"
|
|
" __qt_property__(QString a READ a WRITE setA NOTIFY aChanged)\n"
|
|
"public:\n"
|
|
" QString a();\n"
|
|
" void setA(const QString&);\n"
|
|
"__qt_signals__:\n"
|
|
" void aChanged(QString);\n"
|
|
"};\n");
|
|
|
|
QVERIFY(top);
|
|
QVERIFY(top->problems().isEmpty());
|
|
QCOMPARE(top->localDeclarations().size(), 2);
|
|
QCOMPARE(top->childContexts().size(), 2);
|
|
Declaration* QStringDecl = top->localDeclarations().first();
|
|
QCOMPARE(QStringDecl->uses().size(), 1);
|
|
QCOMPARE(QStringDecl->uses().begin()->size(), 4);
|
|
QCOMPARE(QStringDecl->uses().begin()->first(), RangeInRevision(2, 18, 2, 25));
|
|
QVector<Declaration*> decls = top->childContexts().last()->localDeclarations();
|
|
QCOMPARE(decls.size(), 3);
|
|
QCOMPARE(decls.at(0)->toString(), QLatin1String("QString a ()"));
|
|
QCOMPARE(decls.at(0)->uses().size(), 1);
|
|
QCOMPARE(decls.at(0)->uses().begin()->size(), 1);
|
|
QCOMPARE(decls.at(0)->uses().begin()->first(), RangeInRevision(2, 33, 2, 34));
|
|
QCOMPARE(decls.at(1)->toString(), QLatin1String("void setA (const QString&)"));
|
|
QCOMPARE(decls.at(1)->uses().size(), 1);
|
|
QCOMPARE(decls.at(1)->uses().begin()->size(), 1);
|
|
QCOMPARE(decls.at(1)->uses().begin()->first(), RangeInRevision(2, 41, 2, 45));
|
|
QCOMPARE(decls.at(2)->toString(), QLatin1String("void aChanged (QString)"));
|
|
QCOMPARE(decls.at(2)->uses().size(), 1);
|
|
QCOMPARE(decls.at(2)->uses().begin()->size(), 1);
|
|
QCOMPARE(decls.at(2)->uses().begin()->first(), RangeInRevision(2, 53, 2, 61));
|
|
}
|
|
|
|
#include "moc_test_duchain.cpp"
|