From 26d6ef0c8f359b3bc29e2f68238e28f86e9448c5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 2 Aug 2018 14:18:11 +0200 Subject: shiboken: Implement template inheritance for fields Add the fields to the typedef'ed class specializing the type similar to the functions. Task-number: PYSIDE-725 Change-Id: I2daae9bd3c8a73fbd868f495cfc3a2dfba703103 Reviewed-by: Christian Tismer --- .../shiboken2/ApiExtractor/abstractmetabuilder.cpp | 20 +++++ .../shiboken2/ApiExtractor/tests/testtemplates.cpp | 98 ++++++++++++++++++++++ .../shiboken2/ApiExtractor/tests/testtemplates.h | 2 + 3 files changed, 120 insertions(+) (limited to 'sources/shiboken2/ApiExtractor') diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index cbe33ae22..bcd447023 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -2922,6 +2922,26 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, subclass->addFunction(f.take()); } + const AbstractMetaFieldList &subClassFields = subclass->fields(); + const AbstractMetaFieldList &templateClassFields = templateClass->fields(); + for (const AbstractMetaField *field : templateClassFields) { + // If the field is modified or the instantiation has a field named + // the same as an existing field we have shadowing, so we need to skip it. + if (field->isModifiedRemoved(TypeSystem::All) + || field->attributes().testFlag(AbstractMetaAttributes::Static) + || AbstractMetaField::find(subClassFields, field->name()) != nullptr) { + continue; + } + + QScopedPointer f(field->copy()); + f->setEnclosingClass(subclass); + AbstractMetaType *fieldType = inheritTemplateType(templateTypes, field->type()); + if (!fieldType) + continue; + f->replaceType(fieldType); + subclass->addField(f.take()); + } + subclass->setTemplateBaseClass(templateClass); subclass->setTemplateBaseClassInstantiations(templateTypes); subclass->setInterfaces(templateClass->interfaces()); diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp index 8d869e3f9..d32e24379 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -28,6 +28,7 @@ #include "testtemplates.h" #include +#include #include #include "testutil.h" #include @@ -438,4 +439,101 @@ typedef Vector IntVector; QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector")); } +// Perform checks on template inheritance; a typedef of a template class +// should result in rewritten types. +void TestTemplates::testTemplateTypeDefs_data() +{ + QTest::addColumn("cpp"); + QTest::addColumn("xml"); + + const char optionalClassDef[] = R"CPP( +template // Some value type similar to std::optional +class Optional { +public: + T value() const { return m_value; } + operator bool() const { return m_success; } + + T m_value; + bool m_success = false; +}; +)CPP"; + + const char xmlPrefix[] = R"XML( + + + +)XML"; + + const char xmlOptionalDecl[] = "\n"; + const char xmlOptionalIntDecl[] = "\n"; + const char xmlPostFix[] = "\n"; + + // Flat, global namespace + QString cpp; + QTextStream(&cpp) << optionalClassDef + << "typedef Optional IntOptional;\n"; + QString xml; + QTextStream(&xml) << xmlPrefix << xmlOptionalDecl << xmlOptionalIntDecl + << xmlPostFix; + QTest::newRow("global-namespace") + << cpp << xml; + + // Typedef from namespace Std + cpp.clear(); + QTextStream(&cpp) << "namespace Std {\n" << optionalClassDef << "}\n" + << "typedef Std::Optional IntOptional;\n"; + xml.clear(); + QTextStream(&xml) << xmlPrefix + << "\n" << xmlOptionalDecl + << "\n" << xmlOptionalIntDecl + << xmlPostFix; + QTest::newRow("namespace-Std") + << cpp << xml; + + // Typedef from nested class + cpp.clear(); + QTextStream(&cpp) << "class Outer {\npublic:\n" << optionalClassDef << "\n};\n" + << "typedef Outer::Optional IntOptional;\n"; + xml.clear(); + QTextStream(&xml) << xmlPrefix + << "\n" << xmlOptionalDecl + << "\n" << xmlOptionalIntDecl + << xmlPostFix; + QTest::newRow("nested-class") + << cpp << xml; +} + +void TestTemplates::testTemplateTypeDefs() +{ + QFETCH(QString, cpp); + QFETCH(QString, xml); + + const QByteArray cppBa = cpp.toLocal8Bit(); + const QByteArray xmlBa = xml.toLocal8Bit(); + QScopedPointer builder(TestUtil::parse(cppBa.constData(), xmlBa.constData(), true)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + const AbstractMetaClass *optional = AbstractMetaClass::findClass(classes, QLatin1String("Optional")); + QVERIFY(optional); + + // Find the typedef'ed class + const AbstractMetaClass *optionalInt = + AbstractMetaClass::findClass(classes, QLatin1String("IntOptional")); + QVERIFY(optionalInt); + QCOMPARE(optionalInt->templateBaseClass(), optional); + + // Check whether the value() method now has an 'int' return + const AbstractMetaFunction *valueMethod = + optionalInt->findFunction(QLatin1String("value")); + QVERIFY(valueMethod); + QCOMPARE(valueMethod->type()->cppSignature(), QLatin1String("int")); + + // Check whether the m_value field is of type 'int' + const AbstractMetaField *valueField = + optionalInt->findField(QLatin1String("m_value")); + QVERIFY(valueField); + QCOMPARE(valueField->type()->cppSignature(), QLatin1String("int")); +} + QTEST_APPLESS_MAIN(TestTemplates) diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h index 3e1565933..df3de18b9 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.h +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h @@ -46,6 +46,8 @@ private slots: void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration(); void testTypedefOfInstantiationOfTemplateClass(); void testContainerTypeIncompleteArgument(); + void testTemplateTypeDefs_data(); + void testTemplateTypeDefs(); }; #endif -- cgit v1.2.3