diff options
12 files changed, 127 insertions, 12 deletions
diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 55e5d3e8a..a220996a1 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -93,6 +93,7 @@ public: int m_sbkIndex = 0; TypeEntry::Type m_type; bool m_stream = false; + bool m_private = false; }; TypeEntryPrivate::TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, @@ -344,6 +345,16 @@ void TypeEntry::setStream(bool b) m_d->m_stream = b; } +bool TypeEntry::isPrivate() const +{ + return m_d->m_private; +} + +void TypeEntry::setPrivate(bool b) +{ + m_d->m_private = b; +} + QString TypeEntry::name() const { return m_d->m_name; @@ -2061,6 +2072,8 @@ void TypeEntry::formatDebug(QDebug &debug) const debug << ", sbkIndex=" << m_d->m_sbkIndex; if (m_d->m_include.isValid()) debug << ", include=" << m_d->m_include; + if (m_d->m_private) + debug << ", [private]"; formatList(debug, "extraIncludes", m_d->m_extraIncludes, ", "); } diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h index 7d96c1bfb..abbbcd049 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.h +++ b/sources/shiboken6/ApiExtractor/typesystem.h @@ -147,6 +147,9 @@ public: bool stream() const; void setStream(bool b); + bool isPrivate() const; + void setPrivate(bool b); + // The type's name in C++, fully qualified QString name() const; // C++ excluding inline namespaces diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index 42a4015fc..baf979a8f 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -100,6 +100,7 @@ static inline QString staticAttribute() { return QStringLiteral("static"); } static inline QString threadAttribute() { return QStringLiteral("thread"); } static inline QString sourceAttribute() { return QStringLiteral("source"); } static inline QString streamAttribute() { return QStringLiteral("stream"); } +static inline QString privateAttribute() { return QStringLiteral("private"); } static inline QString xPathAttribute() { return QStringLiteral("xpath"); } static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); } static inline QString visibleAttribute() { return QStringLiteral("visible"); } @@ -1551,6 +1552,9 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader const auto name = attributes->at(i).qualifiedName(); if (name == streamAttribute()) { ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false)); + } else if (name == privateAttribute()) { + ctype->setPrivate(convertBoolean(attributes->takeAt(i).value(), + privateAttribute(), false)); } else if (name == generateAttribute()) { generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true); } else if (name ==packageAttribute()) { diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index fadc78cd2..a8761d7f2 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -318,6 +318,7 @@ value-type disable-wrapper="yes | no" exception-handling="..." hash-function="..." + private="yes | no" stream="yes | no" default-constructor="..." revision="..." @@ -344,6 +345,8 @@ value-type For the *optional* **disable-wrapper** attribute, see :ref:`object-type`. + For the *optional* **private** attribute, see :ref:`private_types`. + The **revision** attribute can be used to specify a revision for each type, easing the production of ABI compatible bindings. @@ -378,6 +381,7 @@ object-type exception-handling="..." force-abstract="yes | no" hash-function="..." + private="yes | no" stream="yes | no" revision="..." snake-case="yes | no | both" /> @@ -402,6 +406,8 @@ object-type references, or using a default value that cannot be generated for a parameter, or similar). + For the *optional* **private** attribute, see :ref:`private_types`. + The *optional* attribute **stream** specifies whether this type will be able to use externally defined operators, like QDataStream << and >>. If equals to **yes**, these operators will be called as normal methods within the current class. @@ -601,3 +607,16 @@ Conditional Processing Other keywords can be specified using the :ref:`--keywords <conditional_keywords>` command line option. + +.. _private_types: + +Private Types +^^^^^^^^^^^^^ + +Marking :ref:`object-type` or :ref:`value-type` entries as private causes a +separate, private module header besides the public module header to be +generated for them. + +This can be used for classes that are not referenced in dependent modules +and helps to prevent the propagation of for example private C++ headers +required for them. diff --git a/sources/shiboken6/generator/generator.cpp b/sources/shiboken6/generator/generator.cpp index 58998a380..1988c63f6 100644 --- a/sources/shiboken6/generator/generator.cpp +++ b/sources/shiboken6/generator/generator.cpp @@ -177,6 +177,7 @@ struct Generator::GeneratorPrivate AbstractMetaTypeList instantiatedContainers; AbstractMetaTypeList instantiatedSmartPointers; AbstractMetaClassCList m_invisibleTopNamespaces; + bool m_hasPrivateClasses = false; }; Generator::Generator() : m_d(new GeneratorPrivate) @@ -464,6 +465,8 @@ bool Generator::generate() for (auto cls : m_d->api.classes()) { if (!generateFileForContext(contextForClass(cls))) return false; + if (shouldGenerate(cls) && cls->typeEntry()->isPrivate()) + m_d->m_hasPrivateClasses = true; } const auto smartPointers = m_d->api.smartPointers(); @@ -508,6 +511,11 @@ const ApiExtractorResult &Generator::api() const return m_d->api; } +bool Generator::hasPrivateClasses() const +{ + return m_d->m_hasPrivateClasses; +} + QString Generator::getFullTypeName(const TypeEntry *type) { QString result = type->qualifiedCppName(); diff --git a/sources/shiboken6/generator/generator.h b/sources/shiboken6/generator/generator.h index 2930ff5ee..48ce9edca 100644 --- a/sources/shiboken6/generator/generator.h +++ b/sources/shiboken6/generator/generator.h @@ -237,6 +237,8 @@ public: /// Returns the API as determined by ApiExtractor const ApiExtractorResult &api() const; + bool hasPrivateClasses() const; + /** * Retrieves the name of the currently processed module. * While package name is a complete package idetification, e.g. 'PySide.QtCore', diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 2e9ea8d0b..c58842c95 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -413,6 +413,8 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon s << "#include <helper.h>\n#include <iostream>\n"; s << "\n// module include\n" << "#include \"" << getModuleHeaderFileName() << "\"\n"; + if (hasPrivateClasses()) + s << "#include \"" << getPrivateModuleHeaderFileName() << "\"\n"; QString headerfile = fileNameForContext(classContext); headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h")); diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp index 8bf22d52c..d4dc38090 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.cpp +++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp @@ -404,6 +404,7 @@ bool HeaderGenerator::finishGeneration() // This header should be included by binding modules // extendind on top of this one. QSet<Include> includes; + QSet<Include> privateIncludes; StringStream macrosStream(TextStream::Language::Cpp); const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips(); @@ -494,6 +495,7 @@ bool HeaderGenerator::finishGeneration() macrosStream << "// Macros for type check\n"; StringStream typeFunctions(TextStream::Language::Cpp); + StringStream privateTypeFunctions(TextStream::Language::Cpp); if (usePySideExtensions()) { typeFunctions << "QT_WARNING_PUSH\n"; typeFunctions << "QT_WARNING_DISABLE_DEPRECATED\n"; @@ -512,19 +514,22 @@ bool HeaderGenerator::finishGeneration() //Includes const TypeEntry *classType = metaClass->typeEntry(); - includes << classType->include(); + const bool isPrivate = classType->isPrivate(); + auto &includeList = isPrivate ? privateIncludes : includes; + includeList << classType->include(); + auto &typeFunctionsStr = isPrivate ? privateTypeFunctions : typeFunctions; for (const AbstractMetaEnum &cppEnum : metaClass->enums()) { if (cppEnum.isAnonymous() || cppEnum.isPrivate()) continue; EnumTypeEntry *enumType = cppEnum.typeEntry(); - includes << enumType->include(); + includeList << enumType->include(); writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); - writeSbkTypeFunction(typeFunctions, cppEnum); + writeSbkTypeFunction(typeFunctionsStr, cppEnum); } if (!metaClass->isNamespace()) - writeSbkTypeFunction(typeFunctions, metaClass); + writeSbkTypeFunction(typeFunctionsStr, metaClass); } for (const AbstractMetaType &metaType : instantiatedSmartPtrs) { @@ -535,9 +540,9 @@ bool HeaderGenerator::finishGeneration() if (usePySideExtensions()) typeFunctions << "QT_WARNING_POP\n"; - QString moduleHeaderFileName(outputDirectory() - + QDir::separator() + subDirectoryForPackage(packageName()) - + QDir::separator() + getModuleHeaderFileName()); + const QString moduleHeaderDir = outputDirectory() + QLatin1Char('/') + + subDirectoryForPackage(packageName()) + QLatin1Char('/'); + const QString moduleHeaderFileName(moduleHeaderDir + getModuleHeaderFileName()); QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H")); @@ -599,7 +604,50 @@ bool HeaderGenerator::finishGeneration() << "} // namespace Shiboken\n\n" << "#endif // " << includeShield << "\n\n"; - return file.done() != FileOut::Failure; + if (file.done() == FileOut::Failure) + return false; + + return !hasPrivateClasses() + || writePrivateHeader(moduleHeaderDir, includeShield, + privateIncludes, privateTypeFunctions.toString()); +} + +bool HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir, + const QString &publicIncludeShield, + const QSet<Include> &privateIncludes, + const QString &privateTypeFunctions) +{ + // Write includes and type functions of private classes + + FileOut privateFile(moduleHeaderDir + getPrivateModuleHeaderFileName()); + TextStream &ps = privateFile.stream; + ps.setLanguage(TextStream::Language::Cpp); + QString privateIncludeShield = + publicIncludeShield.left(publicIncludeShield.size() - 2) + + QStringLiteral("_P_H"); + + ps << licenseComment()<< "\n\n"; + + ps << "#ifndef " << privateIncludeShield << '\n'; + ps << "#define " << privateIncludeShield << "\n\n"; + + for (const Include &include : qAsConst(privateIncludes)) + ps << include; + ps << '\n'; + + if (usePySideExtensions()) + ps << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n"; + + ps << "namespace Shiboken\n{\n\n" + << "// PyType functions, to get the PyObjectType for a type T\n" + << privateTypeFunctions << '\n' + << "} // namespace Shiboken\n\n"; + + if (usePySideExtensions()) + ps << "QT_WARNING_POP\n"; + + ps << "#endif\n"; + return privateFile.done() != FileOut::Failure; } void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) const diff --git a/sources/shiboken6/generator/shiboken/headergenerator.h b/sources/shiboken6/generator/shiboken/headergenerator.h index 1fe0dd444..91a10eef8 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.h +++ b/sources/shiboken6/generator/shiboken/headergenerator.h @@ -65,6 +65,10 @@ private: void writeMemberFunctionWrapper(TextStream &s, const AbstractMetaFunctionCPtr &func, const QString &postfix = {}) const; + bool writePrivateHeader(const QString &moduleHeaderDir, + const QString &publicIncludeShield, + const QSet<Include> &privateIncludes, + const QString &privateTypeFunctions); QSet<AbstractMetaFunctionCPtr> m_inheritedOverloads; }; diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 05a9e7571..4ecc69b15 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -2125,9 +2125,19 @@ const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const Abs return getMultipleInheritingClass(metaClass->baseClass()); } +QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName) +{ + return moduleCppPrefix(moduleName).toLower() + QStringLiteral("_python"); +} + QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName) { - return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h"); + return getModuleHeaderFileBaseName(moduleName) + QStringLiteral(".h"); +} + +QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName) +{ + return getModuleHeaderFileBaseName(moduleName) + QStringLiteral("_p.h"); } std::optional<AbstractMetaType> diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h index bcba349cf..29b32c23a 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.h +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h @@ -313,7 +313,8 @@ protected: static QString getFormatUnitString(const AbstractMetaFunctionCPtr &func, bool incRef = false); /// Returns the file name for the module global header. If no module name is provided the current will be used. - static QString getModuleHeaderFileName(const QString &moduleName = QString()) ; + static QString getModuleHeaderFileName(const QString &moduleName = QString()); + static QString getPrivateModuleHeaderFileName(const QString &moduleName = QString()); OptionDescriptions options() const override; bool handleOption(const QString &key, const QString &value) override; @@ -398,6 +399,7 @@ protected: static const QHash<QString, QString> &formatUnits(); private: + static QString getModuleHeaderFileBaseName(const QString &moduleName = QString()); static QString cpythonGetterFunctionName(const QString &name, const AbstractMetaClass *enclosingClass); static QString cpythonSetterFunctionName(const QString &name, diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml index fe5e4343c..d86a637ff 100644 --- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml @@ -2302,7 +2302,7 @@ <object-type name="MDerived5"/> <object-type name="SonOfMDerived1"/> - <object-type name="Bucket"> + <object-type name="Bucket" private="true"> <modify-function signature="lock()" allow-thread="yes" /> <modify-function signature="virtualBlockerMethod()" allow-thread="yes"/> <modify-function signature="callVirtualBlockerMethodButYouDontKnowThis()" allow-thread="yes"/> @@ -2330,7 +2330,7 @@ <property type="RenderHints" name="renderHints" get="getRenderHints" set="setRenderHints"/> </value-type> - <value-type name="CtorConvRule"> + <value-type name="CtorConvRule" private="true"> <modify-function signature="CtorConvRule(long)"> <modify-argument index="1"> <!--<replace-type modified-type="long"/>--> |
