diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp | 286 |
1 files changed, 250 insertions, 36 deletions
diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp index 4c2930234..67ebcc606 100644 --- a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp @@ -1,40 +1,33 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of Qt for Python. -** -** $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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testresolvetype.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> +#include <abstractmetaenum.h> +#include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <complextypeentry.h> +#include <enumtypeentry.h> +#include <primitivetypeentry.h> +#include <typedatabase.h> + +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + +void TestResolveType::initTestCase() +{ + // For enum lookup in testFixDefaultArguments() + AbstractMetaBuilder::setCodeModelTestMode(true); +} void TestResolveType::testResolveReturnTypeFromParentScope() { - const char* cppCode = "\n\ + const char cppCode[] = "\n\ namespace A {\n\ struct B {\n\ struct C {};\n\ @@ -44,7 +37,7 @@ void TestResolveType::testResolveReturnTypeFromParentScope() C* method();\n\ };\n\ };"; - const char* xmlCode = R"XML( + const char xmlCode[] = R"XML( <typesystem package='Foo'> <namespace-type name='A'> <value-type name='B'> @@ -54,14 +47,235 @@ void TestResolveType::testResolveReturnTypeFromParentScope() </namespace-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("A::D")); + const auto classD = AbstractMetaClass::findClass(classes, "A::D"); QVERIFY(classD); - const auto meth = classD->findFunction(QLatin1String("method")); - QVERIFY(!meth.isNull()); + const auto meth = classD->findFunction("method"); + QVERIFY(meth); QVERIFY(meth); } -QTEST_APPLESS_MAIN(TestResolveType) +// Helper classes and functions for testing default value fixing. +// Put the AbstractMetaBuilder into test fixture struct to avoid having +// to re-parse for each data row. + +struct DefaultValuesFixture +{ + std::shared_ptr<AbstractMetaBuilder> builder; + + AbstractMetaType intType; + AbstractMetaType stringType; + AbstractMetaType classType; + AbstractMetaType listType; + AbstractMetaType enumType; + AbstractMetaClassCPtr klass{}; +}; + +Q_DECLARE_METATYPE(DefaultValuesFixture) +Q_DECLARE_METATYPE(AbstractMetaType) + +static int populateDefaultValuesFixture(DefaultValuesFixture *fixture) +{ + static const char cppCode[] =R"( +#include <string> +#include <list> + +namespace Namespace { +class Test +{ +public: + enum Enum { enumValue1, enumValue2 }; + + explicit Test(int x = INT_FIELD_1); + explicit Test(const std::string &t = std::string(CHAR_FIELD_1)); + + static void listFunc(std::list<Test> list = std::list<Test>()); + + static const int INT_FIELD_1 = 42; + static const char *CHAR_FIELD_1; + static const Enum DefaultValue = enumValue1; +}; +} // Namespace +)"; + static const char xmlCode[] = R"( +<typesystem package="Foo"> + <namespace-type name='Namespace'> + <value-type name='Test'> + <enum-type name='Enum'/> + </value-type> + </namespace-type> + <container-type name="std::list" type="list"/> +</typesystem> +)"; + + fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false)); + if (!fixture->builder) + return -1; + + for (const auto &klass : fixture->builder->classes()) { + if (klass->name() == u"Test") { + fixture->klass = klass; + break; + } + } + if (!fixture->klass) + return -2; + + fixture->classType = AbstractMetaType(fixture->klass->typeEntry()); + fixture->classType.decideUsagePattern(); + + for (const auto &f : fixture->klass->findFunctions("Test")) { + if (f->functionType() == AbstractMetaFunction::ConstructorFunction + && f->arguments().size() == 1) { + const auto type = f->arguments().constFirst().type(); + if (type.name() == u"int") + fixture->intType = type; + else + fixture->stringType = type; + } + } + if (fixture->intType.isVoid() || fixture->stringType.isVoid()) + return -3; + + auto listFunc = fixture->klass->findFunction("listFunc"); + if (!listFunc || listFunc->arguments().size() != 1) + return -3; + fixture->listType = listFunc->arguments().constFirst().type(); + + fixture->enumType = AbstractMetaType(fixture->klass->enums().constFirst().typeEntry()); + fixture->enumType.decideUsagePattern(); + return 0; +} + +void TestResolveType::testFixDefaultArguments_data() +{ + DefaultValuesFixture fixture; + const int setupOk = populateDefaultValuesFixture(&fixture); + + QTest::addColumn<DefaultValuesFixture>("fixture"); + QTest::addColumn<int>("setupOk"); // To verify setup + QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("int") << fixture << setupOk + << fixture.intType << "1" << "1"; + QTest::newRow("int-macro") << fixture << setupOk + << fixture.intType << "GL_MACRO" << "GL_MACRO"; + QTest::newRow("int-enum") << fixture << setupOk + << fixture.intType << "enumValue1" << "Namespace::Test::Enum::enumValue1"; + + // Test expansion of container types + QString expected = u"std::list<Namespace::Test>()"_s; + QTest::newRow("list") + << fixture << setupOk << fixture.listType + << expected << expected; + QTest::newRow("partially qualified list") + << fixture << setupOk << fixture.listType + << "std::list<Test>()" << expected; + + // Test field expansion + expected = u"Namespace::Test::INT_FIELD_1"_s; + QTest::newRow("qualified class field") + << fixture << setupOk << fixture.intType + << expected << expected; + QTest::newRow("partially qualified class field") + << fixture << setupOk << fixture.intType + << "Test::INT_FIELD_1" << expected; + QTest::newRow("unqualified class field") + << fixture << setupOk << fixture.intType + << "INT_FIELD_1" << expected; + + // Test field expansion when constructing some class + expected = u"QLatin1String(Namespace::Test::CHAR_FIELD_1)"_s; + QTest::newRow("class from qualified class field") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("class from partially qualified class field") + << fixture << setupOk << fixture.classType + << "QLatin1String(Test::CHAR_FIELD_1)" << expected; + QTest::newRow("class from unqualified class field") + << fixture << setupOk << fixture.classType + << "QLatin1String(CHAR_FIELD_1)" << expected; + + // Test field expansion when constructing class itself + expected = u"Namespace::Test(Namespace::Test::CHAR_FIELD_1)"_s; + QTest::newRow("self from qualified class field") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("self from partially qualified class field") + << fixture << setupOk << fixture.classType + << "Test(Test::CHAR_FIELD_1)" << expected; + QTest::newRow("self from unqualified class field") + << fixture << setupOk << fixture.classType + << "Test(CHAR_FIELD_1)" << expected; + + // Test enum expansion when constructing class itself + expected = u"Namespace::Test(Namespace::Test::Enum::enumValue1)"_s; + QTest::newRow("self from qualified enum") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("self from enum") + << fixture << setupOk << fixture.classType + << "Test(enumValue1)" << expected; + + // Don't qualify fields to "Test::Enum::DefaultValue" + QTest::newRow("enum from static field") + << fixture << setupOk << fixture.enumType + << "DefaultValue" << u"Namespace::Test::DefaultValue"_s; +} + +void TestResolveType::testFixDefaultArguments() +{ + QFETCH(DefaultValuesFixture, fixture); + QFETCH(int, setupOk); + QFETCH(AbstractMetaType, metaType); + QFETCH(QString, input); + QFETCH(QString, expected); + QCOMPARE(setupOk, 0); + const QString actual = fixture.builder->fixDefaultValue(input, metaType, fixture.klass); + QCOMPARE(actual, expected); +} + +// Verify that the typedefs of the C++ 11 integer types (int32_t, ...) +// are seen by the C++ parser, otherwise they are handled as unknown +// primitive types, causing invalid code to be generated. +// (see BuilderPrivate::visitHeader(), +// sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp). +void TestResolveType::testCppTypes() +{ + static const char cppCode[] =R"( +#include <cstdint> + +class Test +{ +public: + explicit Test(int32_t v); +}; +)"; + static const char xmlCode[] = R"( +<typesystem package="Foo"> + <value-type name='Test'/> + <primitive-type name='int32_t'/> +</typesystem> +)"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(builder); + AbstractMetaClassList classes = builder->classes(); + const auto testClass = AbstractMetaClass::findClass(classes, "Test"); + QVERIFY(testClass); + + auto *tdb = TypeDatabase::instance(); + auto int32TEntry = tdb->findType(u"int32_t"_s); + QVERIFY2(int32TEntry, "int32_t not found"); + QVERIFY(int32TEntry->isPrimitive()); + auto int32T = std::static_pointer_cast<const PrimitiveTypeEntry>(int32TEntry); + auto basicType = basicReferencedTypeEntry(int32T); + QVERIFY2(basicType != int32T, + "Typedef for int32_t not found. Check the system include paths."); +} + +QTEST_APPLESS_MAIN(TestResolveType) |