diff options
Diffstat (limited to 'sources/shiboken6')
32 files changed, 356 insertions, 149 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index 27570ec4f..fb5399baa 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -2664,7 +2664,7 @@ std::optional<AbstractMetaType> qsizetype i = d ? d->m_scopes.size() - 1 : -1; while (i >= 0) { typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--)); - if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s)) + if (typeInfo.qualifiedName() != _typei.qualifiedName()) break; } @@ -2757,12 +2757,22 @@ std::optional<AbstractMetaType> // 4. Special case QFlags (include instantiation in name) if (qualifiedName == u"QFlags") { - qualifiedName = typeInfo.toString(); + qualifiedName = typeInfo.qualifiedInstantationName(); typeInfo.clearInstantiations(); } TypeEntryCList types = findTypeEntries(qualifiedName, name, flags, currentClass, d, errorMessageIn); + if (types.isEmpty() && !typeInfo.instantiations().isEmpty()) { + // Allow for specifying template specializations as primitive types + // with converters ('std::optional<int>' or similar). + auto pt = TypeDatabase::instance()->findPrimitiveType(typeInfo.qualifiedInstantationName()); + if (pt) { + types.append(pt); + typeInfo.clearInstantiations(); + } + } + if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) { // Avoid clashes between QByteArray and enum value QMetaType::QByteArray // unless we are looking for template arguments. @@ -2796,7 +2806,7 @@ std::optional<AbstractMetaType> // For non-type template parameters, create a dummy type entry on the fly // as is done for classes. if (!targType.has_value()) { - const QString value = ti.qualifiedName().join(u"::"_s); + const QString value = ti.qualifiedNameString(); if (isNumber(value)) { auto module = typeSystemTypeEntry(type); TypeDatabase::instance()->addConstantValueTypeEntry(value, module); @@ -3082,7 +3092,7 @@ AbstractMetaClassPtr QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString(); QString completeName = prefix + name; const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage); - QString qualifiedName = parsed.qualifiedName().join(u"::"_s); + QString qualifiedName = parsed.qualifiedNameString(); if (qualifiedName.isEmpty()) { qWarning().noquote().nospace() << "Unable to parse type \"" << completeName << "\" while looking for template \"" << name << "\": " << errorMessage; @@ -3196,7 +3206,7 @@ static std::optional<AbstractMetaType> const AbstractMetaClassCPtr &templateClass, const TypeInfo &info, QString *errorMessage) { - QString typeName = info.qualifiedName().join("::"_L1); + QString typeName = info.qualifiedNameString(); TypeDatabase *typeDb = TypeDatabase::instance(); TypeEntryPtr t; // Check for a non-type template integer parameter, that is, for a base diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp index 90f4f5dd9..38dedfd14 100644 --- a/sources/shiboken6/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp @@ -370,6 +370,7 @@ bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags) bool addCompilerSupportArguments = true; if (clangOptionsSize > 0) { + clang::setTargetTriple(m_clangOptions); qsizetype i = 0; if (m_clangOptions.at(i) == u"-") { ++i; diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp index 54a1a2c8b..747937ede 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp @@ -275,6 +275,24 @@ static CXTranslationUnit createTranslationUnit(CXIndex index, return tu; } +static void setupTarget(CXTranslationUnit translationUnit) +{ + const CXTargetInfo targetInfo = clang_getTranslationUnitTargetInfo(translationUnit); + const auto tripleCS = clang_TargetInfo_getTriple(targetInfo); + clang::setPointerSize(clang_TargetInfo_getPointerWidth(targetInfo)); + clang::setTargetTriple(QString::fromUtf8(clang_getCString(tripleCS))); + clang_disposeString(tripleCS); + + QString message; + { + QTextStream str(&message); + str << "CLANG v" << CINDEX_VERSION_MAJOR << '.' << CINDEX_VERSION_MINOR + << " targeting \"" << targetTriple() << "\", " << pointerSize() << "bit."; + } + qCInfo(lcShiboken, "%s", qPrintable(message)); + ReportHandler::addGeneralMessage(message + u'\n'); +} + /* clangFlags are flags to clang_parseTranslationUnit2() such as * CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35) */ @@ -295,6 +313,8 @@ bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments, if (!translationUnit) return false; + setupTarget(translationUnit); + CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit); clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv)); diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp index ed8057b62..4d93a084f 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp @@ -59,6 +59,9 @@ bool setCompiler(const QString &name) QString _compilerPath; // Pre-defined compiler path (from command line) +static unsigned _pointerSize = QT_POINTER_SIZE * 8; +static QString _targetTriple; + const QString &compilerPath() { return _compilerPath; @@ -153,14 +156,15 @@ static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths) if (homebrewPrefix.isEmpty()) return; - qCInfo(lcShiboken) << "Found HOMEBREW_OPT with value:" << homebrewPrefix - << "Assuming homebrew build environment."; + ReportHandler::addGeneralMessage("Found HOMEBREW_OPT with value:"_L1 + + QString::fromUtf8(homebrewPrefix) + + "\nAssuming homebrew build environment."_L1); HeaderPaths::iterator it = headerPaths.begin(); while (it != headerPaths.end()) { if (it->path.startsWith(homebrewPrefix)) { - qCInfo(lcShiboken) << "Filtering out homebrew include path: " - << it->path; + ReportHandler::addGeneralMessage("Filtering out homebrew include path: "_L1 + + QString::fromUtf8(it->path)); it = headerPaths.erase(it); } else { ++it; @@ -186,12 +190,6 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler) const QByteArrayList stdErrLines = stdErr.split('\n'); bool isIncludeDir = false; - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCInfo(lcShiboken()).noquote().nospace() - << "gppInternalIncludePaths:\n compiler: " << compiler - << "\n stdOut: " << stdOut - << "\n stdErr: " << stdErr; - for (const QByteArray &line : stdErrLines) { if (isIncludeDir) { if (line.startsWith(QByteArrayLiteral("End of search list"))) { @@ -212,6 +210,17 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler) if (platform() == Platform::macOS) filterHomebrewHeaderPaths(result); + QString message; + { + QTextStream str(&message); + str << "gppInternalIncludePaths:\n compiler: " << compiler << '\n'; + for (const auto &h : result) + str << " " << h.path << '\n'; + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + str << " stdOut: " << stdOut << "\n stdErr: " << stdErr; + } + ReportHandler::addGeneralMessage(message); + return result; } @@ -365,11 +374,10 @@ static void appendClangBuiltinIncludes(HeaderPaths *p) "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR " " nor running llvm-config). This may lead to parse errors."); } else { - qCInfo(lcShiboken, "CLANG v%d.%d, builtins includes directory: %s", - CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR, - qPrintable(clangBuiltinIncludesDir)); p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), HeaderType::System}); + ReportHandler::addGeneralMessage("CLANG builtins includes directory: "_L1 + + clangBuiltinIncludesDir); } } @@ -451,4 +459,33 @@ LanguageLevel languageLevelFromOption(const char *o) return LanguageLevel::Default; } +unsigned pointerSize() +{ + return _pointerSize; +} + +void setPointerSize(unsigned ps) +{ + _pointerSize = ps; +} + +QString targetTriple() +{ + return _targetTriple; + +} +void setTargetTriple(const QString &t) +{ + _targetTriple = t; +} + +void setTargetTriple(const QStringList &clangOptions) +{ + static constexpr auto targetOption = "--target="_L1; + auto targetOptionPred = [](const QString &o) { return o.startsWith(targetOption); }; + const auto it = std::find_if(clangOptions.cbegin(), clangOptions.cend(), targetOptionPred); + if (it != clangOptions.cend()) + _targetTriple = it->sliced(targetOption.size()); +} + } // namespace clang diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h index 1fa980998..0e12ca137 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h @@ -51,6 +51,14 @@ void setCompilerPath(const QString &name); Platform platform(); bool setPlatform(const QString &name); + +unsigned pointerSize(); // (bit) +void setPointerSize(unsigned ps); // Set by parser + +QString targetTriple(); +void setTargetTriple(const QStringList &clangOptions); // Set from cmd line before parsing +void setTargetTriple(const QString &t); // Updated by clang parser while parsing + } // namespace clang #endif // COMPILERSUPPORT_H diff --git a/sources/shiboken6/ApiExtractor/customconversion.cpp b/sources/shiboken6/ApiExtractor/customconversion.cpp index 4cfd1b974..7b65bcf3a 100644 --- a/sources/shiboken6/ApiExtractor/customconversion.cpp +++ b/sources/shiboken6/ApiExtractor/customconversion.cpp @@ -5,6 +5,7 @@ #include "containertypeentry.h" #include "customtypenentry.h" #include "primitivetypeentry.h" +#include "smartpointertypeentry.h" #include "valuetypeentry.h" #include <QtCore/qdebug.h> @@ -139,6 +140,8 @@ CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntryCPtr &t return std::static_pointer_cast<const ContainerTypeEntry>(type)->customConversion(); if (type->isValue()) return std::static_pointer_cast<const ValueTypeEntry>(type)->customConversion(); + if (type->isSmartPointer()) + return std::static_pointer_cast<const SmartPointerTypeEntry>(type)->customConversion(); return {}; } diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp index 845a0f916..93627e6d5 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp @@ -110,6 +110,28 @@ QStringList TypeInfo::qualifiedName() const return d->m_qualifiedName; } +QString TypeInfo::qualifiedNameString() const +{ + return d->m_qualifiedName.join("::"_L1); +} + +QString TypeInfo::qualifiedInstantationName() const +{ + QString result = qualifiedNameString(); + if (const auto instantiationCount = d->m_instantiations.size()) { + result += u'<'; + for (qsizetype i = 0; i < instantiationCount; ++i) { + if (i) + result += ", "_L1; + result += d->m_instantiations.at(i).toString(); + } + if (result.endsWith(u'>')) + result += u' '; + result += u'>'; + } + return result; +} + void TypeInfo::setQualifiedName(const QStringList &qualified_name) { if (d->m_qualifiedName != qualified_name) @@ -300,7 +322,7 @@ TypeInfo TypeInfo::resolveType(const CodeModelItem &__item, TypeInfo const &__ty // typedef struct xcb_connection_t xcb_connection_t; if (nextItem.get() ==__item.get()) { std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__ - << "() on " << qPrintable(__type.qualifiedName().join(u"::"_s)) + << "() on " << qPrintable(__type.qualifiedNameString()) << '\n'; return otherType; } @@ -385,19 +407,7 @@ QString TypeInfo::toString() const if (isVolatile()) tmp += u"volatile "_s; - tmp += d->m_qualifiedName.join(u"::"_s); - - if (const auto instantiationCount = d->m_instantiations.size()) { - tmp += u'<'; - for (qsizetype i = 0; i < instantiationCount; ++i) { - if (i) - tmp += u", "_s; - tmp += d->m_instantiations.at(i).toString(); - } - if (tmp.endsWith(u'>')) - tmp += u' '; - tmp += u'>'; - } + tmp += qualifiedInstantationName(); for (Indirection i : d->m_indirections) tmp.append(indirectionKeyword(i)); diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h index 9cd746e85..6f75b5737 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.h +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h @@ -39,6 +39,11 @@ public: QStringList qualifiedName() const; void setQualifiedName(const QStringList &qualified_name); + // Returns "std::list" + QString qualifiedNameString() const; + // Returns qualifiedName() with instantions ("std::list<int>") + QString qualifiedInstantationName() const; + void addName(const QString &); bool isVoid() const; diff --git a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h index d704210f7..7b67647b9 100644 --- a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h +++ b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h @@ -5,6 +5,7 @@ #define SMARTPOINTERTYPEENTRY_H #include "complextypeentry.h" +#include "customconversion_typedefs.h" class SmartPointerTypeEntryPrivate; @@ -51,6 +52,10 @@ public: QString getTargetName(const AbstractMetaType &metaType) const; + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 0820150f8..46e88291d 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -2154,6 +2154,7 @@ public: QString m_resetMethod; SmartPointerTypeEntry::Instantiations m_instantiations; TypeEntryCList m_excludedInstantiations; + CustomConversionPtr m_customConversion; TypeSystem::SmartPointerType m_smartPointerType; }; @@ -2306,6 +2307,24 @@ QString SmartPointerTypeEntry::getTargetName(const AbstractMetaType &metaType) c return fixSmartPointerName(name); } +bool SmartPointerTypeEntry::hasCustomConversion() const +{ + S_D(const SmartPointerTypeEntry); + return bool(d->m_customConversion); +} + +void SmartPointerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(SmartPointerTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr SmartPointerTypeEntry::customConversion() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_customConversion; +} + // ----------------- NamespaceTypeEntry class NamespaceTypeEntryPrivate : public ComplexTypeEntryPrivate { diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index 8b2ad08de..7ae25e48c 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -2348,9 +2348,10 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, if (topElement != StackElement::ModifyArgument && topElement != StackElement::ValueTypeEntry && topElement != StackElement::PrimitiveTypeEntry - && topElement != StackElement::ContainerTypeEntry) { + && topElement != StackElement::ContainerTypeEntry + && topElement != StackElement::SmartPointerTypeEntry) { m_error = u"Conversion rules can only be specified for argument modification, " - "value-type, primitive-type or container-type conversion."_s; + "value-type, primitive-type, or container-type or smartpointer-type conversion."_s; return false; } @@ -2415,6 +2416,9 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion); else if (top->entry->isValue()) std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isSmartPointer()) + std::static_pointer_cast<SmartPointerTypeEntry>(top->entry)->setCustomConversion(customConversion); + customConversionsForReview.append(customConversion); return true; } diff --git a/sources/shiboken6/cmake/ShibokenHelpers.cmake b/sources/shiboken6/cmake/ShibokenHelpers.cmake index bcaf31e89..c6414b2ca 100644 --- a/sources/shiboken6/cmake/ShibokenHelpers.cmake +++ b/sources/shiboken6/cmake/ShibokenHelpers.cmake @@ -869,28 +869,9 @@ endfunction() # Get path to libclang.dll/libclang.so depending on the platform macro(find_libclang) - if(CMAKE_HOST_WIN32) - set(libclang_directory_suffix "bin") - set(libclang_suffix ".dll") - else() - set(libclang_directory_suffix "lib") - if(CMAKE_HOST_APPLE) - set(libclang_suffix ".dylib") - else() - set(libclang_suffix ".so") - endif() - endif() - - set(libclang_lib_dir "") - if(DEFINED ENV{LLVM_INSTALL_DIR}) - set(libclang_lib_dir "$ENV{LLVM_INSTALL_DIR}/${libclang_directory_suffix}") - elseif(DEFINED ENV{CLANG_INSTALL_DIR}) - set(libclang_lib_dir "$ENV{CLANG_INSTALL_DIR}/${libclang_directory_suffix}") - else() - message(WARNING - "Couldn't find libclang${libclang_suffix} " - "You will likely need to add it manually to PATH to ensure the build succeeds.") - endif() + find_package(Clang CONFIG REQUIRED) + get_target_property(libclang_location libclang LOCATION) + get_filename_component(libclang_lib_dir "${libclang_location}" DIRECTORY) endmacro() # Allow setting a shiboken debug level from the the build system or from the environment diff --git a/sources/shiboken6/doc/typesystem_conversionrule.rst b/sources/shiboken6/doc/typesystem_conversionrule.rst index cee45bfb3..f6ce18345 100644 --- a/sources/shiboken6/doc/typesystem_conversionrule.rst +++ b/sources/shiboken6/doc/typesystem_conversionrule.rst @@ -12,9 +12,13 @@ The **conversion-rule** tag specifies how a **primitive-type**, a **container-ty or a **value-type** may be converted to and from the native C++ language types to the target language types (see also :ref:`user-defined-type-conversion`). -It is a child of the :ref:`container-type`, :ref:`primitive-type` or -:ref:`value-type` and may contain :ref:`native-to-target` or -:ref:`native-to-target` child nodes. +It may be a child of the :ref:`container-type` and :ref:`primitive-type` nodes, +where conversions have to be provided for both directions using the +:ref:`native-to-target` and :ref:`target-to-native` child nodes. + +It may also appear as a child of :ref:`value-type` or :ref:`smart-pointer-type` +where additional conversions from other target language types can be provided +using the :ref:`target-to-native` child node. .. code-block:: xml @@ -70,8 +74,9 @@ an input value an does what's needed to convert it to the output value. </conversion-rule> Use the replace node to modify the template code. -Notice that the generator must provide type system variables for the input -and output values and types, namely **%in**, **%out**, **%INTYPE** and +Notice that the generator provides type system variables for the input +and output values and types (see :ref:`converter_variables_and_functions`). +The most important ones are **%in**, **%out**, **%INTYPE** and **%OUTTYPE**. In the case of container types, **%INTYPE** refers to the full container type (e.g. **"list<int>"**) and **%INTYPE_0**, **%INTYPE_1**, **%INTYPE_#**, should be replaced by the types used in the container template diff --git a/sources/shiboken6/doc/typesystem_converters.rst b/sources/shiboken6/doc/typesystem_converters.rst index ab6fba930..f34f5b829 100644 --- a/sources/shiboken6/doc/typesystem_converters.rst +++ b/sources/shiboken6/doc/typesystem_converters.rst @@ -16,7 +16,8 @@ C++ and vice-versa. // C++ class struct Complex { - Complex(double real, double imag); + explicit Complex(double real, double imag); + double real() const; double imag() const; }; @@ -82,8 +83,9 @@ Here's how to do it: <!-- Code injection at module level. --> <inject-code class="native" position="beginning"> - static bool Check2TupleOfNumbers(PyObject* pyIn) { - if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) + static bool Check2TupleOfNumbers(PyObject *pyIn) + { + if (PySequence_Check(pyIn) == 0 || PySequence_Size(pyIn) != 2) return false; Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); if (!PyNumber_Check(pyReal)) @@ -134,7 +136,8 @@ Container Conversions Converters for :ref:`container-type <container-type>` are pretty much the same as for other type, except that they make use of the type system variables -:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>`. +:ref:`%INTYPE_# <intype_n>` and :ref:`%OUTTYPE_# <outtype_n>` denoting the +template parameters. |project| combines the conversion code for containers with the conversion defined (or automatically generated) for the containers. @@ -147,13 +150,12 @@ defined (or automatically generated) for the containers. <native-to-target> PyObject* %out = PyDict_New(); - %INTYPE::const_iterator it = %in.begin(); - for (; it != %in.end(); ++it) { - %INTYPE_0 key = it->first; - %INTYPE_1 value = it->second; - PyDict_SetItem(%out, + for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) { + const auto &key = it->first; + const auto &value = it->second; + PyDict_SetItem(%out, %CONVERTTOPYTHON[%INTYPE_0](key), - %CONVERTTOPYTHON[%INTYPE_1](value)); + %CONVERTTOPYTHON[%INTYPE_1](value)); } return %out; </native-to-target> @@ -161,8 +163,8 @@ defined (or automatically generated) for the containers. <target-to-native> <add-conversion type="PyDict"> - PyObject* key; - PyObject* value; + PyObject *key{}; + PyObject *value{}; Py_ssize_t pos = 0; while (PyDict_Next(%in, &pos, &key, &value)) { %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); @@ -183,10 +185,10 @@ defined (or automatically generated) for the containers. For this case, a number of pre-defined conversion templates are provided (see :ref:`predefined_templates`). -.. _variables_and_functions: +.. _converter_variables_and_functions: -Variables & Functions -===================== +Converter Variables & Functions +=============================== .. _in: @@ -212,7 +214,7 @@ Variables & Functions .. _intype_n: **%INTYPE_#** - Replaced by the name of the #th type used in a container. + Replaced by the name of the #th template parameter type used in a container. .. _outtype: @@ -225,7 +227,7 @@ Variables & Functions .. _outtype_n: **%OUTTYPE_#** - Replaced by the name of the #th type used in a container. + Replaced by the name of the #th template parameter type used in a container. .. _checktype: diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index c03d203b9..798ef5719 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -208,6 +208,9 @@ can be generated for them. Instead, an instance of the viewed class should be instantiated and passed to functions using the view class for argument types. +It is also possible to specify template specializations +like "std::optional<int>" as primitive types with converters. + See :ref:`predefined_templates` for built-in templates for standard type conversion rules. @@ -726,7 +729,8 @@ The ``smart pointer`` type node indicates that the given class is a smart pointe and requires inserting calls to **getter** to access the pointeee. Currently, the usage is limited to function return values. **ref-count-method** specifies the name of the method used to do reference counting. -It is a child of the :ref:`typesystem_details` node or other type nodes. +It is a child of the :ref:`typesystem_details` node or other type nodes +and may contain :ref:`conversion-rule` nodes. The *optional* attribute **instantiations** specifies for which instantiations of the smart pointer wrappers will be generated (comma-separated list). diff --git a/sources/shiboken6/doc/typesystem_variables.rst b/sources/shiboken6/doc/typesystem_variables.rst index 5eb5d5abe..6dfd1f801 100644 --- a/sources/shiboken6/doc/typesystem_variables.rst +++ b/sources/shiboken6/doc/typesystem_variables.rst @@ -16,6 +16,8 @@ implementation specifics. Variables ========= +In addition to the below listed variables, there are some variables specific to type +conversion code (see :ref:`converter_variables_and_functions`). .. _cpp_return_argument: diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 21e167b53..9092768a3 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -997,7 +997,7 @@ void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext & { s << "void " << classContext.wrapperName() << "::resetPyMethodCache()\n{\n" << indent - << "std::fill_n(m_PyMethodCache, sizeof(m_PyMethodCache) / sizeof(m_PyMethodCache[0]), false);\n" + << "std::fill(m_PyMethodCache.begin(), m_PyMethodCache.end(), nullptr);\n" << outdent << "}\n\n"; } @@ -2120,6 +2120,24 @@ void CppGenerator::writeCustomConverterRegister(TextStream &s, } } +void CppGenerator::writeTemplateCustomConverterRegister(TextStream &s, + const AbstractMetaType &type, + QString converter) +{ + auto customConversion = CustomConversion::getCustomConversion(type.typeEntry()); + if (!customConversion || customConversion->targetToNativeConversions().isEmpty()) + return; + if (converter.isEmpty()) + converter = converterVar; + const QString typeName = fixedCppTypeName(type); + for (const auto &conv : customConversion->targetToNativeConversions()) { + const QString &sourceTypeName = conv.sourceTypeName(); + QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName); + QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName); + writeAddPythonToCppConversion(s, converter, toCpp, isConv); + } +} + void CppGenerator::writeContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType) const { @@ -3600,13 +3618,15 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck); } -void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const +void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, + const AbstractMetaType &templateType) const { - Q_ASSERT(containerType.typeEntry()->isContainer()); - const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry()); - const auto customConversion = cte->customConversion(); - for (const auto &conv : customConversion->targetToNativeConversions()) - writePythonToCppConversionFunction(s, containerType, conv); + const auto customConversion = CustomConversion::getCustomConversion(templateType.typeEntry()); + if (customConversion) { + const auto &conversions = customConversion->targetToNativeConversions(); + for (const auto &conv : conversions) + writePythonToCppConversionFunction(s, templateType, conv); + } } void CppGenerator::writePythonToCppConversionFunction(TextStream &s, @@ -4438,8 +4458,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s, s << '&' << targetTypeName << "_Type"; } - const QString typeName = fixedCppTypeName(type); - s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n"; + s << ", " << cppToPythonFunctionName(fixedCppTypeName(type), targetTypeName) << ");\n"; s << registerConverterName(cppSignature, converter); if (usePySideExtensions() && cppSignature.startsWith("const "_L1) @@ -4448,12 +4467,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s, s << registerConverterName(underlyingType, converter); } - for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) { - const QString &sourceTypeName = conv.sourceTypeName(); - QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName); - QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName); - writeAddPythonToCppConversion(s, converter, toCpp, isConv); - } + writeTemplateCustomConverterRegister(s, type, converter); auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature()); if (typedefItPair.first != typedefItPair.second) { diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 0cf204234..441a9f781 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -114,6 +114,9 @@ private: static void writeCustomConverterRegister(TextStream &s, const CustomConversionPtr &customConversion, const QString &converterVar); + static void writeTemplateCustomConverterRegister(TextStream &s, + const AbstractMetaType &type, + QString converter = {}); void writeContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType) const; @@ -361,9 +364,10 @@ private: const TargetToNativeConversion &toNative, const TypeEntryCPtr &targetType) const; - /// Writes a pair of Python to C++ conversion and check functions for instantiated container types. + /// Writes a pair of Python to C++ conversion and check functions for instantiated + /// template (smart pointer/container types). void writePythonToCppConversionFunctions(TextStream &s, - const AbstractMetaType &containerType) const; + const AbstractMetaType &templateType) const; void writePythonToCppConversionFunction(TextStream &s, const AbstractMetaType &containerType, diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp index 48c4ed5d2..1d3280e36 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp @@ -232,13 +232,16 @@ void CppGenerator::generateSmartPointerClass(TextStream &s, void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s, const AbstractMetaType &smartPointerType) const { + auto smartPointerTypeEntry = + std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry()); + + if (smartPointerTypeEntry->hasCustomConversion()) + writePythonToCppConversionFunctions(s, smartPointerType); + const auto baseClasses = findSmartPointeeBaseClasses(api(), smartPointerType); if (baseClasses.isEmpty()) return; - auto smartPointerTypeEntry = - std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry()); - // TODO: Missing conversion to smart pointer pointer type: s << "// Register smartpointer conversion for all derived classes\n"; @@ -290,6 +293,8 @@ void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s, writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv); }; + writeTemplateCustomConverterRegister(s, type); + const auto classes = findSmartPointeeBaseClasses(api(), type); if (classes.isEmpty()) return; diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp index 965d80dad..7616fa5c3 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.cpp +++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp @@ -185,6 +185,7 @@ void HeaderGenerator::writeWrapperClass(TextStream &s, for( const auto &includeGroup : includeGroups) s << includeGroup; } + s << "#include <sbkpython.h>\n\n#include <array>\n"; s << "namespace Shiboken { class AutoDecRef; class GilState; }\n\n"; @@ -288,9 +289,10 @@ void *qt_metacast(const char *_clname) override; } if (needsMethodCache) { - s << "mutable bool m_PyMethodCache[" << maxOverrides << "] = {false"; + s << "mutable std::array<PyObject *, " << maxOverrides + << "> m_PyMethodCache = {nullptr"; for (int i = 1; i < maxOverrides; ++i) - s << ", false"; + s << ", nullptr"; s << "};\n"; } diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index 3e26b4605..039cd3085 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -21,6 +21,7 @@ #include "voidptr.h" #include <algorithm> +#include <cctype> #include <cstddef> #include <cstring> #include <iostream> @@ -786,32 +787,57 @@ static PyObject *overrideMethodName(PyObject *pySelf, const char *methodName, // The virtual function call PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject, Shiboken::GilState &gil, const char *funcName, - bool &resultCache, PyObject **nameCache) -{ - PyObject *pyOverride{}; - if (!resultCache) { - gil.acquire(); - auto &bindingManager = Shiboken::BindingManager::instance(); - SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject); - // The refcount can be 0 if the object is dieing and someone called - // a virtual method from the destructor - if (wrapper == nullptr) - return nullptr; - auto *pySelf = reinterpret_cast<PyObject *>(wrapper); - if (Py_REFCNT(pySelf) == 0) - return nullptr; - PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache); - pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName); - if (pyOverride == nullptr) { - resultCache = true; - gil.release(); - } else if (Shiboken::Errors::occurred() != nullptr) { - // Give up. - Py_XDECREF(pyOverride); - pyOverride = nullptr; - } + PyObject *&resultCache, PyObject **nameCache) +{ + if (Py_IsInitialized() == 0 || resultCache == Py_None) + return nullptr; // Bail out, execute C++ call (wrappers may outlive Python). + + auto &bindingManager = Shiboken::BindingManager::instance(); + SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject); + // The refcount can be 0 if the object is dieing and someone called + // a virtual method from the destructor + if (wrapper == nullptr) + return nullptr; + auto *pySelf = reinterpret_cast<PyObject *>(wrapper); + if (Py_REFCNT(pySelf) == 0) + return nullptr; + + gil.acquire(); + + if (resultCache != nullptr) // recreate the callable from function/self + return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr); + + PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache); + auto *wrapper_dict = SbkObject_GetDict_NoRef(pySelf); + + // Note: This special case was implemented for duck-punching, which happens + // in the instance dict. It does not work with properties. + // This is not cached to avoid leaking. FIXME PYSIDE 7: Remove (PYSIDE-2916)? + if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) { + Py_INCREF(method); + return method; + } + + auto *pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName); + if (pyOverride == nullptr) { + resultCache = Py_None; + Py_INCREF(resultCache); + gil.release(); + return nullptr; // No override, execute C++ call } - return pyOverride; + + if (Shiboken::Errors::occurred() != nullptr) { + // Give up. + Py_XDECREF(pyOverride); + resultCache = Py_None; + Py_INCREF(resultCache); + gil.release(); + return nullptr; // // Give up. + } + + resultCache = pyOverride; + // recreate the callable from function/self + return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr); } namespace diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h index 9eea89540..426298bcf 100644 --- a/sources/shiboken6/libshiboken/basewrapper.h +++ b/sources/shiboken6/libshiboken/basewrapper.h @@ -123,9 +123,8 @@ LIBSHIBOKEN_API PyObject *Sbk_ReturnFromPython_Self(PyObject *self); } // extern "C" LIBSHIBOKEN_API PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject, - Shiboken::GilState &gil, - const char *funcName, bool &resultCache, - PyObject **nameCache); + Shiboken::GilState &gil, const char *funcName, + PyObject *&resultCache, PyObject **nameCache); namespace Shiboken { diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp index 25cc5c00a..ca509aefd 100644 --- a/sources/shiboken6/libshiboken/bindingmanager.cpp +++ b/sources/shiboken6/libshiboken/bindingmanager.cpp @@ -369,13 +369,6 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr, PyTypeObject *typeO PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName) { auto *obWrapper = reinterpret_cast<PyObject *>(wrapper); - auto *wrapper_dict = SbkObject_GetDict_NoRef(obWrapper); - if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) { - // Note: This special case was implemented for duck-punching, which happens - // in the instance dict. It does not work with properties. - Py_INCREF(method); - return method; - } Shiboken::AutoDecRef method(PyObject_GetAttr(obWrapper, pyMethodName)); if (method.isNull()) @@ -387,9 +380,9 @@ PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName // crude check for them. // PYSIDE-535: This macro is redefined in a compatible way in pep384 if (PyMethod_Check(method) != 0) { - if (PyMethod_GET_SELF(method) != obWrapper) + if (PyMethod_Self(method) != obWrapper) return nullptr; - function = PyMethod_GET_FUNCTION(method); + function = PyMethod_Function(method); } else if (isCompiledMethod(method)) { Shiboken::AutoDecRef im_self(PyObject_GetAttr(method, PyName::im_self())); // Not retaining a reference inline with what PyMethod_GET_SELF does. @@ -413,13 +406,13 @@ PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName if (PyObject *defaultMethod = PyDict_GetItem(parentDict.object(), pyMethodName)) { defaultFound = true; if (function != defaultMethod) - return method.release(); + return function; } } } // PYSIDE-2255: If no default method was found, use the method. if (!defaultFound) - return method.release(); + return function; return nullptr; } diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py index 109562a98..8eea431c3 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/layout.py @@ -352,6 +352,7 @@ def create_signature_union(props, key): if last == _VAR_POSITIONAL: kind = _KEYWORD_ONLY if default is None: + ann = typing.Union[ann] ann = typing.Optional[ann] if default is not _empty and layout.ellipsis: default = ellipsis @@ -373,6 +374,7 @@ def create_signature_union(props, key): ret_anno = annotations.get('return', _empty) if ret_anno is not _empty and props["fullname"] in missing_optional_return: + ret_anno = typing.Union[ret_anno] ret_anno = typing.Optional[ret_anno] return inspect.Signature(params, return_annotation=ret_anno, __validate_parameters__=False) diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py index c5dc44644..1031e0bb0 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py @@ -69,12 +69,12 @@ class Formatter(Writer): backup = inspect.formatannotation @classmethod - def formatannotation(cls, annotation, base_module=None): + def formatannotation(cls, annotation, base_module=None, *args, **kwargs): if getattr(annotation, '__module__', None) == 'typing': # do not remove the prefix! return repr(annotation) # do the normal action. - return cls.backup(annotation, base_module) + return cls.backup(annotation, base_module, *args, **kwargs) @classmethod def fix_typing_prefix(cls, signature): diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 2bb3c9a87..84cb15feb 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -509,6 +509,7 @@ def init_PySide6_QtCore(): "PySide6.QtCore.QUrl.ComponentFormattingOptions": PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? "PyUnicode": typing.Text, + "QByteArray": typing.Union[PySide6.QtCore.QByteArray, bytes, bytearray, memoryview], "QByteArrayView": PySide6.QtCore.QByteArray, "Q_NULLPTR": None, "QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified, diff --git a/sources/shiboken6/tests/libsample/bucket.cpp b/sources/shiboken6/tests/libsample/bucket.cpp index cafd382a9..43a32f414 100644 --- a/sources/shiboken6/tests/libsample/bucket.cpp +++ b/sources/shiboken6/tests/libsample/bucket.cpp @@ -40,15 +40,21 @@ bool Bucket::empty() void Bucket::lock() { - m_locked = true; - while (m_locked) { - SLEEP(300); + bool expected = false; + if (m_locked.compare_exchange_strong(expected, true)) { + while (m_locked) { + SLEEP(300); + } + } else { + std::cerr << __FUNCTION__ << " Attempt to lock twice.\n"; } } void Bucket::unlock() { - m_locked = false; + bool expected = true; + if (!m_locked.compare_exchange_strong(expected, false)) + std::cerr << __FUNCTION__ << " Attempt to unlock twice.\n"; } bool Bucket::virtualBlockerMethod() diff --git a/sources/shiboken6/tests/libsample/bucket.h b/sources/shiboken6/tests/libsample/bucket.h index 73e8edd78..677069fe7 100644 --- a/sources/shiboken6/tests/libsample/bucket.h +++ b/sources/shiboken6/tests/libsample/bucket.h @@ -7,6 +7,7 @@ #include "libsamplemacros.h" #include "objecttype.h" +#include <atomic> #include <list> class ObjectType; @@ -19,7 +20,7 @@ public: int pop(); bool empty(); void lock(); - inline bool locked() { return m_locked; } + bool locked() { return m_locked.load(); } void unlock(); virtual bool virtualBlockerMethod(); @@ -27,8 +28,7 @@ public: private: std::list<int> m_data; - - volatile bool m_locked = false; + std::atomic<bool> m_locked{false}; }; #endif // BUCKET_H diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp index 18a18d28d..3836f43aa 100644 --- a/sources/shiboken6/tests/libsample/samplenamespace.cpp +++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp @@ -97,6 +97,15 @@ int passReferenceToObjectType(const ObjectType &obj, int multiplier) return obj.objectName().size() * multiplier; } +// Exercise specifying complete template specializations as primitive types. +std::optional<long> optionalMultiply(const std::optional<long> &v1, + const std::optional<long> &v2) +{ + if (!v1.has_value() || !v2.has_value()) + return std::nullopt; + return v1.value() * v2.value(); +} + int variableInNamespace = 42; } // namespace SampleNamespace diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h index 99a0787ee..63dc2f316 100644 --- a/sources/shiboken6/tests/libsample/samplenamespace.h +++ b/sources/shiboken6/tests/libsample/samplenamespace.h @@ -9,6 +9,7 @@ #include "point.h" #include "objecttype.h" +#include <optional> #include <list> // Anonymous global enum @@ -157,6 +158,9 @@ LIBSAMPLE_API double passReferenceToValueType(const Point &point, double multipl // Add a new signature on type system with only a ObjectType pointer as parameter. LIBSAMPLE_API int passReferenceToObjectType(const ObjectType &obj, int multiplier); +LIBSAMPLE_API std::optional<long> optionalMultiply(const std::optional<long> &v1, + const std::optional<long> &v2); + extern LIBSAMPLE_API int variableInNamespace; } // namespace SampleNamespace diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py index c003ad398..43b84d36e 100644 --- a/sources/shiboken6/tests/samplebinding/sample_test.py +++ b/sources/shiboken6/tests/samplebinding/sample_test.py @@ -79,6 +79,13 @@ class ModuleTest(unittest.TestCase): mo2 = sample.MoveOnlyHandler.passMoveOnly(mo) self.assertEqual(mo2.value(), v) + def testOptionalLong(self): + v1 = 2 + v2 = 3 + self.assertEqual(sample.SampleNamespace.optionalMultiply(v1, v2), 6) + self.assertIsNone(sample.SampleNamespace.optionalMultiply(v1, None)) + self.assertIsNone(sample.SampleNamespace.optionalMultiply(None, v2)) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml index 3f1b2e96f..391a0804d 100644 --- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml @@ -120,6 +120,25 @@ </conversion-rule> </primitive-type> + <primitive-type name="std::optional<long>" target-langapi-name="PyObject"> + <conversion-rule> + <native-to-target> + if (!%in.has_value()) + Py_RETURN_NONE; + return PyLong_FromLong(%in.value()); + </native-to-target> + <target-to-native> + <add-conversion type="Py_None"> + SBK_UNUSED(%in) + %out = %OUTTYPE(); + </add-conversion> + <add-conversion type="PyLong" check="PyLong_CheckExact(%in)"> + %out = %OUTTYPE(PyLong_AsLong(%in)); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + <value-type name="MoveOnly"/> <object-type name="MoveOnlyHandler"/> |