/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of PySide2. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "testtemplates.h" #include #include #include "testutil.h" #include #include void TestTemplates::testTemplateWithNamespace() { const char cppCode[] = "\n\ template struct QList {}; \n\ struct Url {\n\ void name();\n\ };\n\ namespace Internet {\n\ struct Url{};\n\ struct Bookmarks {\n\ QList list();\n\ };\n\ }"; const char xmlCode0[] = "\n\ \n\ \n\ "; QTemporaryFile file; QVERIFY(file.open()); file.write(xmlCode0); file.close(); QString xmlCode1 = QString::fromLatin1("\n\ \n\ \n\ \n\ \n\ \n\ \n\ ").arg(file.fileName()); QScopedPointer builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Bookmarks")); QVERIFY(classB); const AbstractMetaFunction* func = classB->findFunction(QLatin1String("list")); AbstractMetaType* funcType = func->type(); QVERIFY(funcType); QCOMPARE(funcType->cppSignature(), QLatin1String("QList")); } void TestTemplates::testTemplateOnContainers() { const char cppCode[] = "\n\ struct Base {};\n\ template struct QList {}; \n\ namespace Namespace {\n\ enum SomeEnum { E1, E2 };\n\ template struct A {\n\ A foo(const QList >& a);\n\ };\n\ typedef A B;\n\ }\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isNull()); const AbstractMetaFunction* func = classB->findFunction(QLatin1String("foo")); AbstractMetaType* argType = func->arguments().first()->type(); QCOMPARE(argType->instantiations().count(), 1); QCOMPARE(argType->typeEntry()->qualifiedCppName(), QLatin1String("QList")); const AbstractMetaType* instance1 = argType->instantiations().first(); QCOMPARE(instance1->instantiations().count(), 1); QCOMPARE(instance1->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::A")); const AbstractMetaType* instance2 = instance1->instantiations().first(); QCOMPARE(instance2->instantiations().count(), 0); QCOMPARE(instance2->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::E1")); } void TestTemplates::testTemplateValueAsArgument() { const char cppCode[] = "\n\ template struct List {};\n\ void func(List arg) {}\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); QCOMPARE(globalFuncs.count(), 1); AbstractMetaFunction* func = globalFuncs.first(); QCOMPARE(func->minimalSignature(), QLatin1String("func(List)")); QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List")); } void TestTemplates::testTemplatePointerAsArgument() { const char cppCode[] = "\n\ template struct List {};\n\ void func(List* arg) {}\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); QCOMPARE(globalFuncs.count(), 1); AbstractMetaFunction* func = globalFuncs.first(); QCOMPARE(func->minimalSignature(), QLatin1String("func(List*)")); QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List *")); } void TestTemplates::testTemplateReferenceAsArgument() { const char cppCode[] = "\n\ template struct List {};\n\ void func(List& arg) {}\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); QCOMPARE(globalFuncs.count(), 1); AbstractMetaFunction* func = globalFuncs.first(); QCOMPARE(func->minimalSignature(), QLatin1String("func(List&)")); QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List &")); } void TestTemplates::testTemplateParameterFixup() { const char cppCode[] = "\n\ template\n\ struct List {\n\ struct Iterator {};\n\ void append(List l);\n\ void erase(List::Iterator it);\n\ };\n"; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n"; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); const AbstractMetaClassList templates = builder->templates(); QCOMPARE(templates.count(), 1); const AbstractMetaClass *list = templates.first(); // Verify that the parameter of "void append(List l)" gets fixed to "List" const AbstractMetaFunction *append = list->findFunction(QStringLiteral("append")); QVERIFY(append); QCOMPARE(append->arguments().size(), 1); QCOMPARE(append->arguments().at(0)->type()->cppSignature(), QLatin1String("List")); // Verify that the parameter of "void erase(Iterator)" is not modified const AbstractMetaFunction *erase = list->findFunction(QStringLiteral("erase")); QVERIFY(erase); QCOMPARE(erase->arguments().size(), 1); QCOMPARE(erase->arguments().at(0)->type()->cppSignature(), QLatin1String("List::Iterator")); } void TestTemplates::testInheritanceFromContainterTemplate() { const char cppCode[] = "\n\ template\n\ struct ListContainer {\n\ inline void push_front(const T& t);\n\ inline T& front();\n\ };\n\ struct FooBar {};\n\ struct FooBars : public ListContainer {};\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); AbstractMetaClassList templates = builder->templates(); QCOMPARE(classes.count(), 2); QCOMPARE(templates.count(), 1); const AbstractMetaClass* foobars = AbstractMetaClass::findClass(classes, QLatin1String("FooBars")); QCOMPARE(foobars->functions().count(), 4); const AbstractMetaClass* lc = templates.first(); QCOMPARE(lc->functions().count(), 2); } void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() { const char cppCode[] = "\n\ enum SomeEnum { E1, E2 };\n\ template struct Future;\n\ template\n\ struct A {\n\ A();\n\ void method();\n\ friend struct Future;\n\ };\n\ typedef A B;\n\ template struct Future {};\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isNull()); // 3 functions: simple constructor, copy constructor and "method()". QCOMPARE(classB->functions().count(), 3); } void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration() { const char cppCode[] = "\n\ namespace Namespace {\n\ enum SomeEnum { E1, E2 };\n\ template struct Future;\n\ template\n\ struct A {\n\ A();\n\ void method();\n\ friend struct Future;\n\ };\n\ typedef A B;\n\ template struct Future {};\n\ };\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::B")); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isNull()); // 3 functions: simple constructor, copy constructor and "method()". QCOMPARE(classB->functions().count(), 3); } void TestTemplates::testTypedefOfInstantiationOfTemplateClass() { const char cppCode[] = "\n\ namespace NSpace {\n\ enum ClassType {\n\ TypeOne\n\ };\n\ template\n\ struct BaseTemplateClass {\n\ inline ClassType getClassType() const { CLASS_TYPE; }\n\ };\n\ typedef BaseTemplateClass TypeOneClass;\n\ }\n\ "; const char xmlCode[] = "\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.count(), 3); const AbstractMetaClass* base = AbstractMetaClass::findClass(classes, QLatin1String("BaseTemplateClass")); QVERIFY(base); const AbstractMetaClass* one = AbstractMetaClass::findClass(classes, QLatin1String("TypeOneClass")); QVERIFY(one); QCOMPARE(one->templateBaseClass(), base); QCOMPARE(one->functions().count(), base->functions().count()); QVERIFY(one->isTypeDef()); const ComplexTypeEntry* oneType = one->typeEntry(); const ComplexTypeEntry* baseType = base->typeEntry(); QCOMPARE(oneType->baseContainerType(), baseType); QCOMPARE(one->baseClassNames(), QStringList(QLatin1String("BaseTemplateClass"))); QVERIFY(one->hasTemplateBaseClassInstantiations()); AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); QCOMPARE(instantiations.count(), 1); const AbstractMetaType* inst = instantiations.first(); QVERIFY(inst); QVERIFY(!inst->isEnum()); QVERIFY(!inst->typeEntry()->isEnum()); QVERIFY(inst->typeEntry()->isEnumValue()); QCOMPARE(inst->cppSignature(), QLatin1String("NSpace::TypeOne")); } void TestTemplates::testContainerTypeIncompleteArgument() { const char* cppCode ="\n\ template\n\ class Vector {\n\ void method(const Vector& vector);\n\ Vector otherMethod();\n\ };\n\ template \n\ void Vector::method(const Vector& vector) {}\n\ template \n\ Vector Vector::otherMethod() { return Vector(); }\n\ typedef Vector IntVector;\n\ "; const char* xmlCode = "\n\ \n\ \n\ \n\ \n\ "; QScopedPointer builder(TestUtil::parse(cppCode, xmlCode, true)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.count(), 1); AbstractMetaClass* vector = AbstractMetaClass::findClass(classes, QLatin1String("IntVector")); QVERIFY(vector); QVERIFY(vector->typeEntry()->baseContainerType()); QCOMPARE(reinterpret_cast(vector->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::VectorContainer); QCOMPARE(vector->functions().count(), 4); const AbstractMetaFunction* method = vector->findFunction(QLatin1String("method")); QVERIFY(method); QCOMPARE(method->signature(), QLatin1String("method(const Vector & vector)")); const AbstractMetaFunction* otherMethod = vector->findFunction(QLatin1String("otherMethod")); QVERIFY(otherMethod); QCOMPARE(otherMethod->signature(), QLatin1String("otherMethod()")); QVERIFY(otherMethod->type()); QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector")); } QTEST_APPLESS_MAIN(TestTemplates)