diff options
Diffstat (limited to 'sources/shiboken6/generator/shiboken/headergenerator.cpp')
-rw-r--r-- | sources/shiboken6/generator/shiboken/headergenerator.cpp | 995 |
1 files changed, 661 insertions, 334 deletions
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp index 8bf22d52c..35d0d114f 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.cpp +++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp @@ -1,76 +1,106 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "headergenerator.h" +#include "configurablescope.h" +#include "generatorcontext.h" #include <apiextractorresult.h> +#include <abstractmetaargument.h> #include <abstractmetaenum.h> #include <abstractmetafield.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <abstractmetalang_helpers.h> -#include <modifications.h> +#include <codesnip.h> +#include <clangparser/compilersupport.h> +#include <exception.h> #include <typedatabase.h> #include <reporthandler.h> #include <textstream.h> #include <fileout.h> -#include "parser/codemodel.h" +#include "containertypeentry.h" +#include "enumtypeentry.h" +#include "flagstypeentry.h" +#include <messages.h> +#include "namespacetypeentry.h" +#include "primitivetypeentry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" + +#include "qtcompat.h" #include <algorithm> +#include <set> #include <QtCore/QDir> #include <QtCore/QTextStream> #include <QtCore/QVariant> #include <QtCore/QDebug> -QString HeaderGenerator::fileNameSuffix() const +using namespace Qt::StringLiterals; + +struct IndexValue +{ + QString name; // "SBK_..." + int value; + QString comment; +}; + +TextStream &operator<<(TextStream &s, const IndexValue &iv) { - return QLatin1String("_wrapper.h"); + s << " " << AlignedField(iv.name, 56) << " = " << iv.value << ','; + if (!iv.comment.isEmpty()) + s << " // " << iv.comment; + s << '\n'; + return s; } +// PYSIDE-504: Handling the "protected hack" +// The problem: Creating wrappers when the class has private destructors. +// You can see an example on Windows in qclipboard_wrapper.h and others. +// Simply search for the text "// C++11: need to declare (unimplemented) destructor". +// The protected hack is the definition "#define protected public". +// For most compilers, this "hack" is enabled, because the problem of private +// destructors simply vanishes. +// +// If one does not want to use this hack, then a new problem arises: +// C++11 requires that a destructor is declared in a wrapper class when it is +// private in the base class. There is no implementation allowed! +// +// Unfortunately, MSVC in recent versions supports C++11, and due to restrictive +// rules, it is impossible to use the hack with this compiler. +// More unfortunate: Clang, when C++11 is enabled, also enforces a declaration +// of a private destructor, but it falsely then creates a linker error! +// +// Originally, we wanted to remove the protected hack. But due to the Clang +// problem, we gave up on removal of the protected hack and use it always +// when we can. This might change again when the Clang problem is solved. + +static bool alwaysGenerateDestructorDeclaration() +{ + return clang::compiler() == Compiler::Msvc; +} + +const char *HeaderGenerator::protectedHackDefine = R"(// Workaround to access protected functions +#ifndef protected +# define protected public +#endif + +)"; + QString HeaderGenerator::fileNameForContext(const GeneratorContext &context) const { - const AbstractMetaClass *metaClass = context.metaClass(); - if (!context.forSmartPointer()) { - QString fileNameBase = metaClass->qualifiedCppName().toLower(); - fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); - return fileNameBase + fileNameSuffix(); - } - QString fileNameBase = getFileNameBaseForSmartPointer(context.preciseType(), metaClass); - return fileNameBase + fileNameSuffix(); + return headerFileNameForContext(context); } -void HeaderGenerator::writeCopyCtor(TextStream &s, const AbstractMetaClass *metaClass) const +void HeaderGenerator::writeCopyCtor(TextStream &s, + const AbstractMetaClassCPtr &metaClass) { s << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self) : " << metaClass->qualifiedCppName() << "(self)\n{\n}\n\n"; } -static void writeProtectedEnums(TextStream &s, const AbstractMetaClass *metaClass) +static void writeProtectedEnums(TextStream &s, const AbstractMetaClassCPtr &metaClass) { const QString name = metaClass->qualifiedCppName(); for (const auto &e : metaClass->enums()) { @@ -79,145 +109,181 @@ static void writeProtectedEnums(TextStream &s, const AbstractMetaClass *metaClas } } -void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContextIn) +void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContext) { - GeneratorContext classContext = classContextIn; - const AbstractMetaClass *metaClass = classContext.metaClass(); - m_inheritedOverloads.clear(); + const AbstractMetaClassCPtr metaClass = classContext.metaClass(); // write license comment s << licenseComment(); - QString wrapperName; - if (!classContext.forSmartPointer()) { - wrapperName = classContext.useWrapper() - ? classContext.wrapperName() : metaClass->qualifiedCppName(); - } else { - wrapperName = classContext.smartPointerWrapperName(); - } - QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper(); - QString innerHeaderGuard; + QString wrapperName = classContext.effectiveClassName(); + QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName); // Header s << "#ifndef SBK_" << outerHeaderGuard << "_H\n"; s << "#define SBK_" << outerHeaderGuard << "_H\n\n"; if (!avoidProtectedHack()) - s << "#define protected public\n\n"; + s << protectedHackDefine; - //Includes - auto typeEntry = metaClass->typeEntry(); - s << typeEntry->include() << '\n'; - if (classContext.useWrapper() && !typeEntry->extraIncludes().isEmpty()) { - s << "\n// Extra includes\n"; - for (const Include &inc : typeEntry->extraIncludes()) - s << inc.toString() << '\n'; + // Includes + s << metaClass->typeEntry()->include() << '\n'; + for (auto &inst : metaClass->templateBaseClassInstantiations()) + s << inst.typeEntry()->include(); + + if (classContext.useWrapper()) + writeWrapperClass(s, wrapperName, classContext); + + s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n"; +} + +void HeaderGenerator::writeWrapperClass(TextStream &s, + const QString &wrapperName, + const GeneratorContext &classContext) const +{ + const auto metaClass = classContext.metaClass(); + + if (avoidProtectedHack()) { + const auto includeGroups = classIncludes(metaClass); + for( const auto &includeGroup : includeGroups) + s << includeGroup; } - if (classContext.useWrapper() && usePySideExtensions() && metaClass->isQObject()) + if (usePySideExtensions() && isQObject(metaClass)) s << "namespace PySide { class DynamicQMetaObject; }\n\n"; - while (classContext.useWrapper()) { - if (!innerHeaderGuard.isEmpty()) { - s << "# ifndef SBK_" << innerHeaderGuard << "_H\n"; - s << "# define SBK_" << innerHeaderGuard << "_H\n\n"; - s << "// Inherited base class:\n"; + writeWrapperClassDeclaration(s, wrapperName, classContext); + + // PYSIDE-500: Use also includes for inherited wrapper classes other + // modules, because without the protected hack, we sometimes need to + // cast inherited wrappers. CppGenerator generates include statements for + // the classes of the current module. For other modules, we insert the + // declarations as recursive headers, since wrapper headers are not + // installed. This keeps the file structure as simple as before the + // enhanced inheritance. + if (avoidProtectedHack()) { + const auto &baseClasses = allBaseClasses(classContext.metaClass()); + for (const auto &baseClass : baseClasses) { + const auto gen = baseClass->typeEntry()->codeGeneration(); + if (gen == TypeEntry::GenerateForSubclass) { // other module + const auto baseContext = contextForClass(baseClass); + if (baseContext.useWrapper()) + writeInheritedWrapperClassDeclaration(s, baseContext); + } } + } +} - // Class - s << "class " << wrapperName - << " : public " << metaClass->qualifiedCppName() - << "\n{\npublic:\n" << indent; - - // Make protected enums accessible - if (avoidProtectedHack()) { - recurseClassHierarchy(metaClass, [&s] (const AbstractMetaClass *metaClass) { - writeProtectedEnums(s, metaClass); - return false; - }); - } +void HeaderGenerator::writeInheritedWrapperClassDeclaration(TextStream &s, + const GeneratorContext &classContext) const +{ + const QString wrapperName = classContext.effectiveClassName(); + const QString innerHeaderGuard = + getFilteredCppSignatureString(wrapperName).toUpper(); - if (avoidProtectedHack() && metaClass->hasProtectedFields()) { - s << "\n// Make protected fields accessible\n"; - const QString name = metaClass->qualifiedCppName(); - for (const auto &f : metaClass->fields()) { - if (f.isProtected()) - s << "using " << name << "::" << f.originalName() << ";\n"; - } - s << '\n'; - } + s << "# ifndef SBK_" << innerHeaderGuard << "_H\n" + << "# define SBK_" << innerHeaderGuard << "_H\n\n" + << "// Inherited base class:\n"; - const auto &funcs = filterFunctions(metaClass); - int maxOverrides = 0; - for (const auto &func : funcs) { - if (!func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)) { - writeFunction(s, func); - // PYSIDE-803: Build a boolean cache for unused overrides. - if (shouldWriteVirtualMethodNative(func)) - maxOverrides++; - } - } - if (!maxOverrides) - maxOverrides = 1; - - //destructor - // PYSIDE-504: When C++ 11 is used, then the destructor must always be declared. - // See abstractmetalang.cpp, determineCppWrapper() and generator.h for further - // reference. - if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) { - if (avoidProtectedHack() && metaClass->hasPrivateDestructor()) - s << "// C++11: need to declare (unimplemented) destructor because " - "the base class destructor is private.\n"; - s << '~' << wrapperName << "();\n"; + writeWrapperClassDeclaration(s, wrapperName, classContext); + + s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n"; +} + +void HeaderGenerator::writeWrapperClassDeclaration(TextStream &s, + const QString &wrapperName, + const GeneratorContext &classContext) const +{ + const AbstractMetaClassCPtr metaClass = classContext.metaClass(); + const auto typeEntry = metaClass->typeEntry(); + InheritedOverloadSet inheritedOverloads; + + // write license comment + s << licenseComment(); + + // Class + s << "class " << wrapperName + << " : public " << metaClass->qualifiedCppName() + << "\n{\npublic:\n" << indent + << wrapperName << "(const " << wrapperName << " &) = delete;\n" + << wrapperName << "& operator=(const " << wrapperName << " &) = delete;\n" + << wrapperName << '(' << wrapperName << " &&) = delete;\n" + << wrapperName << "& operator=(" << wrapperName << " &&) = delete;\n\n"; + + // Make protected enums accessible + if (avoidProtectedHack()) { + recurseClassHierarchy(metaClass, [&s] (const AbstractMetaClassCPtr &metaClass) { + writeProtectedEnums(s, metaClass); + return false; + }); + } + + if (avoidProtectedHack() && metaClass->hasProtectedFields()) { + s << "\n// Make protected fields accessible\n"; + const QString name = metaClass->qualifiedCppName(); + for (const auto &f : metaClass->fields()) { + if (f.isProtected()) + s << "using " << name << "::" << f.originalName() << ";\n"; } + s << '\n'; + } - writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(), - TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, - classContext); + int maxOverrides = 0; + for (const auto &func : metaClass->functions()) { + const auto generation = functionGeneration(func); + writeFunction(s, func, &inheritedOverloads, generation); + // PYSIDE-803: Build a boolean cache for unused overrides. + if (generation.testFlag(FunctionGenerationFlag::VirtualMethod)) + maxOverrides++; + } + if (!maxOverrides) + maxOverrides = 1; + + //destructor + // PYSIDE-504: When C++ 11 is used, then the destructor must always be declared. + if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() + || alwaysGenerateDestructorDeclaration()) { + if (avoidProtectedHack() && metaClass->hasPrivateDestructor()) + s << "// C++11: need to declare (unimplemented) destructor because " + "the base class destructor is private.\n"; + s << '~' << wrapperName << "()"; + if (metaClass->hasVirtualDestructor()) + s << " override"; + s << ";\n"; + } + + writeClassCodeSnips(s, typeEntry->codeSnips(), + TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, + classContext); - if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) - && usePySideExtensions() && metaClass->isQObject()) { - s << outdent << "public:\n" << indent << -R"(int qt_metacall(QMetaObject::Call call, int id, void **args) override; + if (shouldGenerateMetaObjectFunctions(metaClass)) { + s << R"( +const ::QMetaObject * metaObject() const override; +int qt_metacall(QMetaObject::Call call, int id, void **args) override; void *qt_metacast(const char *_clname) override; )"; - } + } - if (!m_inheritedOverloads.isEmpty()) { - s << "// Inherited overloads, because the using keyword sux\n"; - for (const auto &func : qAsConst(m_inheritedOverloads)) - writeMemberFunctionWrapper(s, func); - m_inheritedOverloads.clear(); - } + if (!inheritedOverloads.isEmpty()) { + s << "// Inherited overloads, because the using keyword sux\n"; + for (const auto &func : std::as_const(inheritedOverloads)) + writeMemberFunctionWrapper(s, func); + } - if (usePySideExtensions()) - s << "static void pysideInitQtMetaTypes();\n"; - - s << "void resetPyMethodCache();\n" - << outdent << "private:\n" << indent - << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n" - << outdent << "};\n\n"; - if (!innerHeaderGuard.isEmpty()) - s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n"; - - // PYSIDE-500: Use also includes for inherited wrapper classes, because - // without the protected hack, we sometimes need to cast inherited wrappers. - // But we don't use multiple include files. Instead, they are inserted as recursive - // headers. This keeps the file structure as simple as before the enhanced inheritance. - metaClass = metaClass->baseClass(); - if (!metaClass || !avoidProtectedHack()) - break; - classContext = contextForClass(metaClass); - if (!classContext.forSmartPointer()) { - wrapperName = classContext.useWrapper() - ? classContext.wrapperName() : metaClass->qualifiedCppName(); - } else { - wrapperName = classContext.smartPointerWrapperName(); - } - innerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper(); + if (usePySideExtensions()) + s << "static void pysideInitQtMetaTypes();\n"; + + s << "void resetPyMethodCache();\n" + << outdent << "private:\n" << indent; + + if (!metaClass->userAddedPythonOverrides().isEmpty()) { + for (const auto &f : metaClass->userAddedPythonOverrides()) + s << functionSignature(f, {}, {}, Generator::OriginalTypeDescription) << ";\n"; + s << '\n'; } - s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n"; + s << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n" + << outdent << "};\n\n"; } // Write an inline wrapper around a function @@ -227,8 +293,6 @@ void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s, { Q_ASSERT(!func->isConstructor() && !func->isOperatorOverload()); s << "inline "; - if (func->isStatic()) - s << "static "; s << functionSignature(func, {}, postfix, Generator::OriginalTypeDescription) << " { "; if (!func->isVoid()) @@ -248,58 +312,52 @@ void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s, if (i > 0) s << ", "; const AbstractMetaArgument &arg = arguments.at(i); - const TypeEntry *enumTypeEntry = nullptr; - if (arg.type().isFlags()) - enumTypeEntry = static_cast<const FlagsTypeEntry *>(arg.type().typeEntry())->originator(); - else if (arg.type().isEnum()) - enumTypeEntry = arg.type().typeEntry(); - if (enumTypeEntry) - s << arg.type().cppSignature() << '(' << arg.name() << ')'; - else + const auto &type = arg.type(); + TypeEntryCPtr enumTypeEntry; + if (type.isFlags()) + enumTypeEntry = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry())->originator(); + else if (type.isEnum()) + enumTypeEntry = type.typeEntry(); + if (enumTypeEntry) { + s << type.cppSignature() << '(' << arg.name() << ')'; + } else if (type.passByValue() && type.isUniquePointer()) { + s << stdMove(arg.name()); + } else { s << arg.name(); + } } s << "); }\n"; } -void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func) +void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func, + InheritedOverloadSet *inheritedOverloads, + FunctionGeneration generation) const { // do not write copy ctors here. - if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) { + if (generation.testFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor)) { writeCopyCtor(s, func->ownerClass()); return; } - if (func->isUserAdded()) - return; - - if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() - && !func->isOperatorOverload()) { - writeMemberFunctionWrapper(s, func, QLatin1String("_protected")); - } - // pure virtual functions need a default implementation - const bool notAbstract = !func->isAbstract(); - if ((func->isPrivate() && notAbstract && !func->isVisibilityModifiedToPrivate()) - || (func->isModifiedRemoved() && notAbstract)) - return; + if (generation.testFlag(FunctionGenerationFlag::ProtectedWrapper)) + writeMemberFunctionWrapper(s, func, u"_protected"_s); - if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor() - && (func->isAbstract() || func->isVirtual())) + if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor)) { + Options option = func->hasSignatureModifications() + ? Generator::OriginalTypeDescription : Generator::NoOption; + s << functionSignature(func, {}, {}, option) << ";\n"; return; + } - if (func->isConstructor() || func->isAbstract() || func->isVirtual()) { - Options virtualOption = Generator::OriginalTypeDescription; - - const bool virtualFunc = func->isVirtual() || func->isAbstract(); - if (!virtualFunc && !func->hasSignatureModifications()) - virtualOption = Generator::NoOption; - - s << functionSignature(func, QString(), QString(), virtualOption); + const bool isVirtual = generation.testFlag(FunctionGenerationFlag::VirtualMethod); + if (isVirtual) { + s << functionSignature(func, {}, {}, Generator::OriginalTypeDescription) + << " override;\n"; + } - if (virtualFunc) - s << " override"; - s << ";\n"; - // Check if this method hide other methods in base classes + // Check if this method hide other methods in base classes + if (isVirtual) { for (const auto &f : func->ownerClass()->functions()) { if (f != func && !f->isConstructor() @@ -308,7 +366,7 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt && !f->isAbstract() && !f->isStatic() && f->name() == func->name()) { - m_inheritedOverloads << f; + inheritedOverloads->insert(f); } } @@ -318,46 +376,61 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt } } -static void _writeTypeIndexValue(TextStream &s, const QString &variableName, - int typeIndex) -{ - s << " " << AlignedField(variableName, 56) << " = " << typeIndex; -} - -static inline void _writeTypeIndexValueLine(TextStream &s, - const QString &variableName, - int typeIndex) +// Find equivalent typedefs "using Foo=QList<int>", "using Bar=QList<int>" +static AbstractMetaClassCPtr + findEquivalentTemplateTypedef(const AbstractMetaClassCList &haystack, + const AbstractMetaClassCPtr &needle) { - _writeTypeIndexValue(s, variableName, typeIndex); - s << ",\n"; + auto templateBaseClass = needle->templateBaseClass(); + const auto &instantiations = needle->templateBaseClassInstantiations(); + for (const auto &candidate : haystack) { + if (candidate->isTypeDef() + && candidate->templateBaseClass() == templateBaseClass + && candidate->templateBaseClassInstantiations() == instantiations) { + return candidate; + } + } + return nullptr; } -void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorResult &api, - const TypeEntry *typeEntry) +void HeaderGenerator::collectTypeEntryTypeIndexes(const ApiExtractorResult &api, + const TypeEntryCPtr &typeEntry, + IndexValues *indexValues) { if (!typeEntry || !typeEntry->generateCode()) return; - s.setFieldAlignment(QTextStream::AlignLeft); const int typeIndex = typeEntry->sbkIndex(); - _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex); + indexValues->append({getTypeIndexVariableName(typeEntry), typeIndex, {}}); + if (typeEntry->isComplex()) { - const auto *cType = static_cast<const ComplexTypeEntry *>(typeEntry); + // For a typedef "using Foo=QList<int>", write a type index + // SBK_QLIST_INT besides SBK_FOO which is then matched by function + // argument. Check against duplicate typedefs for the same types. + const auto cType = std::static_pointer_cast<const ComplexTypeEntry>(typeEntry); if (cType->baseContainerType()) { auto metaClass = AbstractMetaClass::findClass(api.classes(), cType); Q_ASSERT(metaClass != nullptr); - if (metaClass->templateBaseClass()) - _writeTypeIndexValueLine(s, getTypeIndexVariableName(metaClass, true), typeIndex); + if (metaClass->isTypeDef() + && metaClass->templateBaseClass() != nullptr + && findEquivalentTemplateTypedef(m_alternateTemplateIndexes, + metaClass) == nullptr) { + const QString indexVariable = + getTypeAlternateTemplateIndexVariableName(metaClass); + indexValues->append({indexVariable, typeIndex, {}}); + m_alternateTemplateIndexes.append(m_alternateTemplateIndexes); + } } } if (typeEntry->isEnum()) { - auto ete = static_cast<const EnumTypeEntry *>(typeEntry); + auto ete = std::static_pointer_cast<const EnumTypeEntry>(typeEntry); if (ete->flags()) - writeTypeIndexValueLine(s, api, ete->flags()); + collectTypeEntryTypeIndexes(api, ete->flags(), indexValues); } } -void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api, - const AbstractMetaClass *metaClass) +void HeaderGenerator::collectClassTypeIndexes(const ApiExtractorResult &api, + const AbstractMetaClassCPtr &metaClass, + IndexValues *indexValues) { auto typeEntry = metaClass->typeEntry(); if (!typeEntry->generateCode()) @@ -365,16 +438,16 @@ void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractor // enum indices are required for invisible namespaces as well. for (const AbstractMetaEnum &metaEnum : metaClass->enums()) { if (!metaEnum.isPrivate()) - writeTypeIndexValueLine(s, api, metaEnum.typeEntry()); + collectTypeEntryTypeIndexes(api, metaEnum.typeEntry(), indexValues); } if (NamespaceTypeEntry::isVisibleScope(typeEntry)) - writeTypeIndexValueLine(s, api, metaClass->typeEntry()); + collectTypeEntryTypeIndexes(api, typeEntry, indexValues); } // Format the typedefs for the typedef entries to be generated static void formatTypeDefEntries(TextStream &s) { - QList<const TypedefEntry *> entries; + QList<TypedefEntryCPtr> entries; const auto typeDbEntries = TypeDatabase::instance()->typedefEntries(); for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) { if (it.value()->generateCode() != 0) @@ -383,75 +456,262 @@ static void formatTypeDefEntries(TextStream &s) if (entries.isEmpty()) return; s << "\n// typedef entries\n"; - for (const auto e : entries) { + for (const auto &e : entries) { const QString name = e->qualifiedCppName(); // Fixme: simplify by using nested namespaces in C++ 17. const auto components = QStringView{name}.split(u"::"); - const int nameSpaceCount = components.size() - 1; - for (int n = 0; n < nameSpaceCount; ++n) + const auto nameSpaceCount = components.size() - 1; + for (qsizetype n = 0; n < nameSpaceCount; ++n) s << "namespace " << components.at(n) << " {\n"; s << "using " << components.constLast() << " = " << e->sourceType() << ";\n"; - for (int n = 0; n < nameSpaceCount; ++n) + for (qsizetype n = 0; n < nameSpaceCount; ++n) s << "}\n"; } s << '\n'; } +// Helpers for forward-declaring classes in the module header for the +// specialization of the SbkType template functions. This is possible if the +// class does not have inner types or enums which need to be known. +static bool canForwardDeclare(const AbstractMetaClassCPtr &c) +{ + if (c->isNamespace() || !c->enums().isEmpty() + || !c->innerClasses().isEmpty() || c->isTypeDef()) { + return false; + } + if (auto encl = c->enclosingClass()) + return encl->isNamespace(); + return true; +} -bool HeaderGenerator::finishGeneration() +static void writeForwardDeclaration(TextStream &s, const AbstractMetaClassCPtr &c) { - // Generate the main header for this module. - // This header should be included by binding modules - // extendind on top of this one. - QSet<Include> includes; - StringStream macrosStream(TextStream::Language::Cpp); + Q_ASSERT(!c->isNamespace()); + const bool isStruct = c->attributes().testFlag(AbstractMetaClass::Struct); + s << (isStruct ? "struct " : "class "); + // Do not use name as this can be modified/renamed for target lang. + const QString qualifiedCppName = c->qualifiedCppName(); + const auto lastQualifier = qualifiedCppName.lastIndexOf(u':'); + if (lastQualifier != -1) + s << QStringView{qualifiedCppName}.mid(lastQualifier + 1); + else + s << qualifiedCppName; + s << ";\n"; +} - const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips(); - if (!snips.isEmpty()) { - writeCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration, - TypeSystem::TargetLangCode); +// Helpers for writing out namespaces hierarchically when writing class +// forward declarations to the module header. Ensure inline namespaces +// are marked as such (else clang complains) and namespaces are ordered. +struct NameSpace { + AbstractMetaClassCPtr nameSpace; + AbstractMetaClassCList classes; +}; + +static bool operator<(const NameSpace &n1, const NameSpace &n2) +{ + return n1.nameSpace->name() < n2.nameSpace->name(); +} + +using NameSpaces = QList<NameSpace>; + +static qsizetype indexOf(const NameSpaces &nsps, const AbstractMetaClassCPtr &needle) +{ + for (qsizetype i = 0, count = nsps.size(); i < count; ++i) { + if (nsps.at(i).nameSpace == needle) + return i; } + return -1; +} - macrosStream << "// Type indices\nenum : int {\n"; - AbstractMetaClassCList classList = api().classes(); +static void writeNamespaceForwardDeclarationRecursion(TextStream &s, qsizetype idx, + const NameSpaces &nameSpaces) +{ + auto &root = nameSpaces.at(idx); + s << '\n'; + if (root.nameSpace->isInlineNamespace()) + s << "inline "; + s << "namespace " << root.nameSpace->name() << " {\n" << indent; + for (const auto &c : root.classes) + writeForwardDeclaration(s, c); + + for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) { + if (i != idx && nameSpaces.at(i).nameSpace->enclosingClass() == root.nameSpace) + writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces); + } + s << outdent << "}\n"; +} - std::sort(classList.begin(), classList.end(), [](const AbstractMetaClass *a, const AbstractMetaClass *b) { - return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex(); - }); +static void writeForwardDeclarations(TextStream &s, + const AbstractMetaClassCList &classList) +{ + NameSpaces nameSpaces; - for (const AbstractMetaClass *metaClass : classList) - writeTypeIndexValueLines(macrosStream, api(), metaClass); + s << '\n'; + auto typeSystemEntry = TypeDatabase::instance()->defaultTypeSystemType(); + if (!typeSystemEntry->namespaceBegin().isEmpty()) + s << typeSystemEntry->namespaceBegin() << '\n'; + + for (const auto &c : classList) { + if (auto encl = c->enclosingClass()) { + Q_ASSERT(encl->isNamespace()); + auto idx = indexOf(nameSpaces, encl); + if (idx != -1) { + nameSpaces[idx].classes.append(c); + } else { + nameSpaces.append(NameSpace{encl, {c}}); + for (auto enclNsp = encl->enclosingClass(); enclNsp; + enclNsp = enclNsp->enclosingClass()) { + idx = indexOf(nameSpaces, enclNsp); + if (idx == -1) + nameSpaces.append(NameSpace{enclNsp, {}}); + } + } + } else { + writeForwardDeclaration(s, c); + } + } + + std::sort(nameSpaces.begin(), nameSpaces.end()); + + // Recursively write out namespaces starting at the root elements. + for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) { + const auto &nsp = nameSpaces.at(i); + if (nsp.nameSpace->enclosingClass() == nullptr) + writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces); + } + + if (!typeSystemEntry->namespaceEnd().isEmpty()) + s << typeSystemEntry->namespaceEnd() << '\n'; +} + +// Include parameters required for the module/private module header + +using ConditionalIncludeMap = QMap<QString, IncludeGroup>; + +static TextStream &operator<<(TextStream &s, const ConditionalIncludeMap &m) +{ + for (auto it = m.cbegin(), end = m.cend(); it != end; ++it) + s << it.key() << '\n' << it.value() << "#endif\n"; + return s; +} + +struct ModuleHeaderParameters +{ + AbstractMetaClassCList forwardDeclarations; + std::set<Include> includes; + ConditionalIncludeMap conditionalIncludes; + QString typeFunctions; +}; + +HeaderGenerator::IndexValues + HeaderGenerator::collectTypeIndexes(const AbstractMetaClassCList &classList) +{ + IndexValues result; + + for (const auto &metaClass : classList) + collectClassTypeIndexes(api(), metaClass, &result); for (const AbstractMetaEnum &metaEnum : api().globalEnums()) - writeTypeIndexValueLine(macrosStream, api(), metaEnum.typeEntry()); + collectTypeEntryTypeIndexes(api(), metaEnum.typeEntry(), &result); // Write the smart pointer define indexes. int smartPointerCountIndex = getMaxTypeIndex(); int smartPointerCount = 0; - const AbstractMetaTypeList &instantiatedSmartPtrs = instantiatedSmartPointers(); - for (const AbstractMetaType &metaType : instantiatedSmartPtrs) { - QString indexName = getTypeIndexVariableName(metaType); - _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex); - macrosStream << ", // " << metaType.cppSignature() << '\n'; + for (const auto &smp : api().instantiatedSmartPointers()) { + QString indexName = getTypeIndexVariableName(smp.type); + result.append({indexName, smartPointerCountIndex, smp.type.cppSignature()}); // Add a the same value for const pointees (shared_ptr<const Foo>). - const auto ptrName = metaType.typeEntry()->entryName(); - int pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive); + const auto ptrName = smp.type.typeEntry()->entryName(); + const auto pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive); if (pos >= 0) { - indexName.insert(pos + ptrName.size() + 1, QLatin1String("CONST")); - _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex); - macrosStream << ", // (const)\n"; + indexName.insert(pos + ptrName.size() + 1, u"const"_s); + result.append({indexName, smartPointerCountIndex, "(const)"_L1}); } ++smartPointerCountIndex; ++smartPointerCount; } + result.append({"SBK_"_L1 + moduleName() + "_IDX_COUNT"_L1, + getMaxTypeIndex() + smartPointerCount, {}}); + return result; +} + +HeaderGenerator::IndexValues HeaderGenerator::collectConverterIndexes() const +{ + IndexValues result; + const auto &primitives = primitiveTypes(); + int pCount = 0; + for (const auto &ptype : primitives) { + // Note: do not generate indices for typedef'd primitive types as + // they'll use the primitive type converters instead, so we + // don't need to create any other. + if (ptype->generateCode() && ptype->customConversion() != nullptr) + result.append({getTypeIndexVariableName(ptype), pCount++, {}}); + } - _writeTypeIndexValue(macrosStream, - QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"), - getMaxTypeIndex() + smartPointerCount); - macrosStream << "\n};\n"; + for (const AbstractMetaType &container : api().instantiatedContainers()) { + result.append({getTypeIndexVariableName(container), + pCount++, container.cppSignature()}); + } + + // Because on win32 the compiler will not accept a zero length array. + if (pCount == 0) + pCount++; + result.append({"SBK_"_L1 + moduleName() + "_CONVERTERS_IDX_COUNT"_L1, + pCount, {}}); + return result; +} + +// PYSIDE-2404: Write the enums in unchanged case for reuse in type imports. +// For conpatibility, we create them in uppercase, too and with +// doubled index for emulating the former type-only case. +// +// FIXME: Remove in PySide 7. (See the note in `parser.py`) +// +static IndexValue typeIndexUpper(struct IndexValue const &ti) +{ + QString modi = ti.name.toUpper(); + if (modi == ti.name) + modi = u"// "_s + modi; + return {modi, ti.value * 2, ti.comment}; +} + +bool HeaderGenerator::finishGeneration() +{ + // Generate the main header for this module. This header should be included + // by binding modules extending on top of this one. + ModuleHeaderParameters parameters; + ModuleHeaderParameters privateParameters; + StringStream macrosStream(TextStream::Language::Cpp); + + const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips(); + writeModuleCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration, + TypeSystem::TargetLangCode); + + auto classList = api().classes(); + + std::sort(classList.begin(), classList.end(), + [](const AbstractMetaClassCPtr &a, const AbstractMetaClassCPtr &b) { + return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex(); + }); + + const auto typeIndexes = collectTypeIndexes(classList); + macrosStream << "\n// Type indices\nenum [[deprecated]] : int {\n"; + for (const auto &ti : typeIndexes) + macrosStream << typeIndexUpper(ti); + macrosStream << "};\n"; + + macrosStream << "\n// Type indices\nenum : int {\n"; + for (const auto &ti : typeIndexes) + macrosStream << ti; + macrosStream << "};\n\n"; + + // FIXME: Remove backwards compatible variable in PySide 7. macrosStream << "// This variable stores all Python types exported by this module.\n"; - macrosStream << "extern PyTypeObject **" << cppApiVariableName() << ";\n\n"; + macrosStream << "extern Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << ";\n\n"; + macrosStream << "// This variable stores all Python types exported by this module "; + macrosStream << "in a backwards compatible way with identical indexing.\n"; + macrosStream << "[[deprecated]] extern PyTypeObject **" << cppApiVariableNameOld() << ";\n\n"; macrosStream << "// This variable stores the Python module object exported by this module.\n"; macrosStream << "extern PyObject *" << pythonModuleObjectName() << ";\n\n"; macrosStream << "// This variable stores all type converters exported by this module.\n"; @@ -459,33 +719,16 @@ bool HeaderGenerator::finishGeneration() // TODO-CONVERTER ------------------------------------------------------------------------------ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex(). - macrosStream << "// Converter indices\nenum : int {\n"; - const PrimitiveTypeEntryList &primitives = primitiveTypes(); - int pCount = 0; - for (const PrimitiveTypeEntry *ptype : primitives) { - /* Note: do not generate indices for typedef'd primitive types - * as they'll use the primitive type converters instead, so we - * don't need to create any other. - */ - if (!ptype->generateCode() || !ptype->customConversion()) - continue; - - _writeTypeIndexValueLine(macrosStream, getTypeIndexVariableName(ptype), pCount++); - } - - const AbstractMetaTypeList &containers = instantiatedContainers(); - for (const AbstractMetaType &container : containers) { - _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount); - macrosStream << ", // " << container.cppSignature() << '\n'; - pCount++; - } + const auto converterIndexes = collectConverterIndexes(); + macrosStream << "// Converter indices\nenum [[deprecated]] : int {\n"; + for (const auto &ci : converterIndexes) + macrosStream << typeIndexUpper(ci); + macrosStream << "};\n\n"; - // Because on win32 the compiler will not accept a zero length array. - if (pCount == 0) - pCount++; - _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT") - .arg(moduleName()), pCount); - macrosStream << "\n};\n"; + macrosStream << "// Converter indices\nenum : int {\n"; + for (const auto &ci : converterIndexes) + macrosStream << ci; + macrosStream << "};\n"; formatTypeDefEntries(macrosStream); @@ -493,53 +736,64 @@ bool HeaderGenerator::finishGeneration() macrosStream << "// Macros for type check\n"; - StringStream typeFunctions(TextStream::Language::Cpp); - if (usePySideExtensions()) { - typeFunctions << "QT_WARNING_PUSH\n"; - typeFunctions << "QT_WARNING_DISABLE_DEPRECATED\n"; - } + TextStream typeFunctions(¶meters.typeFunctions, TextStream::Language::Cpp); + TextStream privateTypeFunctions(&privateParameters.typeFunctions, TextStream::Language::Cpp); + for (const AbstractMetaEnum &cppEnum : api().globalEnums()) { if (!cppEnum.isAnonymous()) { - includes << cppEnum.typeEntry()->include(); + const auto te = cppEnum.typeEntry(); + if (te->hasConfigCondition()) + parameters.conditionalIncludes[te->configCondition()].append(te->include()); + else + parameters.includes.insert(cppEnum.typeEntry()->include()); writeSbkTypeFunction(typeFunctions, cppEnum); } } StringStream protEnumsSurrogates(TextStream::Language::Cpp); - for (auto metaClass : classList) { - if (!shouldGenerate(metaClass)) + for (const auto &metaClass : classList) { + const auto classType = metaClass->typeEntry(); + if (!shouldGenerate(classType)) continue; - //Includes - const TypeEntry *classType = metaClass->typeEntry(); - includes << classType->include(); + // Includes + const bool isPrivate = classType->isPrivate(); + auto &par = isPrivate ? privateParameters : parameters; + const auto classInclude = classType->include(); + const bool hasConfigCondition = classType->hasConfigCondition(); + if (leanHeaders() && canForwardDeclare(metaClass)) + par.forwardDeclarations.append(metaClass); + else if (hasConfigCondition) + par.conditionalIncludes[classType->configCondition()].append(classInclude); + else + par.includes.insert(classInclude); + + auto &typeFunctionsStr = isPrivate ? privateTypeFunctions : typeFunctions; + ConfigurableScope configScope(typeFunctionsStr, classType); for (const AbstractMetaEnum &cppEnum : metaClass->enums()) { if (cppEnum.isAnonymous() || cppEnum.isPrivate()) continue; - EnumTypeEntry *enumType = cppEnum.typeEntry(); - includes << enumType->include(); + if (const auto inc = cppEnum.typeEntry()->include(); inc != classInclude) + par.includes.insert(inc); writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); - writeSbkTypeFunction(typeFunctions, cppEnum); + writeSbkTypeFunction(typeFunctionsStr, cppEnum); } if (!metaClass->isNamespace()) - writeSbkTypeFunction(typeFunctions, metaClass); + writeSbkTypeFunction(typeFunctionsStr, metaClass); } - for (const AbstractMetaType &metaType : instantiatedSmartPtrs) { - const TypeEntry *classType = metaType.typeEntry(); - includes << classType->include(); - writeSbkTypeFunction(typeFunctions, metaType); + for (const auto &smp : api().instantiatedSmartPointers()) { + parameters.includes.insert(smp.type.typeEntry()->include()); + writeSbkTypeFunction(typeFunctions, smp.type); } - if (usePySideExtensions()) - typeFunctions << "QT_WARNING_POP\n"; - QString moduleHeaderFileName(outputDirectory() - + QDir::separator() + subDirectoryForPackage(packageName()) - + QDir::separator() + getModuleHeaderFileName()); + const QString moduleHeaderDir = outputDirectory() + u'/' + + subDirectoryForPackage(packageName()) + u'/'; + const QString moduleHeaderFileName(moduleHeaderDir + getModuleHeaderFileName()); - QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H")); + QString includeShield(u"SBK_"_s + moduleName().toUpper() + u"_PYTHON_H"_s); FileOut file(moduleHeaderFileName); TextStream &s = file.stream; @@ -556,34 +810,40 @@ bool HeaderGenerator::finishGeneration() } s << "#include <sbkpython.h>\n"; + s << "#include <sbkmodule.h>\n"; s << "#include <sbkconverter.h>\n"; QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports(); if (!requiredTargetImports.isEmpty()) { s << "// Module Includes\n"; - for (const QString &requiredModule : qAsConst(requiredTargetImports)) + for (const QString &requiredModule : std::as_const(requiredTargetImports)) s << "#include <" << getModuleHeaderFileName(requiredModule) << ">\n"; s<< '\n'; } s << "// Bound library includes\n"; - for (const Include &include : qAsConst(includes)) + for (const Include &include : parameters.includes) s << include; + s << parameters.conditionalIncludes; - if (!primitiveTypes().isEmpty()) { - s << "// Conversion Includes - Primitive Types\n"; - const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); - for (const PrimitiveTypeEntry *ptype : primitiveTypeList) - s << ptype->include(); - s<< '\n'; - } + if (leanHeaders()) { + writeForwardDeclarations(s, parameters.forwardDeclarations); + } else { + if (!primitiveTypes().isEmpty()) { + s << "// Conversion Includes - Primitive Types\n"; + const auto &primitiveTypeList = primitiveTypes(); + for (const auto &ptype : primitiveTypeList) + s << ptype->include(); + s<< '\n'; + } - if (!containerTypes().isEmpty()) { - s << "// Conversion Includes - Container Types\n"; - const ContainerTypeEntryList &containerTypeList = containerTypes(); - for (const ContainerTypeEntry *ctype : containerTypeList) - s << ctype->include(); - s<< '\n'; + if (!containerTypes().isEmpty()) { + s << "// Conversion Includes - Container Types\n"; + const ContainerTypeEntryCList &containerTypeList = containerTypes(); + for (const auto &ctype : containerTypeList) + s << ctype->include(); + s<< '\n'; + } } s << macrosStream.toString() << '\n'; @@ -593,45 +853,112 @@ bool HeaderGenerator::finishGeneration() << protEnumsSurrogates.toString() << '\n'; } + writeTypeFunctions(s, parameters.typeFunctions); + + s << "#endif // " << includeShield << "\n\n"; + + file.done(); + + if (hasPrivateClasses()) + writePrivateHeader(moduleHeaderDir, includeShield, privateParameters); + + return true; +} + +void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir, + const QString &publicIncludeShield, + const ModuleHeaderParameters ¶meters) +{ + // 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) + "_P_H"_L1; + + ps << licenseComment()<< "\n\n"; + + ps << "#ifndef " << privateIncludeShield << '\n'; + ps << "#define " << privateIncludeShield << "\n\n"; + + for (const Include &include : parameters.includes) + ps << include; + ps << parameters.conditionalIncludes; + ps << '\n'; + + if (leanHeaders()) + writeForwardDeclarations(ps, parameters.forwardDeclarations); + + writeTypeFunctions(ps, parameters.typeFunctions); + + ps << "#endif\n"; + privateFile.done(); +} + +void HeaderGenerator::writeTypeFunctions(TextStream &s, const QString &typeFunctions) +{ + if (typeFunctions.isEmpty()) + return; + + if (usePySideExtensions()) + s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n"; + s << "namespace Shiboken\n{\n\n" << "// PyType functions, to get the PyObjectType for a type T\n" - << typeFunctions.toString() << '\n' - << "} // namespace Shiboken\n\n" - << "#endif // " << includeShield << "\n\n"; + << typeFunctions << '\n' + << "} // namespace Shiboken\n\n"; - return file.done() != FileOut::Failure; + if (usePySideExtensions()) + s << "QT_WARNING_POP\n"; } -void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) const +void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) { if (avoidProtectedHack() && cppEnum.isProtected()) s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};\n"; } -void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum) const +void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum) { const QString enumName = avoidProtectedHack() && cppEnum.isProtected() ? protectedEnumSurrogateName(cppEnum) : cppEnum.qualifiedCppName(); + const auto te = cppEnum.typeEntry(); + ConfigurableScope configScope(s, te); + s << "template<> inline PyTypeObject *SbkType< " << m_gsp << enumName << " >() "; + s << "{ return " << cpythonTypeNameExt(te) << "; }\n"; - s << "template<> inline PyTypeObject *SbkType< ::" << enumName << " >() "; - s << "{ return " << cpythonTypeNameExt(cppEnum.typeEntry()) << "; }\n"; - - FlagsTypeEntry *flag = cppEnum.typeEntry()->flags(); + const auto flag = cppEnum.typeEntry()->flags(); if (flag) { - s << "template<> inline PyTypeObject *SbkType< ::" << flag->name() << " >() " + s << "template<> inline PyTypeObject *SbkType< " << m_gsp << flag->name() << " >() " << "{ return " << cpythonTypeNameExt(flag) << "; }\n"; } } -void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClass *cppClass) +void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass) { - s << "template<> inline PyTypeObject *SbkType< ::" << cppClass->qualifiedCppName() << " >() " - << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n"; + s << "template<> inline PyTypeObject *SbkType< " + << getFullTypeName(cppClass) << " >() " + << "{ return " << cpythonTypeNameExt(cppClass->typeEntry()) << "; }\n"; } void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType) { - s << "template<> inline PyTypeObject *SbkType< ::" << metaType.cppSignature() << " >() " - << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(metaType) << "); }\n"; + s << "template<> inline PyTypeObject *SbkType< " + << m_gsp << metaType.cppSignature() << " >() " + << "{ return " << cpythonTypeNameExt(metaType) << "; }\n"; +} + +void HeaderGenerator::writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language) const +{ + if (!codeSnips.isEmpty()) { + try { + writeCodeSnips(s, codeSnips, position, language); + } catch (const std::exception &e) { + throw Exception(msgSnippetError("module header of "_L1 + moduleName(), e.what())); + } + } } |