// 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 "generatorcontext.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "containertypeentry.h" #include "enumtypeentry.h" #include "flagstypeentry.h" #include "namespacetypeentry.h" #include "primitivetypeentry.h" #include "typedefentry.h" #include "typesystemtypeentry.h" #include "qtcompat.h" #include #include #include #include #include using namespace Qt::StringLiterals; // 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; } QString HeaderGenerator::headerFileNameForContext(const GeneratorContext &context) { return fileNameForContextHelper(context, u"_wrapper.h"_s); } QString HeaderGenerator::fileNameForContext(const GeneratorContext &context) const { return headerFileNameForContext(context); } void HeaderGenerator::writeCopyCtor(TextStream &s, const AbstractMetaClass *metaClass) const { s << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self) : " << metaClass->qualifiedCppName() << "(self)\n{\n}\n\n"; } static void writeProtectedEnums(TextStream &s, const AbstractMetaClass *metaClass) { const QString name = metaClass->qualifiedCppName(); for (const auto &e : metaClass->enums()) { if (e.isProtected()) s << "using " << name << "::" << e.name() << ";\n"; } } void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContextIn) { GeneratorContext classContext = classContextIn; const AbstractMetaClass *metaClass = classContext.metaClass(); m_inheritedOverloads.clear(); // write license comment s << licenseComment(); QString wrapperName = classContext.effectiveClassName(); QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper(); QString innerHeaderGuard; // Header s << "#ifndef SBK_" << outerHeaderGuard << "_H\n"; s << "#define SBK_" << outerHeaderGuard << "_H\n\n"; if (!avoidProtectedHack()) s << "#define protected public\n\n"; //Includes auto typeEntry = metaClass->typeEntry(); s << typeEntry->include() << '\n'; for (auto &inst : metaClass->templateBaseClassInstantiations()) s << inst.typeEntry()->include(); if (classContext.useWrapper() && avoidProtectedHack()) { const auto includeGroups = classIncludes(metaClass); for( const auto &includeGroup : includeGroups) s << includeGroup; } if (classContext.useWrapper() && usePySideExtensions() && metaClass->isQObject()) 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"; } // 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; }); } 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'; } int maxOverrides = 0; for (const auto &func : metaClass->functions()) { const auto generation = functionGeneration(func); writeFunction(s, func, 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 << "();\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; void *qt_metacast(const char *_clname) override; )"; } if (!m_inheritedOverloads.isEmpty()) { s << "// Inherited overloads, because the using keyword sux\n"; for (const auto &func : std::as_const(m_inheritedOverloads)) writeMemberFunctionWrapper(s, func); m_inheritedOverloads.clear(); } 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); wrapperName = classContext.effectiveClassName(); innerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper(); } s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n"; } // Write an inline wrapper around a function void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s, const AbstractMetaFunctionCPtr &func, const QString &postfix) const { Q_ASSERT(!func->isConstructor() && !func->isOperatorOverload()); s << "inline "; if (func->isStatic()) s << "static "; s << functionSignature(func, {}, postfix, Generator::OriginalTypeDescription) << " { "; if (!func->isVoid()) s << "return "; if (!func->isAbstract()) { // Use implementingClass() in case of multiple inheritance (for example // function setProperty() being inherited from QObject and // QDesignerPropertySheetExtension). auto klass = func->implementingClass(); if (klass == nullptr) klass = func->ownerClass(); s << klass->qualifiedCppName() << "::"; } s << func->originalName() << '('; const AbstractMetaArgumentList &arguments = func->arguments(); for (qsizetype i = 0, size = arguments.size(); i < size; ++i) { if (i > 0) s << ", "; const AbstractMetaArgument &arg = arguments.at(i); const auto &type = arg.type(); const TypeEntry *enumTypeEntry = nullptr; if (type.isFlags()) enumTypeEntry = static_cast(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, FunctionGeneration generation) { // do not write copy ctors here. if (generation.testFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor)) { writeCopyCtor(s, func->ownerClass()); return; } if (generation.testFlag(FunctionGenerationFlag::ProtectedWrapper)) writeMemberFunctionWrapper(s, func, u"_protected"_s); if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor)) { Options option = func->hasSignatureModifications() ? Generator::OriginalTypeDescription : Generator::NoOption; s << functionSignature(func, {}, {}, option) << ";\n"; return; } const bool isVirtual = generation.testFlag(FunctionGenerationFlag::VirtualMethod); if (isVirtual || generation.testFlag(FunctionGenerationFlag::QMetaObjectMethod)) { s << functionSignature(func, {}, {}, Generator::OriginalTypeDescription) << " override;\n"; } // Check if this method hide other methods in base classes if (isVirtual) { for (const auto &f : func->ownerClass()->functions()) { if (f != func && !f->isConstructor() && !f->isPrivate() && !f->isVirtual() && !f->isAbstract() && !f->isStatic() && f->name() == func->name()) { m_inheritedOverloads << f; } } // TODO: when modified an abstract method ceases to be virtual but stays abstract //if (func->isModifiedRemoved() && func->isAbstract()) { //} } } 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) { _writeTypeIndexValue(s, variableName, typeIndex); s << ",\n"; } // Find equivalent typedefs "using Foo=QList", "using Bar=QList" static const AbstractMetaClass * findEquivalentTemplateTypedef(const AbstractMetaClassCList &haystack, const AbstractMetaClass *needle) { auto *templateBaseClass = needle->templateBaseClass(); const auto &instantiations = needle->templateBaseClassInstantiations(); for (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) { if (!typeEntry || !typeEntry->generateCode()) return; s.setFieldAlignment(QTextStream::AlignLeft); const int typeIndex = typeEntry->sbkIndex(); _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex); if (typeEntry->isComplex()) { // For a typedef "using Foo=QList", 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 = static_cast(typeEntry); if (cType->baseContainerType()) { auto metaClass = AbstractMetaClass::findClass(api.classes(), cType); Q_ASSERT(metaClass != nullptr); if (metaClass->isTypeDef() && metaClass->templateBaseClass() != nullptr && findEquivalentTemplateTypedef(m_alternateTemplateIndexes, metaClass) == nullptr) { const QString indexVariable = getTypeAlternateTemplateIndexVariableName(metaClass); _writeTypeIndexValueLine(s, indexVariable, typeIndex); m_alternateTemplateIndexes.append(m_alternateTemplateIndexes); } } } if (typeEntry->isEnum()) { auto ete = static_cast(typeEntry); if (ete->flags()) writeTypeIndexValueLine(s, api, ete->flags()); } } void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api, const AbstractMetaClass *metaClass) { auto typeEntry = metaClass->typeEntry(); if (!typeEntry->generateCode()) return; // enum indices are required for invisible namespaces as well. for (const AbstractMetaEnum &metaEnum : metaClass->enums()) { if (!metaEnum.isPrivate()) writeTypeIndexValueLine(s, api, metaEnum.typeEntry()); } if (NamespaceTypeEntry::isVisibleScope(typeEntry)) writeTypeIndexValueLine(s, api, typeEntry); } // Format the typedefs for the typedef entries to be generated static void formatTypeDefEntries(TextStream &s) { QList entries; const auto typeDbEntries = TypeDatabase::instance()->typedefEntries(); for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) { if (it.value()->generateCode() != 0) entries.append(it.value()); } if (entries.isEmpty()) return; s << "\n// typedef entries\n"; 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 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 (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 AbstractMetaClass *c) { if (c->isNamespace() || !c->enums().isEmpty() || !c->innerClasses().isEmpty() || c->isTypeDef()) { return false; } if (auto *encl = c->enclosingClass()) return encl->isNamespace(); return true; } static void writeForwardDeclaration(TextStream &s, const AbstractMetaClass *c) { 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"; } // 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 { const AbstractMetaClass *nameSpace; AbstractMetaClassCList classes; }; static bool operator<(const NameSpace &n1, const NameSpace &n2) { return n1.nameSpace->name() < n2.nameSpace->name(); } using NameSpaces = QList; static qsizetype indexOf(const NameSpaces &nsps, const AbstractMetaClass *needle) { for (qsizetype i = 0, count = nsps.size(); i < count; ++i) { if (nsps.at(i).nameSpace == needle) return i; } return -1; } 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 (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"; } static void writeForwardDeclarations(TextStream &s, const AbstractMetaClassCList &classList) { NameSpaces nameSpaces; for (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 != nullptr; 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); } } bool HeaderGenerator::finishGeneration() { // Generate the main header for this module. // This header should be included by binding modules // extendind on top of this one. AbstractMetaClassCList forwardDeclarations; AbstractMetaClassCList privateForwardDeclarations; QSet includes; QSet privateIncludes; StringStream macrosStream(TextStream::Language::Cpp); const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips(); if (!snips.isEmpty()) { writeCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::TargetLangCode); } macrosStream << "// Type indices\nenum : int {\n"; auto classList = api().classes(); std::sort(classList.begin(), classList.end(), [](const AbstractMetaClass *a, const AbstractMetaClass *b) { return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex(); }); for (const AbstractMetaClass *metaClass : classList) writeTypeIndexValueLines(macrosStream, api(), metaClass); for (const AbstractMetaEnum &metaEnum : api().globalEnums()) writeTypeIndexValueLine(macrosStream, api(), metaEnum.typeEntry()); // Write the smart pointer define indexes. int smartPointerCountIndex = getMaxTypeIndex(); int smartPointerCount = 0; for (const auto &smp : api().instantiatedSmartPointers()) { QString indexName = getTypeIndexVariableName(smp.type); _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex); macrosStream << ", // " << smp.type.cppSignature() << '\n'; // Add a the same value for const pointees (shared_ptr). const auto ptrName = smp.type.typeEntry()->entryName(); int pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive); if (pos >= 0) { indexName.insert(pos + ptrName.size() + 1, u"CONST"_s); _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex); macrosStream << ", // (const)\n"; } ++smartPointerCountIndex; ++smartPointerCount; } _writeTypeIndexValue(macrosStream, u"SBK_"_s + moduleName() + u"_IDX_COUNT"_s, getMaxTypeIndex() + smartPointerCount); macrosStream << "\n};\n"; macrosStream << "// This variable stores all Python types exported by this module.\n"; macrosStream << "extern PyTypeObject **" << cppApiVariableName() << ";\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"; macrosStream << "extern SbkConverter **" << convertersVariableName() << ";\n\n"; // TODO-CONVERTER ------------------------------------------------------------------------------ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex(). macrosStream << "// Converter indices\nenum : int {\n"; const auto &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++); } for (const AbstractMetaType &container : api().instantiatedContainers()) { _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount); macrosStream << ", // " << container.cppSignature() << '\n'; pCount++; } // 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"; formatTypeDefEntries(macrosStream); // TODO-CONVERTER ------------------------------------------------------------------------------ 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"; } for (const AbstractMetaEnum &cppEnum : api().globalEnums()) { if (!cppEnum.isAnonymous()) { includes << cppEnum.typeEntry()->include(); writeSbkTypeFunction(typeFunctions, cppEnum); } } StringStream protEnumsSurrogates(TextStream::Language::Cpp); for (auto metaClass : classList) { const TypeEntry *classType = metaClass->typeEntry(); if (!shouldGenerate(classType)) continue; //Includes const bool isPrivate = classType->isPrivate(); auto &includeList = isPrivate ? privateIncludes : includes; auto &forwardList = isPrivate ? privateForwardDeclarations : forwardDeclarations; if (leanHeaders() && canForwardDeclare(metaClass)) forwardList.append(metaClass); else includeList << classType->include(); auto &typeFunctionsStr = isPrivate ? privateTypeFunctions : typeFunctions; for (const AbstractMetaEnum &cppEnum : metaClass->enums()) { if (cppEnum.isAnonymous() || cppEnum.isPrivate()) continue; EnumTypeEntry *enumType = cppEnum.typeEntry(); includeList << enumType->include(); writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum); writeSbkTypeFunction(typeFunctionsStr, cppEnum); } if (!metaClass->isNamespace()) writeSbkTypeFunction(typeFunctionsStr, metaClass); } for (const auto &smp : api().instantiatedSmartPointers()) { const TypeEntry *classType = smp.type.typeEntry(); includes << classType->include(); writeSbkTypeFunction(typeFunctions, smp.type); } if (usePySideExtensions()) typeFunctions << "QT_WARNING_POP\n"; const QString moduleHeaderDir = outputDirectory() + u'/' + subDirectoryForPackage(packageName()) + u'/'; const QString moduleHeaderFileName(moduleHeaderDir + getModuleHeaderFileName()); QString includeShield(u"SBK_"_s + moduleName().toUpper() + u"_PYTHON_H"_s); FileOut file(moduleHeaderFileName); TextStream &s = file.stream; s.setLanguage(TextStream::Language::Cpp); // write license comment s << licenseComment()<< "\n\n"; s << "#ifndef " << includeShield<< '\n'; s << "#define " << includeShield<< "\n\n"; if (!avoidProtectedHack()) { s << "//workaround to access protected functions\n"; s << "#define protected public\n\n"; } s << "#include \n"; s << "#include \n"; QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports(); if (!requiredTargetImports.isEmpty()) { s << "// Module Includes\n"; for (const QString &requiredModule : std::as_const(requiredTargetImports)) s << "#include <" << getModuleHeaderFileName(requiredModule) << ">\n"; s<< '\n'; } s << "// Bound library includes\n"; for (const Include &include : std::as_const(includes)) s << include; if (leanHeaders()) { writeForwardDeclarations(s, forwardDeclarations); } else { if (!primitiveTypes().isEmpty()) { s << "// Conversion Includes - Primitive Types\n"; const auto &primitiveTypeList = primitiveTypes(); for (const PrimitiveTypeEntry *ptype : primitiveTypeList) s << ptype->include(); s<< '\n'; } if (!containerTypes().isEmpty()) { s << "// Conversion Includes - Container Types\n"; const ContainerTypeEntryCList &containerTypeList = containerTypes(); for (const ContainerTypeEntry *ctype : containerTypeList) s << ctype->include(); s<< '\n'; } } s << macrosStream.toString() << '\n'; if (protEnumsSurrogates.size() > 0) { s << "// Protected enum surrogates\n" << protEnumsSurrogates.toString() << '\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"; file.done(); if (hasPrivateClasses()) { writePrivateHeader(moduleHeaderDir, includeShield, privateIncludes, privateForwardDeclarations, privateTypeFunctions.toString()); } return true; } void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir, const QString &publicIncludeShield, const QSet &privateIncludes, const AbstractMetaClassCList &forwardDeclarations, 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 : std::as_const(privateIncludes)) ps << include; ps << '\n'; if (leanHeaders()) writeForwardDeclarations(ps, forwardDeclarations); 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"; privateFile.done(); } void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) const { if (avoidProtectedHack() && cppEnum.isProtected()) s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};\n"; } void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum) const { const QString enumName = avoidProtectedHack() && cppEnum.isProtected() ? protectedEnumSurrogateName(cppEnum) : cppEnum.qualifiedCppName(); s << "template<> inline PyTypeObject *SbkType< ::" << enumName << " >() "; s << "{ return " << cpythonTypeNameExt(cppEnum.typeEntry()) << "; }\n"; FlagsTypeEntry *flag = cppEnum.typeEntry()->flags(); if (flag) { s << "template<> inline PyTypeObject *SbkType< ::" << flag->name() << " >() " << "{ return " << cpythonTypeNameExt(flag) << "; }\n"; } } void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClass *cppClass) { s << "template<> inline PyTypeObject *SbkType< ::" << cppClass->qualifiedCppName() << " >() " << "{ return reinterpret_cast(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n"; } void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType) { s << "template<> inline PyTypeObject *SbkType< ::" << metaType.cppSignature() << " >() " << "{ return " << cpythonTypeNameExt(metaType) << "; }\n"; }