diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-04-04 14:07:10 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-04-05 14:45:06 +0200 |
commit | c7d0c7c5ce00a37461908dd9329aa563cd146b1e (patch) | |
tree | 739b86ef81a884121cd5a6a765db5f3412e62d2b | |
parent | 5f836597140d2ae82f235d69561cc7f426e2d7af (diff) |
shiboken6: Add attribute "value-check-method" to smart pointers
"value-check-method" (operator bool, std::optional::has_value()), is
the opposite of the existing "null-check-method"
(QSharedPointer::isNull()) and takes precedence over it. Synthesize
these methods for smart pointers as well.
As a drive-by, actually generate the value check and null check methods.
Add a test for std::shared_ptr.
Task-number: PYSIDE-454
Change-Id: Ie3b6f7042883888d23c9e6bed8a1409f0bdb56b9
Reviewed-by: Christian Tismer <tismer@stackless.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
10 files changed, 96 insertions, 23 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index 84bbc4d9e..4853b0120 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -2243,33 +2243,55 @@ const AbstractMetaClass *AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(co // internal, compiler-dependent STL implementation headers might not be exposed // to the parser unless those headers are specified as <system-include>. +static AbstractMetaFunctionPtr + addMethod(AbstractMetaClass *s, const AbstractMetaType &returnType, + const QString &name, bool isConst = true) +{ + AbstractMetaFunctionPtr function(new AbstractMetaFunction(name)); + function->setType(returnType); + s->addFunction(function); + function->setConstant(isConst); + qCWarning(lcShiboken, "Synthesizing \"%s\"...", + qPrintable(function->classQualifiedSignature())); + return function; +} + +static AbstractMetaFunctionPtr + addMethod(AbstractMetaClass *s, const QString &returnTypeName, + const QString &name, bool isConst = true) +{ + auto *typeEntry = TypeDatabase::instance()->findPrimitiveType(returnTypeName); + Q_ASSERT(typeEntry); + AbstractMetaType returnType(typeEntry); + returnType.decideUsagePattern(); + return addMethod(s, returnType, name, isConst); +} + // Add the relevant missing smart pointer functions. static void fixSmartPointerClass(AbstractMetaClass *s, const SmartPointerTypeEntry *ste) { const QString getterName = ste->getter(); if (s->findFunction(getterName).isNull()) { - AbstractMetaFunctionPtr getter(new AbstractMetaFunction(getterName)); AbstractMetaType type(s->templateArguments().constFirst()); type.addIndirection(); type.decideUsagePattern(); - getter->setType(type); - s->addFunction(getter); - qCWarning(lcShiboken, "Synthesizing \"%s\"...", - qPrintable(getter->classQualifiedSignature())); + addMethod(s, type, getterName); } const QString refCountName = ste->refCountMethodName(); - if (!refCountName.isEmpty() && s->findFunction(refCountName).isNull()) { - AbstractMetaFunctionPtr refCount(new AbstractMetaFunction(refCountName)); - auto *intTypeEntry = TypeDatabase::instance()->findPrimitiveType(u"int"_qs); - Q_ASSERT(intTypeEntry); - AbstractMetaType intType(intTypeEntry); - intType.decideUsagePattern(); - refCount->setType(intType); - s->addFunction(refCount); - qCWarning(lcShiboken, "Synthesizing \"%s\"...", - qPrintable(refCount->classQualifiedSignature())); + if (!refCountName.isEmpty() && s->findFunction(refCountName).isNull()) + addMethod(s, u"int"_qs, refCountName); + + const QString valueCheckMethod = ste->valueCheckMethod(); + if (!valueCheckMethod.isEmpty() && s->findFunction(valueCheckMethod).isNull()) { + auto f = addMethod(s, u"bool"_qs, valueCheckMethod); + if (valueCheckMethod == u"operator bool") + f->setFunctionType(AbstractMetaFunction::ConversionOperator); } + + const QString nullCheckMethod = ste->nullCheckMethod(); + if (!nullCheckMethod.isEmpty() && s->findFunction(nullCheckMethod).isNull()) + addMethod(s, u"bool"_qs, nullCheckMethod); } // Create a missing smart pointer class diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index c074df785..8898a3cf9 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -677,10 +677,10 @@ QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntry *te) + te->name() + u"\" not found."_qs; } -QString msgCannotFindSmartPointerRefCount(const SmartPointerTypeEntry *te) +QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntry *te, const QString &m) { - return u"Ref count method \""_qs + te->refCountMethodName() - + u"()\" of smart pointer \""_qs + te->name() + u"\" not found."_qs; + return u"Method \""_qs + m + u"()\" of smart pointer \""_qs + + te->name() + u"\" not found."_qs; } QString msgMethodNotFound(const AbstractMetaClass *klass, const QString &name) diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index cdce6788c..45ed3540c 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -207,7 +207,7 @@ QString msgConversionTypesDiffer(const QString &varType, const QString &conversi QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntry *); -QString msgCannotFindSmartPointerRefCount(const SmartPointerTypeEntry *); +QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntry *te, const QString &m); QString msgMethodNotFound(const AbstractMetaClass *klass, const QString &name); diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 21314449e..452fb92aa 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -1741,6 +1741,7 @@ public: QString m_getterName; QString m_smartPointerType; QString m_refCountMethodName; + QString m_valueCheckMethod; QString m_nullCheckMethod; QString m_resetMethod; SmartPointerTypeEntry::Instantiations m_instantiations; @@ -1768,6 +1769,18 @@ QString SmartPointerTypeEntry::refCountMethodName() const return d->m_refCountMethodName; } +QString SmartPointerTypeEntry::valueCheckMethod() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_valueCheckMethod; +} + +void SmartPointerTypeEntry::setValueCheckMethod(const QString &m) +{ + S_D(SmartPointerTypeEntry); + d->m_valueCheckMethod = m; +} + QString SmartPointerTypeEntry::nullCheckMethod() const { S_D(const SmartPointerTypeEntry); diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h index d0894dac1..f1499e612 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.h +++ b/sources/shiboken6/ApiExtractor/typesystem.h @@ -722,6 +722,8 @@ public: QString refCountMethodName() const; + QString valueCheckMethod() const; + void setValueCheckMethod(const QString &); QString nullCheckMethod() const; void setNullCheckMethod(const QString &); QString resetMethod() const; diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index 49cd0970a..4a615420e 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -1366,6 +1366,7 @@ SmartPointerTypeEntry * QString smartPointerType; QString getter; QString refCountMethodName; + QString valueCheckMethod; QString nullCheckMethod; QString resetMethod; QString instantiations; @@ -1379,6 +1380,8 @@ SmartPointerTypeEntry * refCountMethodName = attributes->takeAt(i).value().toString(); } else if (name == QLatin1String("instantiations")) { instantiations = attributes->takeAt(i).value().toString(); + } else if (name == u"value-check-method") { + valueCheckMethod = attributes->takeAt(i).value().toString(); } else if (name == u"null-check-method") { nullCheckMethod = attributes->takeAt(i).value().toString(); } else if (name == u"reset-method") { @@ -1420,6 +1423,7 @@ SmartPointerTypeEntry * return nullptr; applyComplexTypeAttributes(reader, type, attributes); type->setNullCheckMethod(nullCheckMethod); + type->setValueCheckMethod(valueCheckMethod); type->setResetMethod(resetMethod); m_smartPointerInstantiations.insert(type, instantiations); return type; diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index ea308554a..e4e9d8bc2 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -577,11 +577,16 @@ smart-pointer-type type="..." getter="..." ref-count-method="..." + value-check-method="..." null-check-method="..." reset-method="..." instantiations="..."/> </typesystem> + + The *optional* attribute **value-check-method** specifies a method + that can be used to check whether the pointer has a value. + The *optional* attribute **null-check-method** specifies a method that can be used to check for ``nullptr``. diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index ee3bfb542..eeefae010 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -292,6 +292,15 @@ CppGenerator::BoolCastFunctionOptional const auto *te = metaClass->typeEntry(); if (te->isSmartPointer()) { auto *ste = static_cast<const SmartPointerTypeEntry *>(te); + + auto valueCheckMethod = ste->valueCheckMethod(); + if (!valueCheckMethod.isEmpty()) { + const auto func = metaClass->findFunction(valueCheckMethod); + if (func.isNull()) + throw Exception(msgMethodNotFound(metaClass, valueCheckMethod)); + return BoolCastFunction{func, false}; + } + auto nullCheckMethod = ste->nullCheckMethod(); if (!nullCheckMethod.isEmpty()) { const auto func = metaClass->findFunction(nullCheckMethod); @@ -848,11 +857,19 @@ void CppGenerator::generateSmartPointerClass(TextStream &s, const GeneratorConte writeMethodWrapper(s, md, signatureStream, {getter}, classContext); } - const QString refCountMethodName = typeEntry->refCountMethodName(); - if (!refCountMethodName.isEmpty()) { // optional - auto it = functionGroups.constFind(refCountMethodName); + QStringList optionalMethods; + if (!typeEntry->refCountMethodName().isEmpty()) + optionalMethods.append(typeEntry->refCountMethodName()); + const QString valueCheckMethod = typeEntry->valueCheckMethod(); + if (!valueCheckMethod.isEmpty() && !valueCheckMethod.startsWith(u"operator")) + optionalMethods.append(valueCheckMethod); + if (!typeEntry->nullCheckMethod().isEmpty()) + optionalMethods.append(typeEntry->nullCheckMethod()); + + for (const QString &optionalMethod : optionalMethods) { + auto it = functionGroups.constFind(optionalMethod); if (it == functionGroups.cend() || it.value().size() != 1) - throw Exception(msgCannotFindSmartPointerRefCount(typeEntry)); + throw Exception(msgCannotFindSmartPointerMethod(typeEntry, optionalMethod)); writeMethodWrapper(s, md, signatureStream, it.value(), classContext); } diff --git a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py index 1b96569a7..4617f8932 100644 --- a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py +++ b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py @@ -41,12 +41,21 @@ init_paths() from smart import StdSharedPtrTestBench +def call_func_on_ptr(ptr): + ptr.printInteger() + + class StdSharedPtrTests(unittest.TestCase): def testIt(self): p = StdSharedPtrTestBench.createInteger() StdSharedPtrTestBench.printInteger(p) + self.assertTrue(p) + call_func_on_ptr(p) + np = StdSharedPtrTestBench.createNullInteger() StdSharedPtrTestBench.printInteger(np) + self.assertFalse(np) + self.assertRaises(AttributeError, call_func_on_ptr, np) if __name__ == '__main__': diff --git a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml index 8a68bb18d..2bbb1f56a 100644 --- a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml +++ b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml @@ -45,6 +45,7 @@ <modify-function signature="^.*$" remove="all"/> <enum-type name="pointer_safety"/> <smart-pointer-type name="shared_ptr" type="shared" getter="get" + value-check-method="operator bool" ref-count-method="use_count" instantiations="Integer"> <include file-name="memory" location="global"/> |