From 24cd62c9d18850707574ba7eb637ff24bee353a1 Mon Sep 17 00:00:00 2001 From: Renato Araujo Oliveira Filho Date: Tue, 6 Oct 2020 09:49:18 -0300 Subject: Update SmartPointers conversions * Updated test to accept base types derived using std::shared_ptr; * Generate new coode to be able to convert smart pointers into shared pointers of base class. Functions that accepts SharedPointer as argument should be able to accept SharedPointer if B is derived from A. Task-number: PYSIDE-1397 Change-Id: I7e5235980daaf4651dad3ab1c880373f1c64e134 Reviewed-by: Friedemann Kleint --- .../shiboken2/generator/shiboken2/cppgenerator.cpp | 97 +++++++++++++++++++++- .../shiboken2/generator/shiboken2/cppgenerator.h | 5 ++ .../generator/shiboken2/shibokengenerator.cpp | 2 +- .../tests/smartbinding/smart_pointer_test.py | 13 +++ 4 files changed, 113 insertions(+), 4 deletions(-) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index fe98146e3..05d9d97d6 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -255,6 +255,15 @@ const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass *meta && func->arguments().isEmpty() ? func : nullptr; } +const AbstractMetaType *CppGenerator::findSmartPointerInstantiation(const TypeEntry *entry) const +{ + for (auto i : instantiatedSmartPointers()) { + if (i->instantiations().at(0)->typeEntry() == entry) + return i; + } + return nullptr; +} + using FunctionGroupMap = QMap; // Prevent ELF symbol qt_version_tag from being generated into the source @@ -1644,6 +1653,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas } }; + if (!classContext.forSmartPointer()) { writeConversionsForType(metaClass->qualifiedCppName()); } else { @@ -1654,7 +1664,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas Qt::SkipEmptyParts); while (!lst.isEmpty()) { QString signature = lst.join(QLatin1String("::")); - writeConversions(QStringLiteral("%1<%2>").arg(smartPointerName, signature)); + writeConversions(QStringLiteral("%1<%2 >").arg(smartPointerName, signature)); lst.removeFirst(); } @@ -1746,6 +1756,30 @@ void CppGenerator::writeContainerConverterFunctions(QTextStream &s, const Abstra writePythonToCppConversionFunctions(s, containerType); } +void CppGenerator::writeSmartPointerConverterFunctions(QTextStream &s, const AbstractMetaType *smartPointerType) +{ + const AbstractMetaClass *targetClass = AbstractMetaClass::findClass(classes(), smartPointerType->instantiations().at(0)->typeEntry()); + + if (targetClass) { + const auto *smartPointerTypeEntry = + static_cast( + smartPointerType->typeEntry()); + + // TODO: Missing conversion to smart pointer pointer type: + + s << "// Register smartpointer conversion for all derived classes\n"; + const auto classes = getBaseClasses(targetClass); + for (auto k : classes) { + if (smartPointerTypeEntry->matchesInstantiation(k->typeEntry())) { + if (auto smartTargetType = findSmartPointerInstantiation(k->typeEntry())) { + s << INDENT << "// SmartPointer derived class: " << smartTargetType->cppSignature() << "\n"; + writePythonToCppConversionFunctions(s, smartPointerType, smartTargetType, {}, {}, {}); + } + } + } + } +} + void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, const GeneratorContext &context) { @@ -3062,10 +3096,10 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s, QTextStream c(&code); Indentor nested; if (conversion.isEmpty()) - conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn")); + conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType, QLatin1String("pyIn")); if (!preConversion.isEmpty()) c << nested << preConversion << Qt::endl; - const QString fullTypeName = getFullTypeName(targetType->typeEntry()); + const QString fullTypeName = targetType->isSmartPointer() ? targetType->cppSignature() : getFullTypeName(targetType->typeEntry()); c << nested << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = " << fullTypeName << '(' << conversion << ");"; QString sourceTypeName = fixedCppTypeName(sourceType); @@ -3933,6 +3967,44 @@ void CppGenerator::writeContainerConverterInitialization(QTextStream &s, const A writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv); } +void CppGenerator::writeSmartPointerConverterInitialization(QTextStream &s, const AbstractMetaType *type) +{ + const QByteArray cppSignature = type->cppSignature().toUtf8(); + auto writeConversionRegister = [this, &s](const AbstractMetaType *sourceType, const QString &targetTypeName, const QString &targetConverter) + { + const QString sourceTypeName = fixedCppTypeName(sourceType); + const QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); + const QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); + + writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv); + }; + + auto klass = AbstractMetaClass::findClass(classes(), type->instantiations().at(0)->typeEntry()); + if (!klass) + return; + + const auto classes = getBaseClasses(klass); + if (classes.isEmpty()) + return; + + s << INDENT << "// Register SmartPointer converter for type '" << cppSignature << "'." << Qt::endl; + s << INDENT << "///////////////////////////////////////////////////////////////////////////////////////"<< Qt::endl; + s << Qt::endl; + + for (auto k : classes) { + if (auto smartTargetType = findSmartPointerInstantiation(k->typeEntry())) + { + s << INDENT << "// Convert to SmartPointer derived class: [" << smartTargetType->cppSignature() << "]" << Qt::endl; + const QString converter = QLatin1String("Shiboken::Conversions::getConverter(\"%1\")").arg(smartTargetType->cppSignature()); + writeConversionRegister(type, fixedCppTypeName(smartTargetType), converter); + } else { + s << INDENT << "// Class not found:" << type->instantiations().at(0)->cppSignature(); + } + } + + s << INDENT << "///////////////////////////////////////////////////////////////////////////////////////"<< Qt::endl << Qt::endl; +} + void CppGenerator::writeExtendedConverterInitialization(QTextStream &s, const TypeEntry *externalType, const QVector& conversions) { @@ -6003,6 +6075,17 @@ bool CppGenerator::finishGeneration() s << Qt::endl; } + // Implicit smart pointers conversions + const auto smartPointersList = instantiatedSmartPointers(); + if (!smartPointersList.isEmpty()) { + s << "// SmartPointers converters.\n\n"; + for (const AbstractMetaType *smartPointer : smartPointersList) { + s << "// C++ to Python conversion for type '" << smartPointer->cppSignature() << "'.\n"; + writeSmartPointerConverterFunctions(s, smartPointer); + } + s << Qt::endl; + } + s << "#ifdef IS_PY3K\n"; s << "static struct PyModuleDef moduledef = {\n"; s << " /* m_base */ PyModuleDef_HEAD_INIT,\n"; @@ -6082,6 +6165,14 @@ bool CppGenerator::finishGeneration() } } + if (!smartPointersList.isEmpty()) { + s << Qt::endl; + for (const AbstractMetaType *smartPointer : smartPointersList) { + writeSmartPointerConverterInitialization(s, smartPointer); + s << Qt::endl; + } + } + if (!extendedConverters.isEmpty()) { s << Qt::endl; for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) { diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 1d7894734..41bd17f21 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -81,6 +81,8 @@ private: void writeContainerConverterFunctions(QTextStream &s, const AbstractMetaType *containerType); + void writeSmartPointerConverterFunctions(QTextStream &s, const AbstractMetaType *smartPointerType); + void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, const GeneratorContext &context); void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList &overloads, @@ -332,6 +334,7 @@ private: void writeEnumConverterInitialization(QTextStream &s, const TypeEntry *enumType); void writeEnumConverterInitialization(QTextStream &s, const AbstractMetaEnum *metaEnum); void writeContainerConverterInitialization(QTextStream &s, const AbstractMetaType *type); + void writeSmartPointerConverterInitialization(QTextStream &s, const AbstractMetaType *type); void writeExtendedConverterInitialization(QTextStream &s, const TypeEntry *externalType, const QVector& conversions); void writeParentChildManagement(QTextStream &s, const AbstractMetaFunction *func, bool userHeuristicForReturn); @@ -375,6 +378,8 @@ private: bool hasBoolCast(const AbstractMetaClass *metaClass) const { return boolCast(metaClass) != nullptr; } + const AbstractMetaType *findSmartPointerInstantiation(const TypeEntry *entry) const; + // Number protocol structure members names. static QHash m_nbFuncs; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 4ff3e8408..5d8685b90 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -860,7 +860,7 @@ QString ShibokenGenerator::converterObject(const AbstractMetaType *type) + QLatin1String(">(") + QString::number(nestedArrayTypes.size()) + QLatin1Char(')'); } - if (type->typeEntry()->isContainer()) { + if (type->typeEntry()->isContainer() || type->typeEntry()->isSmartPointer()) { return convertersVariableName(type->typeEntry()->targetLangPackage()) + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']'); } diff --git a/sources/shiboken2/tests/smartbinding/smart_pointer_test.py b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py index 50b2120a2..d7ddf963c 100644 --- a/sources/shiboken2/tests/smartbinding/smart_pointer_test.py +++ b/sources/shiboken2/tests/smartbinding/smart_pointer_test.py @@ -214,6 +214,19 @@ class SmartPointerTests(unittest.TestCase): except AttributeError as error: self.assertEqual(error.args[0], "'smart.SharedPtr_Obj' object has no attribute 'typo'") + def testSmartPointerConversions(self): + # Create Obj. + o = Obj() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 1) + + # Create a shared pointer to an Integer2 + integer2 = o.giveSharedPtrToInteger2() + self.assertEqual(integer2.value(), 456) + + # pass Smart to a function that accepts Smart + r = o.takeSharedPtrToInteger(integer2) + self.assertEqual(r, integer2.value()) if __name__ == '__main__': unittest.main() -- cgit v1.2.3