diff options
Diffstat (limited to 'sources')
38 files changed, 466 insertions, 149 deletions
diff --git a/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml b/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml index f62b1ec7d..cbb392761 100644 --- a/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml +++ b/sources/pyside6/PySide6/QtMultimedia/typesystem_multimedia.xml @@ -21,14 +21,9 @@ </namespace-type> <namespace-type name="QtAudio"> -<!-- FIXME PYSIDE7: Remove namespace "QAudio" and enable the enums. <enum-type name="Error"/> <enum-type name="State"/> <enum-type name="VolumeScale"/> ---> - <inject-code class="target" position="end" - file="../glue/qtmultimedia.cpp" - snippet="qtaudio-namespace-import-enums"/> <modify-field name="NoError" remove="true"/> <modify-field name="OpenError" remove="true"/> <modify-field name="IOError" remove="true"/> diff --git a/sources/pyside6/PySide6/glue/qtmultimedia.cpp b/sources/pyside6/PySide6/glue/qtmultimedia.cpp index 65cefa5fc..457621638 100644 --- a/sources/pyside6/PySide6/glue/qtmultimedia.cpp +++ b/sources/pyside6/PySide6/glue/qtmultimedia.cpp @@ -26,15 +26,3 @@ const auto size = %CPPSELF.byteCount(); const float result = QtAudio::convertVolume(%1, %2, %3); %PYARG_0 = %CONVERTTOPYTHON[float](result); // @snippet qaudio-convertvolume - -// @snippet qtaudio-namespace-import-enums -Shiboken::AutoDecRef qAudio(PyObject_GetAttrString(module, "QAudio")); -if (!qAudio.isNull()) { - Shiboken::AutoDecRef qAudioTypeDict(PepType_GetDict(reinterpret_cast<PyTypeObject *>(qAudio.object()))); - Shiboken::AutoDecRef qtAudioTypeDict(PepType_GetDict(pyType)); - for (const auto *oldEnum : {"Error", "State", "VolumeScale"}) { - if (auto *enumType = PyDict_GetItemString(qAudioTypeDict, oldEnum)) - PyDict_SetItemString(qtAudioTypeDict, oldEnum, enumType); - } -} -// @snippet qtaudio-namespace-import-enums diff --git a/sources/pyside6/doc/_tags/android.rst b/sources/pyside6/doc/_tags/android.rst index 0fdf2041a..d694f75f9 100644 --- a/sources/pyside6/doc/_tags/android.rst +++ b/sources/pyside6/doc/_tags/android.rst @@ -15,9 +15,9 @@ My tags: Android ../examples/example_multimedia_camera.rst ../examples/example_qml_editingmodel.rst ../examples/example_qml_usingmodel.rst + ../examples/example_quick_customitems_painteditem.rst ../examples/example_quick_models_objectlistmodel.rst ../examples/example_quick_models_stringlistmodel.rst - ../examples/example_quick_painteditem.rst ../examples/example_quickcontrols_contactslist.rst ../examples/example_quickcontrols_gallery.rst ../examples/example_widgets_widgets_digitalclock.rst diff --git a/sources/pyside6/doc/conf.py.in b/sources/pyside6/doc/conf.py.in index 5af91019b..38c2c606c 100644 --- a/sources/pyside6/doc/conf.py.in +++ b/sources/pyside6/doc/conf.py.in @@ -33,7 +33,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz', 'inheritance_diagram', 'pysideinclude', 'sphinx.ext.viewcode', 'sphinx_design', 'sphinx_copybutton', 'myst_parser', 'sphinx_tags', - 'sphinx_toolbox.decorators', 'sphinx_reredirects'] + 'sphinx_toolbox.collapse', 'sphinx_toolbox.decorators', 'sphinx_reredirects'] myst_enable_extensions = [ "amsmath", diff --git a/sources/pyside6/doc/developer/add_port_example.rst b/sources/pyside6/doc/developer/add_port_example.rst index 59aa2f115..909986e79 100644 --- a/sources/pyside6/doc/developer/add_port_example.rst +++ b/sources/pyside6/doc/developer/add_port_example.rst @@ -27,7 +27,13 @@ For example: $ flake8 --config pyside-setup/.flake8 your_file.py $ isort your_file.py +Later on, the tool `tools/sync_examples.py` can be used to update the source +files from Qt C++. Each difference produced by tool needs to checked with care, +differences in `qmldir` files (`prefer` directive) might apply to C++ only. +Also, be careful not to back-port old Qt Widgets Designer `.ui` files with +unqualified enumerations. If a `.ui` file has additions, make sure to load and +save it at least once. Add a new example ----------------- diff --git a/sources/pyside6/doc/developer/pythonversions.md b/sources/pyside6/doc/developer/pythonversions.md index a4803bbbe..baef18d77 100644 --- a/sources/pyside6/doc/developer/pythonversions.md +++ b/sources/pyside6/doc/developer/pythonversions.md @@ -2,7 +2,8 @@ ## Relevant preprocessor defines -- The version range is determined by `wheel_artifacts/pyproject.toml.base` +- The version range is determined by `wheel_artifacts/pyproject.toml.base`. + This file also defines the version tag (`py_limited_api = "cp310"`). - `PY_VERSION_HEX` Python version (defined in CPython headers) - `Py_LIMITED_API` Limited API minimum version, defined in several CMake files - `PYPY_VERSION` [PyPy](https://pypy.org/) version (defined in PyPy headers) @@ -16,8 +17,11 @@ The removal of Python versions is tied to their lifetime - Check the source code for preprocessor defines depending on values `Py_LIMITED_API`, `PY_VERSION_HEX` and simplify or remove conditions if possible. +- Check the usages of `_PepRuntimeVersion()` for outdated versions - Run the tests and some examples. There might actually - some version checks in Python code that trigger. + some version checks in Python code that trigger + (see for example + `sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py:70`). ## Adapting to new Python versions diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp index ed7067a2e..d08fb56bf 100644 --- a/sources/pyside6/libpyside/signalmanager.cpp +++ b/sources/pyside6/libpyside/signalmanager.cpp @@ -353,6 +353,18 @@ void SignalManager::handleMetaCallError() Py_SetRecursionLimit(reclimit); } +const char *metaObjectCallName(QMetaObject::Call call) +{ + static const char *names[] = { + "InvokeMetaMethod", "ReadProperty", "WriteProperty", "ResetProperty", + "CreateInstance", "IndexOfMethod", "RegisterPropertyMetaType", + "RegisterMethodArgumentMetaType", "BindableProperty", "CustomCall", + "ConstructInPlace"}; + constexpr size_t count = sizeof(names)/sizeof(names[0]); + static_assert(QMetaObject::ConstructInPlace == count - 1); + return call >= 0 && call < count ? names[call] : "<unknown>"; +} + // Handler for QMetaObject::ReadProperty/WriteProperty/ResetProperty: int SignalManagerPrivate::qtPropertyMetacall(QObject *object, QMetaObject::Call call, @@ -398,7 +410,7 @@ int SignalManagerPrivate::qtPropertyMetacall(QObject *object, } qWarning().noquote().nospace() - << "An error occurred executing the property metacall " << call + << "An error occurred executing the property metacall " << metaObjectCallName(call) << " on property \"" << mp.name() << "\" of " << object; handleMetaCallError(object, &result); } diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index ce361245c..9807e1ea6 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -531,13 +531,22 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, ReportHandler::startProgress("Generated enum model (" + QByteArray::number(enums.size()) + ")."); for (const EnumModelItem &item : enums) { - auto metaEnum = traverseEnum(item, nullptr, QSet<QString>()); + auto metaEnum = traverseEnum(item, nullptr); if (metaEnum.has_value()) { if (metaEnum->typeEntry()->generateCode()) m_globalEnums << metaEnum.value(); } } + const auto &globalTypeDefs = dom->typeDefs(); + for (const auto &typeDef : globalTypeDefs) { + if (typeDef->underlyingTypeCategory() == TypeCategory::Enum) { + const auto metaEnum = traverseTypedefedEnum(dom, typeDef, {}); + if (metaEnum.has_value()) + m_globalEnums.append(metaEnum.value()); + } + } + const auto &namespaceTypeValues = dom->namespaces(); ReportHandler::startProgress("Generated namespace model (" + QByteArray::number(namespaceTypeValues.size()) + ")."); @@ -765,7 +774,7 @@ AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, const NamespaceModelItem &namespaceItem) { - QString namespaceName = currentScope()->qualifiedName().join(u"::"_s); + QString namespaceName = currentScope()->qualifiedNameString(); if (!namespaceName.isEmpty()) namespaceName.append(u"::"_s); namespaceName.append(namespaceItem->name()); @@ -809,7 +818,7 @@ AbstractMetaClassPtr m_itemToClass.insert(namespaceItem.get(), metaClass); } - traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); + traverseEnums(namespaceItem, metaClass); pushScope(namespaceItem); @@ -827,11 +836,20 @@ AbstractMetaClassPtr // specific typedefs to be used as classes. const TypeDefList typeDefs = namespaceItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - const auto cls = traverseTypeDef(dom, typeDef, metaClass); - if (cls) { - metaClass->addInnerClass(cls); - cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.get()); + switch (typeDef->underlyingTypeCategory()) { + case TypeCategory::Enum: { + const auto metaEnum = traverseTypedefedEnum(dom, typeDef, metaClass); + if (metaEnum.has_value()) + metaClass->addEnum(metaEnum.value()); + } + break; + default: + if (const auto cls = traverseTypeDef(dom, typeDef, metaClass)) { + metaClass->addInnerClass(cls); + cls->setEnclosingClass(metaClass); + addAbstractMetaClass(cls, typeDef.get()); + } + break; } } @@ -856,16 +874,15 @@ AbstractMetaClassPtr std::optional<AbstractMetaEnum> AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem, - const AbstractMetaClassPtr &enclosing, - const QSet<QString> &enumsDeclarations) + const AbstractMetaClassPtr &enclosing) { - QString qualifiedName = enumItem->qualifiedName().join(u"::"_s); + QString qualifiedName = enumItem->qualifiedNameString(); TypeEntryPtr typeEntry; - const auto enclosingTypeEntry = enclosing ? enclosing->typeEntry() : TypeEntryCPtr{}; if (enumItem->accessPolicy() == Access::Private) { + Q_ASSERT(enclosing); typeEntry = std::make_shared<EnumTypeEntry>(enumItem->qualifiedName().constLast(), - QVersionNumber(0, 0), enclosingTypeEntry); + QVersionNumber(0, 0), enclosing->typeEntry()); TypeDatabase::instance()->addType(typeEntry); } else if (enumItem->enumKind() != AnonymousEnum) { typeEntry = TypeDatabase::instance()->findType(qualifiedName); @@ -881,12 +898,17 @@ std::optional<AbstractMetaEnum> break; } } + return createMetaEnum(enumItem, qualifiedName, typeEntry, enclosing); +} - QString enumName = enumItem->name(); - - QString className; - if (enclosingTypeEntry) - className = enclosingTypeEntry->qualifiedCppName(); +std::optional<AbstractMetaEnum> + AbstractMetaBuilderPrivate::createMetaEnum(const EnumModelItem &enumItem, + const QString &qualifiedName, + const TypeEntryPtr &typeEntry, + const AbstractMetaClassPtr &enclosing) +{ + const QString enumName = enumItem->name(); + const QString className = enclosing ? enclosing->typeEntry()->qualifiedCppName() : QString{}; QString rejectReason; if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { @@ -922,10 +944,6 @@ std::optional<AbstractMetaEnum> metaEnum.setDeprecated(enumItem->isDeprecated()); metaEnum.setUnderlyingType(enumItem->underlyingType()); metaEnum.setSigned(enumItem->isSigned()); - if (enumsDeclarations.contains(qualifiedName) - || enumsDeclarations.contains(enumName)) { - metaEnum.setHasQEnumsDeclaration(true); - } auto enumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(typeEntry); metaEnum.setTypeEntry(enumTypeEntry); @@ -972,6 +990,49 @@ std::optional<AbstractMetaEnum> return metaEnum; } +// Add typedef'ed enumerations ("Using MyEnum=SomeNamespace::MyEnum") for which +// a type entry exists. +std::optional<AbstractMetaEnum> + AbstractMetaBuilderPrivate::traverseTypedefedEnum(const FileModelItem &dom, + const TypeDefModelItem &typeDefItem, + const AbstractMetaClassPtr &enclosing) +{ + if (enclosing && typeDefItem->accessPolicy() != Access::Public) + return std::nullopt; // Only for global/public enums typedef'ed into classes/namespaces + auto modelItem = CodeModel::findItem(typeDefItem->type().qualifiedName(), dom); + if (!modelItem || modelItem->kind() != _CodeModelItem::Kind_Enum) + return std::nullopt; + auto enumItem = std::static_pointer_cast<_EnumModelItem>(modelItem); + if (enumItem->accessPolicy() != Access::Public) + return std::nullopt; + // Name in class + QString qualifiedName = enclosing + ? enclosing->qualifiedCppName() + "::"_L1 + typeDefItem->name() : typeDefItem->name(); + auto targetTypeEntry = TypeDatabase::instance()->findType(qualifiedName); + if (!targetTypeEntry || !targetTypeEntry->isEnum() || !targetTypeEntry->generateCode()) + return std::nullopt; + auto targetEnumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(targetTypeEntry); + auto sourceTypeEntry = TypeDatabase::instance()->findType(enumItem->qualifiedNameString()); + if (!sourceTypeEntry || !sourceTypeEntry->isEnum()) + return std::nullopt; + + auto sourceEnumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(sourceTypeEntry); + if (sourceEnumTypeEntry == targetEnumTypeEntry) // Reject "typedef Enum1 { V1 } Enum1;" + return std::nullopt; + + const QString message = "Enum \""_L1 + qualifiedName + "\" is an alias to \""_L1 + + enumItem->qualifiedNameString() + "\"."_L1; + ReportHandler::addGeneralMessage(message); + auto result = createMetaEnum(enumItem, qualifiedName, targetTypeEntry, enclosing); + if (result.has_value()) { + targetEnumTypeEntry->setAliasMode(EnumTypeEntry::AliasTarget); + targetEnumTypeEntry->setAliasTypeEntry(sourceEnumTypeEntry); + sourceEnumTypeEntry->setAliasMode(EnumTypeEntry::AliasSource); + sourceEnumTypeEntry->setAliasTypeEntry(targetEnumTypeEntry); + } + return result; +} + AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, const TypeDefModelItem &typeDef, @@ -1177,7 +1238,7 @@ AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelIt parseQ_Properties(metaClass, classItem->propertyDeclarations()); - traverseEnums(classItem, metaClass, classItem->enumsDeclarations()); + traverseEnums(classItem, metaClass); // Inner classes { @@ -1197,10 +1258,20 @@ AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelIt // specific typedefs to be used as classes. const TypeDefList typeDefs = classItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - const auto cls = traverseTypeDef(dom, typeDef, metaClass); - if (cls) { - cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.get()); + if (typeDef->accessPolicy() != Access::Private) { + switch (typeDef->underlyingTypeCategory()) { + case TypeCategory::Enum: { + const auto metaEnum = traverseTypedefedEnum(dom, typeDef, metaClass); + if (metaEnum.has_value()) + metaClass->addEnum(metaEnum.value()); + } + break; + default: + if (const auto cls = traverseTypeDef(dom, typeDef, metaClass)) { + cls->setEnclosingClass(metaClass); + addAbstractMetaClass(cls, typeDef.get()); + } + } } } @@ -1648,13 +1719,11 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me } void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, - const AbstractMetaClassPtr &metaClass, - const QStringList &enumsDeclarations) + const AbstractMetaClassPtr &metaClass) { const EnumList &enums = scopeItem->enums(); - const QSet<QString> enumsDeclarationSet(enumsDeclarations.cbegin(), enumsDeclarations.cend()); for (const EnumModelItem &enumItem : enums) { - auto metaEnum = traverseEnum(enumItem, metaClass, enumsDeclarationSet); + auto metaEnum = traverseEnum(enumItem, metaClass); if (metaEnum.has_value()) { metaClass->addEnum(metaEnum.value()); } @@ -1713,10 +1782,7 @@ AbstractMetaFunctionPtr const auto &args = addedFunc->arguments(); - qsizetype argCount = args.size(); - // Check "foo(void)" - if (argCount == 1 && args.constFirst().typeInfo.isVoid()) - argCount = 0; + const qsizetype argCount = args.size(); for (qsizetype i = 0; i < argCount; ++i) { const AddedFunction::Argument &arg = args.at(i); auto type = translateType(arg.typeInfo, metaClass, {}, errorMessage); diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h index 45dd21e02..0a09d578b 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h @@ -94,10 +94,14 @@ public: AbstractMetaClassPtr traverseNamespace(const FileModelItem &dom, const NamespaceModelItem &item); std::optional<AbstractMetaEnum> traverseEnum(const EnumModelItem &item, - const AbstractMetaClassPtr &enclosing, - const QSet<QString> &enumsDeclarations); - void traverseEnums(const ScopeModelItem &item, const AbstractMetaClassPtr &parent, - const QStringList &enumsDeclarations); + const AbstractMetaClassPtr &enclosing); + void traverseEnums(const ScopeModelItem &item, const AbstractMetaClassPtr &parent); + std::optional<AbstractMetaEnum> + createMetaEnum(const EnumModelItem &enumItem, const QString &qualifiedName, + const TypeEntryPtr &typeEntry, const AbstractMetaClassPtr &enclosing); + std::optional<AbstractMetaEnum> + traverseTypedefedEnum(const FileModelItem &dom, const TypeDefModelItem &typeDefItem, + const AbstractMetaClassPtr &enclosing); AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, const AbstractMetaClassPtr ¤tClass); diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp index 486d3d39c..3f2714ffc 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp @@ -96,8 +96,7 @@ void AbstractMetaEnumValue::setDocumentation(const Documentation &doc) class AbstractMetaEnumData : public QSharedData { public: - AbstractMetaEnumData() : m_deprecated(false), - m_hasQenumsDeclaration(false), m_signed(true) + AbstractMetaEnumData() : m_deprecated(false), m_signed(true) { } @@ -113,7 +112,6 @@ public: EnumKind m_enumKind = CEnum; Access m_access = Access::Public; uint m_deprecated : 1; - uint m_hasQenumsDeclaration : 1; uint m_signed : 1; }; @@ -298,17 +296,6 @@ bool AbstractMetaEnum::isAnonymous() const return d->m_enumKind == AnonymousEnum; } -bool AbstractMetaEnum::hasQEnumsDeclaration() const -{ - return d->m_hasQenumsDeclaration; -} - -void AbstractMetaEnum::setHasQEnumsDeclaration(bool on) -{ - if (d->m_hasQenumsDeclaration != on) - d->m_hasQenumsDeclaration = on; -} - EnumTypeEntryCPtr AbstractMetaEnum::typeEntry() const { return d->m_typeEntry; diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.h b/sources/shiboken6/ApiExtractor/abstractmetaenum.h index cfaa9b9bb..c7edb74f6 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.h +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.h @@ -96,10 +96,6 @@ public: bool isAnonymous() const; - // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class? - bool hasQEnumsDeclaration() const; - void setHasQEnumsDeclaration(bool on); - EnumTypeEntryCPtr typeEntry() const; void setTypeEntry(const EnumTypeEntryCPtr &entry); diff --git a/sources/shiboken6/ApiExtractor/addedfunction.cpp b/sources/shiboken6/ApiExtractor/addedfunction.cpp index ee8009cfe..649296066 100644 --- a/sources/shiboken6/ApiExtractor/addedfunction.cpp +++ b/sources/shiboken6/ApiExtractor/addedfunction.cpp @@ -165,10 +165,12 @@ AddedFunction::AddedFunctionPtr } const auto paramString = signature.mid(openParenPos + 1, closingParenPos - openParenPos - 1); - const auto params = AddedFunctionParser::splitParameters(paramString, errorMessage); + auto params = AddedFunctionParser::splitParameters(paramString, errorMessage); if (params.isEmpty() && !errorMessage->isEmpty()) return {}; - for (const auto &p : params) { + if (params.size() == 1 && params.constFirst().type == "void"_L1) + params.clear(); // "void foo(void)" -> ""void foo()" + for (const auto &p : std::as_const(params)) { TypeInfo type = p.type == u"..." ? TypeInfo::varArgsType() : TypeParser::parse(p.type, errorMessage); if (!errorMessage->isEmpty()) { diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp index 33f3f1ae6..cc2924287 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp @@ -524,6 +524,27 @@ void BuilderPrivate::addTemplateInstantiations(const CXType &type, typeName->remove(pos.first, pos.second - pos.first); } +static TypeCategory typeCategoryFromClang(CXTypeKind k) +{ + switch (k) { + case CXType_Void: + return TypeCategory::Void; + case CXType_Enum: + return TypeCategory::Enum; + case CXType_Pointer: + case CXType_BlockPointer: + return TypeCategory::Pointer; + case CXType_FunctionNoProto: + case CXType_FunctionProto: + return TypeCategory::Function; + default: + break; + } + if (k >= CXType_FirstBuiltin && k <= CXType_LastBuiltin) + return TypeCategory::Builtin; + return TypeCategory::Other; +} + TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type, bool *cacheable) const { @@ -533,6 +554,7 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type, if (argCount >= 0) { TypeInfo result = createTypeInfoUncached(clang_getResultType(pointeeType), cacheable); + result.setTypeCategory(TypeCategory::Pointer); result.setFunctionPointer(true); for (int a = 0; a < argCount; ++a) result.addArgument(createTypeInfoUncached(clang_getArgType(pointeeType, unsigned(a)), @@ -542,6 +564,7 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type, } TypeInfo typeInfo; + typeInfo.setTypeCategory(typeCategoryFromClang(clang_getCanonicalType(type).kind)); CXType nestedType = type; for (; isArrayType(nestedType.kind); nestedType = clang_getArrayElementType(nestedType)) { @@ -623,6 +646,7 @@ void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType) setFileName(cursor, item.get()); item->setType(createTypeInfo(cxType)); item->setScope(m_scope); + item->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); m_scopeStack.back()->addTypeDef(item); } diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.cpp b/sources/shiboken6/ApiExtractor/classdocumentation.cpp index 1e721b589..ccc7b29d2 100644 --- a/sources/shiboken6/ApiExtractor/classdocumentation.cpp +++ b/sources/shiboken6/ApiExtractor/classdocumentation.cpp @@ -88,7 +88,7 @@ enum class WebXmlCodeTag static WebXmlCodeTag tag(QStringView name) { - if (name == u"class" || name == u"namespace") + if (name == "class"_L1 || name == "struct"_L1 || name == "namespace"_L1) return WebXmlCodeTag::Class; if (name == u"enum") return WebXmlCodeTag::Enum; diff --git a/sources/shiboken6/ApiExtractor/documentation.h b/sources/shiboken6/ApiExtractor/documentation.h index 580d8f969..a623529ca 100644 --- a/sources/shiboken6/ApiExtractor/documentation.h +++ b/sources/shiboken6/ApiExtractor/documentation.h @@ -29,6 +29,7 @@ public: bool equals(const Documentation &rhs) const; + bool hasDetailed() const { return !m_detailed.isEmpty(); } const QString &detailed() const { return m_detailed; } void setDetailed(const QString &detailed); diff --git a/sources/shiboken6/ApiExtractor/enumtypeentry.h b/sources/shiboken6/ApiExtractor/enumtypeentry.h index 3360d7db5..633ab3183 100644 --- a/sources/shiboken6/ApiExtractor/enumtypeentry.h +++ b/sources/shiboken6/ApiExtractor/enumtypeentry.h @@ -13,6 +13,12 @@ class EnumTypeEntryPrivate; class EnumTypeEntry : public ConfigurableTypeEntry { public: + enum AliasMode : unsigned char { + NoAlias, + AliasSource, // Source of a C++ alias "using ThatEnum = ThisEnum"; + AliasTarget // Target of a C++ alias "using ThisEnum = ThatEnum"; + }; + explicit EnumTypeEntry(const QString &entryName, const QVersionNumber &vr, const TypeEntryCPtr &parent); @@ -40,6 +46,12 @@ public: QString docFile() const; void setDocFile(const QString &df); + AliasMode aliasMode() const; + void setAliasMode(AliasMode am); + + EnumTypeEntryCPtr aliasTypeEntry() const; + void setAliasTypeEntry(const EnumTypeEntryCPtr &entry); + TypeEntry *clone() const override; #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index 5647cccc5..1abfe466b 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -171,7 +171,7 @@ static void msgFormatEnumType(Stream &str, { switch (enumItem->enumKind()) { case CEnum: - str << "Enum '" << enumItem->qualifiedName().join(u"::"_s) << '\''; + str << "Enum '" << enumItem->qualifiedNameString() << '\''; break; case AnonymousEnum: { const EnumeratorList &values = enumItem->enumerators(); @@ -194,7 +194,7 @@ static void msgFormatEnumType(Stream &str, } break; case EnumClass: - str << "Scoped enum '" << enumItem->qualifiedName().join(u"::"_s) << '\''; + str << "Scoped enum '" << enumItem->qualifiedNameString() << '\''; break; } if (!className.isEmpty()) diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp index a5994bd75..8a56c9eee 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp @@ -160,6 +160,11 @@ QStringList _CodeModelItem::qualifiedName() const return q; } +QString _CodeModelItem::qualifiedNameString() const +{ + return qualifiedName().join("::"_L1); +} + QString _CodeModelItem::name() const { return m_name; @@ -453,11 +458,6 @@ FunctionModelItem _ScopeModelItem::declaredFunction(const FunctionModelItem &ite _ScopeModelItem::~_ScopeModelItem() = default; -void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) -{ - m_enumsDeclarations << enumsDeclaration; -} - void _ScopeModelItem::addClass(const ClassModelItem &item) { m_classes.append(item); @@ -520,15 +520,13 @@ void _ScopeModelItem::appendScope(const _ScopeModelItem &other) m_templateTypeAliases += other.m_templateTypeAliases; m_variables += other.m_variables; m_functions += other.m_functions; - m_enumsDeclarations += other.m_enumsDeclarations; } bool _ScopeModelItem::isEmpty() const { return m_classes.isEmpty() && m_enums.isEmpty() && m_typeDefs.isEmpty() && m_templateTypeAliases.isEmpty() - && m_variables.isEmpty() && m_functions.isEmpty() - && m_enumsDeclarations.isEmpty(); + && m_variables.isEmpty() && m_functions.isEmpty(); } /* This function removes MSVC export declarations of non-type template @@ -1208,11 +1206,26 @@ void _TypeDefModelItem::setType(const TypeInfo &type) m_type = type; } +TypeCategory _TypeDefModelItem::underlyingTypeCategory() const +{ + return m_type.typeCategory(); +} + +Access _TypeDefModelItem::accessPolicy() const +{ + return m_accessPolicy; +} + +void _TypeDefModelItem::setAccessPolicy(Access accessPolicy) +{ + m_accessPolicy = accessPolicy; +} + #ifndef QT_NO_DEBUG_STREAM void _TypeDefModelItem::formatDebug(QDebug &d) const { _CodeModelItem::formatDebug(d); - d << ", type=" << m_type; + d << ", " << m_accessPolicy << ", type=" << m_type; } #endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h index fb46fab82..77082efa5 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h @@ -120,6 +120,7 @@ public: int kind() const; QStringList qualifiedName() const; + QString qualifiedNameString() const; QString name() const; void setName(const QString &name); @@ -211,9 +212,6 @@ public: TemplateTypeAliasModelItem findTemplateTypeAlias(QAnyStringView name) const; VariableModelItem findVariable(QAnyStringView name) const; - void addEnumsDeclaration(const QString &enumsDeclaration); - QStringList enumsDeclarations() const { return m_enumsDeclarations; } - FunctionModelItem declaredFunction(const FunctionModelItem &item); bool isEmpty() const; @@ -250,9 +248,6 @@ private: TemplateTypeAliasList m_templateTypeAliases; VariableList m_variables; FunctionList m_functions; - -private: - QStringList m_enumsDeclarations; }; class _ClassModelItem: public _ScopeModelItem @@ -564,11 +559,17 @@ public: TypeInfo type() const; void setType(const TypeInfo &type); + TypeCategory underlyingTypeCategory() const; + + Access accessPolicy() const; + void setAccessPolicy(Access accessPolicy); + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif private: + Access m_accessPolicy = Access::Public; TypeInfo m_type; }; diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h index e5c429bd0..c3bb10e5f 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h @@ -58,4 +58,14 @@ enum class FunctionAttribute { Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute) Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionAttributes) +// C++ type category for TypeInfo, reflecting clang's CXTypeKind +enum class TypeCategory : unsigned char { + Other, + Builtin, + Enum, + Pointer, + Function, + Void +}; + #endif // CODEMODEL_ENUMS_H diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp index 93627e6d5..c530cafea 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp @@ -25,7 +25,6 @@ class TypeInfoData : public QSharedData public: TypeInfoData(); - bool isVoid() const; bool equals(const TypeInfoData &other) const; bool isStdType() const; void simplifyStdType(); @@ -48,6 +47,7 @@ public: }; ReferenceType m_referenceType = NoReference; + TypeCategory m_category = TypeCategory::Other; }; TypeInfoData::TypeInfoData() : flags(0) @@ -143,18 +143,21 @@ void TypeInfo::addName(const QString &n) d->m_qualifiedName.append(n); } -bool TypeInfoData::isVoid() const +bool TypeInfo::isVoid() const { - return m_indirections.isEmpty() && m_referenceType == NoReference - && m_arguments.isEmpty() && m_arrayElements.isEmpty() - && m_instantiations.isEmpty() - && m_qualifiedName.size() == 1 - && m_qualifiedName.constFirst() == u"void"; + return d->m_category == TypeCategory::Void; } -bool TypeInfo::isVoid() const +TypeCategory TypeInfo::typeCategory() const +{ + return d->m_category; + +} + +void TypeInfo::setTypeCategory(TypeCategory c) { - return d->isVoid(); + if (d->m_category != c) + d->m_category = c; } bool TypeInfo::isConstant() const @@ -457,6 +460,7 @@ bool TypeInfoData::equals(const TypeInfoData &other) const return flags == other.flags && m_qualifiedName == other.m_qualifiedName + && m_category == other.m_category && (!m_functionPointer || m_arguments == other.m_arguments) && m_instantiations == other.m_instantiations; } @@ -584,6 +588,23 @@ void TypeInfo::formatDebug(QDebug &debug) const debug << ", [const]"; if (d->m_volatile) debug << ", [volatile]"; + switch (d->m_category) { + case TypeCategory::Other: + case TypeCategory::Void: + break; + case TypeCategory::Builtin: + debug << ", [builtin]"; + break; + case TypeCategory::Enum: + debug << ", [enum]"; + break; + case TypeCategory::Pointer: + debug << ", [pointer]"; + break; + case TypeCategory::Function: + debug << ", [function"; + break; + } if (!d->m_indirections.isEmpty()) { debug << ", indirections="; for (auto i : d->m_indirections) diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h index 6f75b5737..092fbb724 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.h +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h @@ -48,6 +48,9 @@ public: bool isVoid() const; + TypeCategory typeCategory() const; + void setTypeCategory(TypeCategory c); + bool isConstant() const; void setConstant(bool is); diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp index c7361b87a..a9b76d32c 100644 --- a/sources/shiboken6/ApiExtractor/qtdocparser.cpp +++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp @@ -30,6 +30,7 @@ #include <algorithm> #include <iterator> +#include <utility> using namespace Qt::StringLiterals; @@ -245,23 +246,35 @@ QtDocParser::FunctionDocumentationOpt return std::nullopt; } -// Extract the <brief> section from a WebXML (class) documentation and remove it -// from the source. -static QString extractBrief(QString *value) +// Extract the <brief>/detailed sections from a WebXML (class) documentation (from <description>) +static std::pair<QString, QString> extractBrief(QString value) { - const auto briefStart = value->indexOf(briefStartElement); - if (briefStart < 0) - return {}; - const auto briefEnd = value->indexOf(briefEndElement, - briefStart + briefStartElement.size()); - if (briefEnd < briefStart) - return {}; - const auto briefLength = briefEnd + briefEndElement.size() - briefStart; - QString briefValue = value->mid(briefStart, briefLength); - briefValue.insert(briefValue.size() - briefEndElement.size(), - u"<rst> More_...</rst>"_s); - value->remove(briefStart, briefLength); - return briefValue; + std::pair<QString, QString> result; + const auto briefStart = value.indexOf(briefStartElement); + if (briefStart > 0) { + const auto briefEnd = value.indexOf(briefEndElement, + briefStart + briefStartElement.size()); + if (briefEnd > briefStart) { + const auto briefLength = briefEnd + briefEndElement.size() - briefStart; + if (briefLength > briefStartElement.size() + briefEndElement.size()) + result.first = value.sliced(briefStart, briefLength); + value.remove(briefStart, briefLength); + // Remove any space/newlines between the <brief/> element and its + // surrounding XML elements. + auto lastElement = value.lastIndexOf(u'>', briefStart); + if (lastElement != -1) { + ++lastElement; + const auto nextElement = value.indexOf(u'<', briefStart); + if (nextElement > lastElement) + value.remove(lastElement, nextElement - lastElement); + } + } + } + + if (value != "<description></description>"_L1) + result.second = value; + + return result; } // Apply the documentation parsed from WebXML to a AbstractMetaFunction and complete argument @@ -408,13 +421,12 @@ QString QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass) qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, {}))); } - const QString brief = extractBrief(&docString); + const auto descriptionPair = extractBrief(docString); Documentation doc; doc.setSourceFile(sourceFileName); - if (!brief.isEmpty()) - doc.setValue(brief, DocumentationType::Brief); - doc.setValue(docString); + doc.setValue(descriptionPair.first, DocumentationType::Brief); + doc.setValue(descriptionPair.second, DocumentationType::Detailed); metaClass->setDocumentation(doc); //Functions Documentation diff --git a/sources/shiboken6/ApiExtractor/tests/a.xml b/sources/shiboken6/ApiExtractor/tests/a.xml index 3c09d3800..bb771ed1f 100644 --- a/sources/shiboken6/ApiExtractor/tests/a.xml +++ b/sources/shiboken6/ApiExtractor/tests/a.xml @@ -3,7 +3,7 @@ <WebXML> <document> <class name="A"> - <description>oi + <description><para>before brief</para> <brief>Brief description</brief> <para>Paragraph number 1</para> <para>Paragraph number 2</para> diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp index c2fc3b212..9e59ebde6 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp @@ -28,7 +28,7 @@ R"(<typesystem package="Foo"> </value-type> <value-type name='A'> <modify-documentation xpath='description/brief'><brief>Modified Brief</brief></modify-documentation> - <modify-documentation xpath='description/para[3]'><para>Some changed contents here</para></modify-documentation> + <modify-documentation xpath='description/para[4]'><para>Some changed contents here</para></modify-documentation> </value-type> </typesystem> )"; @@ -66,8 +66,7 @@ R"(<typesystem package="Foo"> const char expectedDoc[] = R"(<?xml version="1.0"?> -<description>oi -<para>Paragraph number 1</para> +<description><para>before brief</para><para>Paragraph number 1</para> <para>Paragraph number 2</para> <para>Some changed contents here</para> </description> diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 46e88291d..c02ec0c93 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -1225,7 +1225,9 @@ public: FlagsTypeEntryPtr m_flags; QString m_cppType; QString m_docFile; + std::weak_ptr<const EnumTypeEntry> m_aliasTypeEntry; TypeSystem::PythonEnumType m_pythonEnumType = TypeSystem::PythonEnumType::Unspecified; + EnumTypeEntry::AliasMode m_aliasMode = EnumTypeEntry::AliasMode::NoAlias; }; EnumTypeEntry::EnumTypeEntry(const QString &entryName, @@ -1330,6 +1332,30 @@ void EnumTypeEntry::setDocFile(const QString &df) d->m_docFile = df; } +EnumTypeEntry::AliasMode EnumTypeEntry::aliasMode() const +{ + S_D(const EnumTypeEntry); + return d->m_aliasMode; +} + +void EnumTypeEntry::setAliasMode(AliasMode am) +{ + S_D(EnumTypeEntry); + d->m_aliasMode = am; +} + +EnumTypeEntryCPtr EnumTypeEntry::aliasTypeEntry() const +{ + S_D(const EnumTypeEntry); + return d->m_aliasTypeEntry.lock(); +} + +void EnumTypeEntry::setAliasTypeEntry(const EnumTypeEntryCPtr &entry) +{ + S_D(EnumTypeEntry); + d->m_aliasTypeEntry = entry; +} + TypeEntry *EnumTypeEntry::clone() const { S_D(const EnumTypeEntry); diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index 798ef5719..7fe4df392 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -347,6 +347,23 @@ production of ABI compatible bindings. The **flags-revision** attribute has the same purposes of **revision** attribute but is used for the QFlag related to this enum. +An enum can also be a C++ type alias: + +.. code-block:: c++ + + enum Option { Value1 = 0; } + + class SomeClass { + public: + using OptionAlias = Option; + }; + +In this case, when specifying `<enum-type name="OptionAlias"...>` in +`SomeClass`, an enumeration `OptionAlias` will be generated into the class. The +values of `OptionAlias` and `Option` can be used interchangeably. This feature +is specifically intended for renaming enumerations by deprecating; it works for +at most one alias. + .. _reject-enum-value: reject-enum-value diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp index c99acb3d2..87e01f35b 100644 --- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp @@ -507,6 +507,25 @@ void QtDocGenerator::writeDetailedDescription(TextStream &s, parsedImages); } +enum ClassDescriptionMode +{ + NoDescription, + BriefOnly, + DetailedOnly, + BriefAndDetailed, + BriefAndDetailedSections, +}; + +static ClassDescriptionMode classDescriptionMode(const Documentation &doc) +{ + if (!doc.hasDetailed()) + return doc.hasBrief() ? BriefOnly : NoDescription; + if (!doc.hasBrief()) + return DetailedOnly; + return doc.detailed().contains("<section"_L1) + ? BriefAndDetailedSections : BriefAndDetailed; +} + void QtDocGenerator::doGenerateClass(TextStream &s, const QString &targetDir, const AbstractMetaClassCPtr &metaClass) { @@ -521,8 +540,33 @@ void QtDocGenerator::doGenerateClass(TextStream &s, const QString &targetDir, QtXmlToSphinxImages parsedImages; auto documentation = metaClass->documentation(); const QString scope = classScope(metaClass); - if (documentation.hasBrief()) + + const auto descriptionMode = classDescriptionMode(documentation); + switch (descriptionMode) { + case NoDescription: + case DetailedOnly: + break; + case BriefOnly: writeFormattedBriefText(s, documentation, scope, &parsedImages); + break; + case BriefAndDetailed: { + // A "collapse" sphinx directive can be used for brief/expanding to details + // for descriptions consisting of a paragraph sequence. + writeFormattedBriefText(s, documentation, scope, &parsedImages); + s << "\n\n.. collapse:: Details\n\n"; + Indentation detailIndent(s); + writeDetailedDescription(s, metaClass, scope, &parsedImages); + } + break; + case BriefAndDetailedSections: { + // If the the description has nested <section>'s (which break collapse::), we + // use a 'more' label for the detailed text to be written further down. + QString brief = documentation.brief(); + brief.insert(brief.lastIndexOf(u'<'), "<rst> More_...</rst>"_L1); + writeFormattedText(s, brief, documentation.format(), scope, &parsedImages); + } + break; + } if (!metaClass->baseClasses().isEmpty()) { if (m_options.inheritanceDiagram) { @@ -560,9 +604,17 @@ void QtDocGenerator::doGenerateClass(TextStream &s, const QString &targetDir, " translation, you can also let us know by creating a ticket on\n" " https:/bugreports.qt.io/projects/PYSIDE\n\n"; - s << '\n' << headline("Detailed Description") << ".. _More:\n"; - - writeDetailedDescription(s, metaClass, scope, &parsedImages); + switch (descriptionMode) { + case DetailedOnly: + case BriefAndDetailedSections: + s << '\n' << headline("Detailed Description"); + if (descriptionMode == BriefAndDetailedSections) + s << ".. _More:\n"; + writeDetailedDescription(s, metaClass, scope, &parsedImages); + break; + default: + break; + } writeEnums(s, metaClass->enums(), scope, &parsedImages); diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 65b03e206..c90a0557c 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -1737,6 +1737,17 @@ void CppGenerator::writeEnumConverterFunctions(TextStream &s, const AbstractMeta writePythonToCppFunction(s, c.toString(), enumConverterPythonType, typeName); QString pyTypeCheck = u"PyObject_TypeCheck(pyIn, "_s + enumPythonType + u')'; + switch (metaEnum.typeEntry()->aliasMode()) { + case EnumTypeEntry::NoAlias: + break; + case EnumTypeEntry::AliasSource: + case EnumTypeEntry::AliasTarget: { + const QString &aliasSourceType = cpythonTypeNameExt(metaEnum.typeEntry()->aliasTypeEntry()); + pyTypeCheck += "\n || PyObject_TypeCheck(pyIn, "_L1 + aliasSourceType + u')'; + } + break; + } + writeIsPythonConvertibleToCppFunction(s, enumConverterPythonType, typeName, pyTypeCheck); c.clear(); @@ -3538,9 +3549,16 @@ void CppGenerator::writeIsPythonConvertibleToCppFunction(TextStream &s, if (!condition.contains(u"pyIn")) s << sbkUnusedVariableCast("pyIn"); } - s << "if (" << condition << ")\n" << indent - << "return " << pythonToCppFuncName << ";\n" << outdent - << "return {};\n" << outdent << "}\n"; + + const bool useBrace = condition.contains(u'\n'); + s << "if (" << condition << ')'; + if (useBrace) + s<< " {"; + s << '\n' << indent + << "return " << pythonToCppFuncName << ";\n" << outdent; + if (useBrace) + s<< "}\n"; + s << "return {};\n" << outdent << "}\n"; } void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, @@ -6022,8 +6040,8 @@ void CppGenerator::writeStaticFieldInitialization(TextStream &s, if (parts.size() < 4) { s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass) << "(PyObject *module)\n{\n" << indent - << "auto *obType = PyObject_GetAttrString(module, \"" << metaClass->name() << "\");\n" - << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n" + << "Shiboken::AutoDecRef obType(PyObject_GetAttrString(module, \"" << metaClass->name() << "\"));\n" + << "auto *type = reinterpret_cast<PyTypeObject *>(obType.object());\n" << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n"; } else { s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass) @@ -6822,7 +6840,8 @@ void CppGenerator::writeContainerConverterInitFunc(TextStream &s, void CppGenerator::writeOpaqueContainerConverterRegisterFunc(TextStream &s, const QString &funcName, const OpaqueContainerTypeHash &opaqueContainers) { - s << "static void " << funcName << "(PyObject *module)\n{\n" << indent; + s << "static void " << funcName << "(PyObject *module)\n{\n" << indent + << "PyTypeObject *pyType{};\n"; if (usePySideExtensions()) { const bool hasQVariantConversion = std::any_of(opaqueContainers.cbegin(), opaqueContainers.cend(), diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp index 591d86f10..826ad89af 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp @@ -285,8 +285,9 @@ CppGenerator::OpaqueContainerData result.pythonToConverterFunctionName); TextStream registrationStr(&result.registrationCode, TextStream::Language::Cpp); - registrationStr << "Py_XINCREF(" << typeFName << "());\nPepModule_AddType(module, " - << typeFName << "());\n"; + registrationStr << "pyType = " << typeFName << "();\n" + << "Py_XINCREF(reinterpret_cast<PyObject *>(pyType));\n" + << "PepModule_AddType(module, pyType);\n"; if (!result.hasQVariantConversion) return result; diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp index 181f04a9d..6ffeef9a3 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.cpp +++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp @@ -814,7 +814,7 @@ bool HeaderGenerator::finishGeneration() TextStream privateTypeFunctions(&privateParameters.typeFunctions, TextStream::Language::Cpp); for (const AbstractMetaEnum &cppEnum : api().globalEnums()) { - if (!cppEnum.isAnonymous()) { + if (!cppEnum.isAnonymous() && cppEnum.typeEntry()->aliasMode() != EnumTypeEntry::AliasSource) { const auto te = cppEnum.typeEntry(); if (te->hasConfigCondition()) parameters.conditionalIncludes[te->configCondition()].append(te->include()); @@ -846,8 +846,10 @@ bool HeaderGenerator::finishGeneration() ConfigurableScope configScope(typeFunctionsStr, classType); for (const AbstractMetaEnum &cppEnum : metaClass->enums()) { - if (cppEnum.isAnonymous() || cppEnum.isPrivate()) + if (cppEnum.isAnonymous() || cppEnum.isPrivate() + || cppEnum.typeEntry()->aliasMode() == EnumTypeEntry::AliasSource) { continue; + } if (const auto inc = cppEnum.typeEntry()->include(); inc != classInclude) par.includes.insert(inc); writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); diff --git a/sources/shiboken6/libshiboken/sbkbindingutils.cpp b/sources/shiboken6/libshiboken/sbkbindingutils.cpp index efa25c547..d61551b3b 100644 --- a/sources/shiboken6/libshiboken/sbkbindingutils.cpp +++ b/sources/shiboken6/libshiboken/sbkbindingutils.cpp @@ -5,6 +5,7 @@ #include "autodecref.h" #include "sbkstring.h" +#include "sbkpep.h" #include "sbkstaticstrings_p.h" #include <algorithm> diff --git a/sources/shiboken6/libshiboken/sbkmodule.cpp b/sources/shiboken6/libshiboken/sbkmodule.cpp index 20566ec50..c8db111ff 100644 --- a/sources/shiboken6/libshiboken/sbkmodule.cpp +++ b/sources/shiboken6/libshiboken/sbkmodule.cpp @@ -140,7 +140,7 @@ static PyTypeObject *incarnateType(PyObject *module, const char *name, initSelectableFeature(saveFeature); // - assign this object to the name in the module - Py_INCREF(type); + Py_INCREF(reinterpret_cast<PyObject *>(type)); PepModule_AddType(module, type); // steals reference // - remove the entry, if not by something cleared. if (!nameToFunc.empty()) diff --git a/sources/shiboken6/tests/libsample/functions.h b/sources/shiboken6/tests/libsample/functions.h index b745aed6b..ef88e543e 100644 --- a/sources/shiboken6/tests/libsample/functions.h +++ b/sources/shiboken6/tests/libsample/functions.h @@ -21,6 +21,8 @@ enum GlobalEnum { ThirdThing }; +using GlobalEnumAlias = GlobalEnum; + enum GlobalOverloadFuncEnum { GlobalOverloadFunc_i, GlobalOverloadFunc_d diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp index 3836f43aa..5e7b67a62 100644 --- a/sources/shiboken6/tests/libsample/samplenamespace.cpp +++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp @@ -11,6 +11,16 @@ namespace SampleNamespace { +SomeClass::OptionAlias SomeClass::passThroughOptionAlias(OptionAlias ov) +{ + return ov; +} + +Option SomeClass::passThroughOption(Option ov) +{ + return ov; +} + // PYSIDE-817, scoped enums must not be converted to int in the wrappers generated // for the protected hacks SomeClass::PublicScopedEnum SomeClass::protectedMethodReturningPublicScopedEnum() const diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h index 63dc2f316..1613ce630 100644 --- a/sources/shiboken6/tests/libsample/samplenamespace.h +++ b/sources/shiboken6/tests/libsample/samplenamespace.h @@ -5,6 +5,7 @@ #define SAMPLENAMESPACE_H #include "libsamplemacros.h" +#include "samplenamespace.h" #include "str.h" #include "point.h" #include "objecttype.h" @@ -86,6 +87,12 @@ class LIBSAMPLE_API SomeClass public: enum class PublicScopedEnum { v1, v2 }; + // Alias an enumeration + using OptionAlias = Option; + inline static constexpr auto None_ = Option::None_; + inline static constexpr auto RandomNumber = Option::RandomNumber; + inline static constexpr auto UnixTime = Option::UnixTime; + class SomeInnerClass { public: @@ -107,16 +114,21 @@ public: inline int someMethod(SomeInnerClass *) { return 0; } virtual OkThisIsRecursiveEnough *someVirtualMethod(OkThisIsRecursiveEnough *arg) { return arg; } - }; + }; // OkThisIsRecursiveEnough protected: enum ProtectedEnum { ProtectedItem0, ProtectedItem1 }; - }; + }; // SomeInnerClass + struct SomeOtherInnerClass { std::list<SomeInnerClass> someInnerClasses; }; + + static OptionAlias passThroughOptionAlias(OptionAlias ov); + static Option passThroughOption(Option ov); + protected: enum ProtectedEnum { ProtectedItem0, diff --git a/sources/shiboken6/tests/samplebinding/namespace_test.py b/sources/shiboken6/tests/samplebinding/namespace_test.py index 0d67c7497..0e92d6e27 100644 --- a/sources/shiboken6/tests/samplebinding/namespace_test.py +++ b/sources/shiboken6/tests/samplebinding/namespace_test.py @@ -64,6 +64,20 @@ class TestClassesUnderNamespace(unittest.TestCase): cls.setValue(SampleNamespace.EnumWithinInlineNamespace.EWIN_Value1) self.assertEqual(cls.value(), SampleNamespace.EnumWithinInlineNamespace.EWIN_Value1) + def testEnumAlias(self): + """Test whether an enumeration can be aliased to another one and values + can be used interchangeably.""" + expected = SampleNamespace.SomeClass.OptionAlias.None_ + actual = SampleNamespace.SomeClass.passThroughOptionAlias(expected) + self.assertEqual(expected, actual) + actual = SampleNamespace.SomeClass.passThroughOption(expected) + self.assertEqual(expected, actual) + # The alias source values should also work + actual = SampleNamespace.SomeClass.passThroughOptionAlias(SampleNamespace.Option.None_) + self.assertEqual(expected, actual) + actual = SampleNamespace.SomeClass.passThroughOption(SampleNamespace.Option.None_) + self.assertEqual(expected, actual) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml index 5503d9bb7..711db9c4a 100644 --- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml @@ -420,6 +420,7 @@ --> <enum-type name="GlobalEnum"/> <enum-type name="GlobalOverloadFuncEnum"/> + <enum-type name="GlobalEnumAlias"/> <enum-type identified-by-value="AnonymousGlobalEnum_Value0"/> @@ -437,6 +438,10 @@ <enum-type name="SampleNamespace"/> </object-type> <value-type name="SomeClass"> + <enum-type name="OptionAlias"/> + <modify-field name="None_" remove="true"/> + <modify-field name="RandomNumber" remove="true"/> + <modify-field name="RandomNumber" remove="true"/> <enum-type name="PublicScopedEnum"/> <value-type name="SomeInnerClass"> <object-type name="OkThisIsRecursiveEnough"> |