diff options
Diffstat (limited to 'sources/shiboken6/generator/shiboken/shibokengenerator.cpp')
-rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 1015 |
1 files changed, 685 insertions, 330 deletions
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 264c8cfea..a1417e5d9 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -2,8 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "shibokengenerator.h" +#include "generatorstrings.h" +#include "generatorargument.h" +#include "defaultvalue.h" +#include "generatorcontext.h" #include "apiextractorresult.h" #include "codesnip.h" +#include "customconversion.h" #include "ctypenames.h" #include <abstractmetabuilder.h> #include <abstractmetaenum.h> @@ -16,12 +21,12 @@ #include <messages.h> #include <modifications.h> #include "overloaddata.h" +#include <optionsparser.h> #include "propertyspec.h" #include "pytypenames.h" #include <reporthandler.h> #include <textstream.h> #include <typedatabase.h> -#include <abstractmetabuilder.h> #include <containertypeentry.h> #include <customtypenentry.h> #include <enumtypeentry.h> @@ -29,6 +34,8 @@ #include <namespacetypeentry.h> #include <primitivetypeentry.h> #include <pythontypeentry.h> +#include <smartpointertypeentry.h> +#include <valuetypeentry.h> #include <iostream> @@ -37,43 +44,73 @@ #include <QtCore/QDir> #include <QtCore/QDebug> #include <QtCore/QRegularExpression> + +#include <algorithm> #include <limits> #include <memory> +#include <utility> using namespace Qt::StringLiterals; -static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic"; -static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic"; -static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages"; -static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero"; -static const char USE_OPERATOR_BOOL_AS_NB_NONZERO[] = "use-operator-bool-as-nb_nonzero"; -static const char WRAPPER_DIAGNOSTICS[] = "wrapper-diagnostics"; -static const char NO_IMPLICIT_CONVERSIONS[] = "no-implicit-conversions"; - -const QString CPP_ARG = u"cppArg"_s; -const QString CPP_ARG_REMOVED = u"removed_cppArg"_s; -const QString CPP_RETURN_VAR = u"cppResult"_s; -const QString CPP_SELF_VAR = u"cppSelf"_s; -const QString NULL_PTR = u"nullptr"_s; -const QString PYTHON_ARG = u"pyArg"_s; -const QString PYTHON_ARGS = u"pyArgs"_s; -const QString PYTHON_OVERRIDE_VAR = u"pyOverride"_s; -const QString PYTHON_RETURN_VAR = u"pyResult"_s; -const QString PYTHON_TO_CPP_VAR = u"pythonToCpp"_s; -const QString SMART_POINTER_GETTER = u"kSmartPointerGetter"_s; - -const QString CONV_RULE_OUT_VAR_SUFFIX = u"_out"_s; -const QString BEGIN_ALLOW_THREADS = - u"PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"_s; -const QString END_ALLOW_THREADS = u"PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"_s; +static constexpr auto PARENT_CTOR_HEURISTIC = "enable-parent-ctor-heuristic"_L1; +static constexpr auto RETURN_VALUE_HEURISTIC = "enable-return-value-heuristic"_L1; +static constexpr auto DISABLE_VERBOSE_ERROR_MESSAGES = "disable-verbose-error-messages"_L1; +static constexpr auto USE_ISNULL_AS_NB_BOOL = "use-isnull-as-nb-bool"_L1; +// FIXME PYSIDE 7: Remove USE_ISNULL_AS_NB_NONZERO/USE_OPERATOR_BOOL_AS_NB_NONZERO +static constexpr auto USE_ISNULL_AS_NB_NONZERO = "use-isnull-as-nb_nonzero"_L1; +static constexpr auto USE_OPERATOR_BOOL_AS_NB_BOOL = "use-operator-bool-as-nb-bool"_L1; +static constexpr auto USE_OPERATOR_BOOL_AS_NB_NONZERO = "use-operator-bool-as-nb-nonzero"_L1; +static constexpr auto WRAPPER_DIAGNOSTICS = "wrapper-diagnostics"_L1; +static constexpr auto NO_IMPLICIT_CONVERSIONS = "no-implicit-conversions"_L1; +static constexpr auto LEAN_HEADERS = "lean-headers"_L1; + +QString CPP_ARG_N(int i) +{ + return CPP_ARG + QString::number(i); +} + +constexpr auto CPP_ARG_REMOVED_PREFIX = "removed_cppArg"_L1; + +QString CPP_ARG_REMOVED(int i) +{ + return CPP_ARG_REMOVED_PREFIX + QString::number(i); +} + +const char *const METHOD_DEF_SENTINEL = "{nullptr, nullptr, 0, nullptr} // Sentinel\n"; +const char *const PYTHON_TO_CPPCONVERSION_STRUCT = "Shiboken::Conversions::PythonToCppConversion"; + +const char *const openTargetExternC = R"( +// Target --------------------------------------------------------- + +extern "C" { +)"; +const char *const closeExternC = "} // extern \"C\"\n\n"; +const char *const richCompareComment = + "// PYSIDE-74: By default, we redirect to object's tp_richcompare (which is `==`, `!=`).\n"; + +struct ShibokenGeneratorOptions +{ + bool useCtorHeuristic = false; + bool userReturnValueHeuristic = false; + bool verboseErrorMessagesDisabled = false; + bool useIsNullAsNbBool = false; + // FIXME PYSIDE 7 Flip m_leanHeaders default or remove? + bool leanHeaders = false; + bool useOperatorBoolAsNbBool = false; + // FIXME PYSIDE 7 Flip generateImplicitConversions default or remove? + bool generateImplicitConversions = true; + bool wrapperDiagnostics = false; +}; struct GeneratorClassInfoCacheEntry { ShibokenGenerator::FunctionGroups functionGroups; + QList<AbstractMetaFunctionCList> numberProtocolOperators; + BoolCastFunctionOptional boolCastFunctionO; bool needsGetattroFunction = false; }; -using GeneratorClassInfoCache = QHash<const AbstractMetaClass *, GeneratorClassInfoCacheEntry>; +using GeneratorClassInfoCache = QHash<AbstractMetaClassCPtr, GeneratorClassInfoCacheEntry>; Q_GLOBAL_STATIC(GeneratorClassInfoCache, generatorClassInfoCache) @@ -97,6 +134,10 @@ const ShibokenGenerator::TypeSystemConverterRegExps & return result; } +// Options are static to avoid duplicated handling since ShibokenGenerator +// is instantiated for HeaderGenerator and CppGenerator. +ShibokenGeneratorOptions ShibokenGenerator::m_options; + ShibokenGenerator::ShibokenGenerator() = default; ShibokenGenerator::~ShibokenGenerator() = default; @@ -105,32 +146,32 @@ ShibokenGenerator::~ShibokenGenerator() = default; static const QHash<QString, QString> &primitiveTypesCorrespondences() { static const QHash<QString, QString> result = { - {u"bool"_s, pyBoolT()}, - {u"char"_s, sbkCharT()}, - {u"signed char"_s, sbkCharT()}, - {u"unsigned char"_s, sbkCharT()}, - {intT(), pyIntT()}, - {u"signed int"_s, pyIntT()}, - {u"uint"_s, pyIntT()}, - {u"unsigned int"_s, pyIntT()}, - {shortT(), pyIntT()}, - {u"ushort"_s, pyIntT()}, - {u"signed short"_s, pyIntT()}, - {u"signed short int"_s, pyIntT()}, - {unsignedShortT(), pyIntT()}, - {u"unsigned short int"_s, pyIntT()}, - {longT(), pyIntT()}, - {doubleT(), pyFloatT()}, - {floatT(), pyFloatT()}, - {u"unsigned long"_s, pyLongT()}, - {u"signed long"_s, pyLongT()}, - {u"ulong"_s, pyLongT()}, - {u"unsigned long int"_s, pyLongT()}, - {u"long long"_s, pyLongT()}, - {u"__int64"_s, pyLongT()}, - {u"unsigned long long"_s, pyLongT()}, - {u"unsigned __int64"_s, pyLongT()}, - {u"size_t"_s, pyLongT()} + {u"bool"_s, pyBoolT}, + {u"char"_s, sbkCharT}, + {u"signed char"_s, sbkCharT}, + {u"unsigned char"_s, sbkCharT}, + {intT, pyLongT}, + {u"signed int"_s, pyLongT}, + {u"uint"_s, pyLongT}, + {u"unsigned int"_s, pyLongT}, + {shortT, pyLongT}, + {u"ushort"_s, pyLongT}, + {u"signed short"_s, pyLongT}, + {u"signed short int"_s, pyLongT}, + {unsignedShortT, pyLongT}, + {u"unsigned short int"_s, pyLongT}, + {longT, pyLongT}, + {doubleT, pyFloatT}, + {floatT, pyFloatT}, + {u"unsigned long"_s, pyLongT}, + {u"signed long"_s, pyLongT}, + {u"ulong"_s, pyLongT}, + {u"unsigned long int"_s, pyLongT}, + {u"long long"_s, pyLongT}, + {u"__int64"_s, pyLongT}, + {u"unsigned long long"_s, pyLongT}, + {u"unsigned __int64"_s, pyLongT}, + {u"size_t"_s, pyLongT} }; return result; } @@ -140,24 +181,24 @@ const QHash<QString, QChar> &ShibokenGenerator::formatUnits() static const QHash<QString, QChar> result = { {u"char"_s, u'b'}, {u"unsigned char"_s, u'B'}, - {intT(), u'i'}, + {intT, u'i'}, {u"unsigned int"_s, u'I'}, - {shortT(), u'h'}, - {unsignedShortT(), u'H'}, - {longT(), u'l'}, - {unsignedLongLongT(), u'k'}, - {longLongT(), u'L'}, + {shortT, u'h'}, + {unsignedShortT, u'H'}, + {longT, u'l'}, + {unsignedLongLongT, u'k'}, + {longLongT, u'L'}, {u"__int64"_s, u'L'}, - {unsignedLongLongT(), u'K'}, + {unsignedLongLongT, u'K'}, {u"unsigned __int64"_s, u'K'}, - {doubleT(), u'd'}, - {floatT(), u'f'}, + {doubleT, u'd'}, + {floatT, u'f'}, }; return result; } QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType &cType, - const AbstractMetaClass *context, + const AbstractMetaClassCPtr &context, Options options) const { if (cType.isArray()) { @@ -174,7 +215,7 @@ QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType return translateType(cType, context, options); } -bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaClass) const +bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass) { const auto wrapper = metaClass->cppWrapper(); return wrapper.testFlag(AbstractMetaClass::CppVirtualMethodWrapper) @@ -182,8 +223,17 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl && wrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper)); } -ShibokenGenerator::FunctionGeneration - ShibokenGenerator::functionGeneration(const AbstractMetaFunctionCPtr &func) const +bool ShibokenGenerator::shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass) +{ + return usePySideExtensions() + && (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) + && !metaClass->typeEntry()->typeFlags() + .testFlag(ComplexTypeEntry::DisableQtMetaObjectFunctions) + && isQObject(metaClass); +} + +ShibokenGenerator::FunctionGeneration ShibokenGenerator::functionGeneration( + const AbstractMetaFunctionCPtr &func) { FunctionGeneration result; @@ -226,14 +276,15 @@ ShibokenGenerator::FunctionGeneration // Check on virtuals (including operators). const bool isAbstract = func->isAbstract(); if (!(isAbstract || func->isVirtual()) - || func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)) { + || func->cppAttributes().testFlag(FunctionAttribute::Final) + || func->isModifiedFinal()) { return result; } // MetaObject virtuals only need to be declared; CppGenerator creates a // special implementation. if (functionType == AbstractMetaFunction::NormalFunction - && usePySideExtensions() && func->ownerClass()->isQObject()) { + && usePySideExtensions() && isQObject(func->ownerClass())) { const QString &name = func->name(); if (name == u"metaObject"_s || name == u"qt_metacall") { result.setFlag(FunctionGenerationFlag::QMetaObjectMethod); @@ -248,11 +299,12 @@ ShibokenGenerator::FunctionGeneration return result; } -AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntry *t) const +AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntryCPtr &t) const { - if (!generateImplicitConversions()) + if (!generateImplicitConversions() || !t->isValue()) return {}; - auto *customConversion = t->customConversion(); + auto vte = std::static_pointer_cast<const ValueTypeEntry>(t); + auto customConversion = vte->customConversion(); if (customConversion && customConversion->replaceOriginalTargetToNativeConversions()) return {}; @@ -265,7 +317,7 @@ AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntry return result; } -QString ShibokenGenerator::wrapperName(const AbstractMetaClass *metaClass) const +QString ShibokenGenerator::wrapperName(const AbstractMetaClassCPtr &metaClass) { Q_ASSERT(shouldGenerateCppWrapper(metaClass)); QString result = metaClass->name(); @@ -274,19 +326,55 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass *metaClass) const return result + u"Wrapper"_s; } -QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClassCPtr &metaClass) { QString fullClassName = metaClass->name(); - const AbstractMetaClass *enclosing = metaClass->enclosingClass(); + auto enclosing = metaClass->enclosingClass(); while (enclosing) { if (NamespaceTypeEntry::isVisibleScope(enclosing->typeEntry())) fullClassName.prepend(enclosing->name() + u'.'); enclosing = enclosing->enclosingClass(); } - fullClassName.prepend(packageName() + u'.'); + fullClassName.prepend(metaClass->typeEntry()->targetLangPackage() + u'.'); return fullClassName; } +QString ShibokenGenerator::headerFileNameForContext(const GeneratorContext &context) +{ + return fileNameForContextHelper(context, u"_wrapper.h"_s); +} + +// PYSIDE-500: When avoiding the protected hack, also include the inherited +// wrapper classes of the *current* module, because without the protected hack, +// we sometimes need to cast inherited wrappers. Inherited classes +// of *other* modules are completely regenerated by the header generator +// since the wrapper headers are not installed. + +IncludeGroup ShibokenGenerator::baseWrapperIncludes(const GeneratorContext &classContext) const +{ + IncludeGroup result{u"Wrappers"_s, {}}; + if (!classContext.useWrapper() || !avoidProtectedHack() + || classContext.forSmartPointer()) { + return result; + } + + const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType(); + const auto &baseClasses = allBaseClasses(classContext.metaClass()); + for (const auto &base : baseClasses) { + const auto te = base->typeEntry(); + if (te->codeGeneration() == TypeEntry::GenerateCode) { // current module + const auto context = contextForClass(base); + if (context.useWrapper()) { + const QString header = headerFileNameForContext(context); + const auto type = typeSystemTypeEntry(te) == moduleEntry + ? Include::LocalPath : Include::IncludePath; + result.append(Include(type, header)); + } + } + } + return result; +} + QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr &func, bool forceFunc) { QString funcName; @@ -311,6 +399,11 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr return funcName; } +bool ShibokenGenerator::wrapperDiagnostics() +{ + return m_options.wrapperDiagnostics; +} + QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum) { QString result = metaEnum.fullName(); @@ -346,37 +439,37 @@ QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &f QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func) { if (!func->ownerClass()) - return QString(); + return {}; return cpythonBaseName(func->ownerClass()->typeEntry()) + u"Method_"_s + func->name(); } -QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClassCPtr &metaClass) { return cpythonBaseName(metaClass) + u"_getsetlist"_s; } -QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass) { return cpythonBaseName(metaClass) + u"_setattro"_s; } -QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass) { return cpythonBaseName(metaClass) + u"_getattro"_s; } QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name, - const AbstractMetaClass *enclosingClass) + const AbstractMetaClassCPtr &enclosingClass) { - return cpythonBaseName(enclosingClass) + QStringLiteral("_get_") + name; + return cpythonBaseName(enclosingClass) + "_get_"_L1 + name; } QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name, - const AbstractMetaClass *enclosingClass) + const AbstractMetaClassCPtr &enclosingClass) { - return cpythonBaseName(enclosingClass) + QStringLiteral("_set_") + name; + return cpythonBaseName(enclosingClass) + "_set_"_L1 + name; } QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField &metaField) @@ -390,13 +483,13 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField &me } QString ShibokenGenerator::cpythonGetterFunctionName(const QPropertySpec &property, - const AbstractMetaClass *metaClass) + const AbstractMetaClassCPtr &metaClass) { return cpythonGetterFunctionName(property.name(), metaClass); } QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec &property, - const AbstractMetaClass *metaClass) + const AbstractMetaClassCPtr &metaClass) { return cpythonSetterFunctionName(property.name(), metaClass); } @@ -409,7 +502,7 @@ static QString cpythonEnumFlagsName(const QString &moduleName, return result; } -QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry *enumEntry) +QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntryCPtr &enumEntry) { QString p = enumEntry->targetLangPackage(); p.replace(u'.', u'_'); @@ -421,7 +514,7 @@ QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum &metaEnum) return cpythonEnumName(metaEnum.typeEntry()); } -QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry *flagsEntry) +QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntryCPtr &flagsEntry) { QString p = flagsEntry->targetLangPackage(); p.replace(u'.', u'_'); @@ -430,18 +523,16 @@ QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry *flagsEntry) QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum) { - const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags(); - if (!flags) - return QString(); - return cpythonFlagsName(flags); + const auto flags = metaEnum->typeEntry()->flags(); + return flags ? cpythonFlagsName(flags) : QString{}; } -QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClassCPtr &metaClass) { return cpythonBaseName(metaClass->typeEntry()) + u"SpecialCastFunction"_s; } -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass *metaClass, +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass, const QString &argName) { return cpythonWrapperCPtr(metaClass->typeEntry(), argName); @@ -451,40 +542,41 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType &metaType, const QString &argName) { if (!metaType.isWrapperType()) - return QString(); + return {}; return u"reinterpret_cast< ::"_s + metaType.cppSignature() + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(metaType) + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s; } -QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry *type, +QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntryCPtr &type, const QString &argName) { if (!type->isWrapperType()) return QString(); - return u"reinterpret_cast< ::"_s + type->qualifiedCppName() + return u"reinterpret_cast< "_s + getFullTypeName(type) + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(type) + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s; } void ShibokenGenerator::writeToPythonConversion(TextStream & s, const AbstractMetaType &type, - const AbstractMetaClass * /* context */, + const AbstractMetaClassCPtr & /* context */, const QString &argumentName) { s << cpythonToPythonConversionFunction(type) << argumentName << ')'; } -void ShibokenGenerator::writeToCppConversion(TextStream &s, const AbstractMetaClass *metaClass, +void ShibokenGenerator::writeToCppConversion(TextStream &s, + const AbstractMetaClassCPtr &metaClass, const QString &inArgName, const QString &outArgName) { s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')'; } void ShibokenGenerator::writeToCppConversion(TextStream &s, const AbstractMetaType &type, - const AbstractMetaClass *context, const QString &inArgName, + const QString &inArgName, const QString &outArgName) { - s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')'; + s << cpythonToCppConversionFunction(type) << inArgName << ", &" << outArgName << ')'; } bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &func, @@ -519,66 +611,61 @@ QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType &type) return cpythonBaseName(type.typeEntry()); } -QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClassCPtr &metaClass) { return cpythonBaseName(metaClass->typeEntry()); } -QString ShibokenGenerator::cpythonBaseName(const TypeEntry *type) +QString ShibokenGenerator::containerCpythonBaseName(const ContainerTypeEntryCPtr &ctype) +{ + switch (ctype->containerKind()) { + case ContainerTypeEntry::SetContainer: + return u"PySet"_s; + case ContainerTypeEntry::MapContainer: + case ContainerTypeEntry::MultiMapContainer: + return u"PyDict"_s; + case ContainerTypeEntry::ListContainer: + case ContainerTypeEntry::PairContainer: + case ContainerTypeEntry::SpanContainer: + break; + default: + Q_ASSERT(false); + } + return cPySequenceT; +} + +QString ShibokenGenerator::cpythonBaseName(const TypeEntryCPtr &type) { QString baseName; if (type->isWrapperType() || type->isNamespace()) { // && type->referenceType() == NoReference) { baseName = u"Sbk_"_s + type->name(); } else if (type->isPrimitive()) { - const auto *ptype = type->asPrimitive()->basicReferencedTypeEntry(); + const auto ptype = basicReferencedTypeEntry(type); baseName = ptype->hasTargetLangApiType() ? ptype->targetLangApiName() : pythonPrimitiveTypeName(ptype->name()); } else if (type->isEnum()) { - baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type)); + baseName = cpythonEnumName(std::static_pointer_cast<const EnumTypeEntry>(type)); } else if (type->isFlags()) { - baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type)); + baseName = cpythonFlagsName(std::static_pointer_cast<const FlagsTypeEntry>(type)); } else if (type->isContainer()) { - const auto *ctype = static_cast<const ContainerTypeEntry *>(type); - switch (ctype->containerKind()) { - case ContainerTypeEntry::ListContainer: - //baseName = "PyList"; - //break; - case ContainerTypeEntry::PairContainer: - //baseName = "PyTuple"; - baseName = cPySequenceT(); - break; - case ContainerTypeEntry::SetContainer: - baseName = u"PySet"_s; - break; - case ContainerTypeEntry::MapContainer: - case ContainerTypeEntry::MultiMapContainer: - baseName = u"PyDict"_s; - break; - default: - Q_ASSERT(false); - } + const auto ctype = std::static_pointer_cast<const ContainerTypeEntry>(type); + baseName = containerCpythonBaseName(ctype); } else { - baseName = cPyObjectT(); + baseName = cPyObjectT; } return baseName.replace(u"::"_s, u"_"_s); } -QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClassCPtr &metaClass) { return cpythonTypeName(metaClass->typeEntry()); } -QString ShibokenGenerator::cpythonTypeName(const TypeEntry *type) +QString ShibokenGenerator::cpythonTypeName(const TypeEntryCPtr &type) { return cpythonBaseName(type) + u"_TypeF()"_s; } -QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry *type) -{ - return cppApiVariableName(type->targetLangPackage()) + u'[' - + getTypeIndexVariableName(type) + u']'; -} - QString ShibokenGenerator::converterObject(const AbstractMetaType &type) { if (type.isCString()) @@ -587,7 +674,7 @@ QString ShibokenGenerator::converterObject(const AbstractMetaType &type) return u"Shiboken::Conversions::PrimitiveTypeConverter<void *>()"_s; const AbstractMetaTypeList nestedArrayTypes = type.nestedArrayTypes(); if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) { - return QStringLiteral("Shiboken::Conversions::ArrayTypeConverter<") + return "Shiboken::Conversions::ArrayTypeConverter<"_L1 + nestedArrayTypes.constLast().minimalSignature() + u">("_s + QString::number(nestedArrayTypes.size()) + u')'; @@ -601,34 +688,31 @@ QString ShibokenGenerator::converterObject(const AbstractMetaType &type) return converterObject(typeEntry); } -QString ShibokenGenerator::converterObject(const TypeEntry *type) +QString ShibokenGenerator::converterObject(const TypeEntryCPtr &type) { - if (type->isExtendedCppPrimitive()) + if (isExtendedCppPrimitive(type)) return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()") .arg(type->qualifiedCppName()); if (type->isWrapperType()) return QString::fromLatin1("PepType_SOTP(reinterpret_cast<PyTypeObject *>(%1))->converter") .arg(cpythonTypeNameExt(type)); - if (type->isEnum()) + if (type->isEnum() || type->isFlags()) return QString::fromLatin1("PepType_SETP(reinterpret_cast<SbkEnumType *>(%1))->converter") .arg(cpythonTypeNameExt(type)); - if (type->isFlags()) - return QString::fromLatin1("PepType_PFTP(reinterpret_cast<PySideQFlagsType *>(%1))->converter") - .arg(cpythonTypeNameExt(type)); if (type->isArray()) { qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName(); - return QString(); + return {}; } /* the typedef'd primitive types case */ - const auto *pte = dynamic_cast<const PrimitiveTypeEntry *>(type); + auto pte = std::dynamic_pointer_cast<const PrimitiveTypeEntry>(type); if (!pte) { qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName(); - return QString(); + return {}; } - pte = pte->basicReferencedTypeEntry(); - if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion()) { + pte = basicReferencedTypeEntry(pte); + if (pte->isPrimitive() && !isCppPrimitive(pte) && !pte->customConversion()) { return u"Shiboken::Conversions::PrimitiveTypeConverter<"_s + pte->qualifiedCppName() + u">()"_s; } @@ -637,19 +721,35 @@ QString ShibokenGenerator::converterObject(const TypeEntry *type) + u'[' + getTypeIndexVariableName(type) + u']'; } -QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type) +QString ShibokenGenerator::cpythonTypeNameExtSet(const TypeEntryCPtr &type) +{ + return cppApiVariableName(type->targetLangPackage()) + u'[' + + getTypeIndexVariableName(type) + "].type"_L1; +} + +QString ShibokenGenerator::cpythonTypeNameExtSet(const AbstractMetaType &type) { return cppApiVariableName(type.typeEntry()->targetLangPackage()) + u'[' - + getTypeIndexVariableName(type) + u']'; + + getTypeIndexVariableName(type) + "].type"_L1; } -static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); } +QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type) +{ + return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage()) + + u'[' + getTypeIndexVariableName(type) + "])"_L1; +} -QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion *toNative) +QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type) { - if (toNative->sourceType()) - return fixedCppTypeName(toNative->sourceType()); - return toNative->sourceTypeName(); + return u"Shiboken::Module::get("_s + cppApiVariableName(type.typeEntry()->targetLangPackage()) + + u'[' + getTypeIndexVariableName(type) + "])"_L1; +} + +QString ShibokenGenerator::fixedCppTypeName(const TargetToNativeConversion &toNative) +{ + if (toNative.sourceType()) + return fixedCppTypeName(toNative.sourceType()); + return toNative.sourceTypeName(); } QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type) { @@ -668,7 +768,7 @@ static QString _fixedCppTypeName(QString typeName) typeName.replace(u"&"_s, u"REF"_s); return typeName; } -QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeName) +QString ShibokenGenerator::fixedCppTypeName(const TypeEntryCPtr &type, QString typeName) { if (typeName.isEmpty()) typeName = type->qualifiedCppName(); @@ -692,8 +792,8 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction { QString op = Generator::pythonOperatorFunctionName(func->originalName()); if (op.isEmpty()) { - qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.data()); - return unknownOperator(); + qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.get()); + return "__UNKNOWN_OPERATOR__"_L1; } if (func->arguments().isEmpty()) { if (op == u"__sub__") @@ -710,27 +810,26 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction bool ShibokenGenerator::isNumber(const QString &cpythonApiName) { - return cpythonApiName == pyIntT() - || cpythonApiName == pyFloatT() || cpythonApiName == pyLongT() - || cpythonApiName == pyBoolT(); + return cpythonApiName == pyFloatT || cpythonApiName == pyLongT + || cpythonApiName == pyBoolT; } static std::optional<TypeSystem::CPythonType> - targetLangApiCPythonType(const PrimitiveTypeEntry *t) + targetLangApiCPythonType(const PrimitiveTypeEntryCPtr &t) { if (!t->hasTargetLangApiType()) return {}; - const auto *cte = t->targetLangApiType(); + const auto cte = t->targetLangApiType(); if (cte->type() != TypeEntry::PythonType) return {}; - return static_cast<const PythonTypeEntry *>(cte)->cPythonType(); + return std::static_pointer_cast<const PythonTypeEntry>(cte)->cPythonType(); } -bool ShibokenGenerator::isNumber(const TypeEntry *type) +bool ShibokenGenerator::isNumber(const TypeEntryCPtr &type) { if (!type->isPrimitive()) return false; - const auto *pte = type->asPrimitive()->basicReferencedTypeEntry(); + const auto pte = basicReferencedTypeEntry(type); const auto cPythonTypeOpt = targetLangApiCPythonType(pte); // FIXME PYSIDE-1660: Return false here after making primitive types built-in? if (!cPythonTypeOpt.has_value()) { @@ -749,17 +848,17 @@ bool ShibokenGenerator::isNumber(const AbstractMetaType &type) return isNumber(type.typeEntry()); } -bool ShibokenGenerator::isPyInt(const TypeEntry *type) +bool ShibokenGenerator::isPyInt(const TypeEntryCPtr &type) { if (!type->isPrimitive()) return false; - const auto *pte = type->asPrimitive()->basicReferencedTypeEntry(); + const auto pte = basicReferencedTypeEntry(type); const auto cPythonTypeOpt = targetLangApiCPythonType(pte); // FIXME PYSIDE-1660: Return false here after making primitive types built-in? if (!cPythonTypeOpt.has_value()) { const auto &mapping = primitiveTypesCorrespondences(); const auto it = mapping.constFind(pte->name()); - return it != mapping.cend() && it.value() == pyLongT(); + return it != mapping.cend() && it.value() == pyLongT; } return cPythonTypeOpt.value() == TypeSystem::CPythonType::Integer; } @@ -777,9 +876,9 @@ bool ShibokenGenerator::isNullPtr(const QString &value) QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType) { - const auto *typeEntry = metaType.typeEntry(); + const auto typeEntry = metaType.typeEntry(); if (typeEntry->isCustom()) { - const auto *cte = static_cast<const CustomTypeEntry *>(typeEntry); + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry); if (cte->hasCheckFunction()) return cte->checkFunction(); throw Exception(msgUnknownCheckFunction(typeEntry)); @@ -796,7 +895,7 @@ QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType) if (typeEntry->isContainer()) { QString typeCheck = u"Shiboken::Conversions::"_s; ContainerTypeEntry::ContainerKind type = - static_cast<const ContainerTypeEntry *>(typeEntry)->containerKind(); + std::static_pointer_cast<const ContainerTypeEntry>(typeEntry)->containerKind(); if (type == ContainerTypeEntry::ListContainer || type == ContainerTypeEntry::SetContainer) { const QString containerType = type == ContainerTypeEntry::SetContainer @@ -844,10 +943,10 @@ QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType) return cpythonCheckFunction(typeEntry); } -QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type) +QString ShibokenGenerator::cpythonCheckFunction(TypeEntryCPtr type) { if (type->isCustom()) { - const auto *cte = static_cast<const CustomTypeEntry *>(type); + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(type); if (cte->hasCheckFunction()) return cte->checkFunction(); throw Exception(msgUnknownCheckFunction(type)); @@ -857,28 +956,26 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type) return u"SbkObject_TypeCheck("_s + cpythonTypeNameExt(type) + u", "_s; if (type->isPrimitive()) - type = type->asPrimitive()->basicReferencedTypeEntry(); + type = basicReferencedTypeEntry(type); - if (auto *tla = type->targetLangApiType()) { + if (auto tla = type->targetLangApiType()) { if (tla->hasCheckFunction()) return tla->checkFunction(); } - if (type->isExtendedCppPrimitive()) { - const auto *pte = type->asPrimitive(); - return pythonPrimitiveTypeName(pte->name()) + u"_Check"_s; - } + if (isExtendedCppPrimitive(type)) + return pythonPrimitiveTypeName(type->name()) + u"_Check"_s; return cpythonIsConvertibleFunction(type); } -QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry *type) +QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntryCPtr &type) { if (type->isWrapperType()) { QString result = u"Shiboken::Conversions::"_s; bool isValue = false; if (type->isValue()) { - const auto *cte = static_cast<const ComplexTypeEntry *>(type); + const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(type); isValue = !cte->isValueTypeWithCopyConstructorOnly(); } result += isValue ? u"isPythonToCppValueConvertible"_s @@ -890,11 +987,11 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry *type) .arg(converterObject(type)); } -QString ShibokenGenerator::cpythonIsConvertibleFunction(AbstractMetaType metaType) +QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType &metaType) { - const auto *typeEntry = metaType.typeEntry(); + const auto typeEntry = metaType.typeEntry(); if (typeEntry->isCustom()) { - const auto *cte = static_cast<const CustomTypeEntry *>(typeEntry); + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry); if (cte->hasCheckFunction()) return cte->checkFunction(); throw Exception(msgUnknownCheckFunction(typeEntry)); @@ -907,12 +1004,14 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(AbstractMetaType metaTyp return result; } if (metaType.isWrapperType()) { - if (metaType.isPointer() || metaType.isValueTypeWithCopyConstructorOnly()) + if (metaType.isPointer() || metaType.isValueTypeWithCopyConstructorOnly()) { result += u"pythonToCppPointerConversion"_s; - else if (metaType.referenceType() == LValueReference) + } else if (metaType.referenceType() == LValueReference + || (metaType.referenceType() == RValueReference && typeEntry->isObject())) { result += u"pythonToCppReferenceConversion"_s; - else + } else { result += u"pythonToCppValueConversion"_s; + } result += u'(' + cpythonTypeNameExt(metaType) + u", "_s; return result; } @@ -935,26 +1034,24 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgume return cpythonIsConvertibleFunction(metaArg.type()); } -QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass) { return u"Shiboken::Conversions::pythonToCppPointer("_s + cpythonTypeNameExt(metaClass->typeEntry()) + u", "_s; } -QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType &type, - const AbstractMetaClass * /* context */) +QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType &type) { if (type.isWrapperType()) { return u"Shiboken::Conversions::pythonToCpp"_s + (type.isPointer() ? u"Pointer"_s : u"Copy"_s) + u'(' + cpythonTypeNameExt(type) + u", "_s; } - return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ") - .arg(converterObject(type)); + return "Shiboken::Conversions::pythonToCppCopy("_L1 + + converterObject(type) + ", "_L1; } -QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type, - const AbstractMetaClass * /* context */) +QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type) { if (type.isWrapperType()) { QString conversion; @@ -973,17 +1070,18 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT result += u'&'; return result; } - return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2") - .arg(converterObject(type), - (type.isCString() || type.isVoidPointer()) ? QString() : u"&"_s); + + const auto indirections = type.indirections() - 1; + return u"Shiboken::Conversions::copyToPython("_s + converterObject(type) + + u", "_s + AbstractMetaType::dereferencePrefix(indirections); } -QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClassCPtr &metaClass) { return cpythonToPythonConversionFunction(metaClass->typeEntry()); } -QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry *type) +QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntryCPtr &type) { if (type->isWrapperType()) { const QString conversion = type->isValue() ? u"copy"_s : u"pointer"_s; @@ -1006,13 +1104,14 @@ QString ShibokenGenerator::argumentString(const AbstractMetaFunctionCPtr &func, auto type = options.testFlag(OriginalTypeDescription) ? argument.type() : argument.modifiedType(); + QString arg = translateType(type, func->implementingClass(), options); if (argument.isTypeModified()) arg.replace(u'$', u'.'); // Haehh? // "int a", "int a[]" - const int arrayPos = arg.indexOf(u'['); + const auto arrayPos = arg.indexOf(u'['); if (arrayPos != -1) arg.insert(arrayPos, u' ' + argument.name()); else @@ -1047,11 +1146,12 @@ void ShibokenGenerator::writeFunctionArguments(TextStream &s, const AbstractMetaFunctionCPtr &func, Options options) const { - AbstractMetaArgumentList arguments = func->arguments(); - int argUsed = 0; - for (int i = 0; i < arguments.size(); ++i) { - const auto &arg = arguments.at(i); + if (func->isUserAddedPythonOverride()) { + s << "Shiboken::GilState &gil, PyObject *" << PYTHON_OVERRIDE_VAR; + argUsed += 2; + } + for (const auto &arg : func->arguments()) { if (options.testFlag(Generator::SkipRemovedArguments) && arg.isModifiedRemoved()) continue; @@ -1062,7 +1162,7 @@ void ShibokenGenerator::writeFunctionArguments(TextStream &s, } } -GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClass *c) const +GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClassCPtr &c) const { GeneratorContext result = Generator::contextForClass(c); if (shouldGenerateCppWrapper(c)) { @@ -1087,6 +1187,8 @@ QString ShibokenGenerator::functionSignature(const AbstractMetaFunctionCPtr &fun { StringStream s(TextStream::Language::Cpp); // The actual function + if (!options.testFlag(Option::SkipDefaultValues) && func->isStatic()) // Declaration + s << "static "; if (func->isEmptyFunction() || func->needsReturnType()) s << functionReturnType(func, options) << ' '; else @@ -1148,15 +1250,10 @@ void ShibokenGenerator::writeFunctionCall(TextStream &s, s << ')'; } -void ShibokenGenerator::writeUnusedVariableCast(TextStream &s, const QString &variableName) -{ - s << "SBK_UNUSED(" << variableName<< ")\n"; -} - ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const { ExtendedConverterData extConvs; - for (auto metaClass : api().classes()) { + for (const auto &metaClass : api().classes()) { // Use only the classes for the current module. if (!shouldGenerate(metaClass->typeEntry())) continue; @@ -1164,7 +1261,7 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter for (const auto &convOp : overloads) { // Get only the conversion operators that return a type from another module, // that are value-types and were not removed in the type system. - const TypeEntry *convType = convOp->type().typeEntry(); + const auto convType = convOp->type().typeEntry(); if (convType->generateCode() || !convType->isValue() || convOp->isModifiedRemoved()) continue; @@ -1174,15 +1271,13 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter return extConvs; } -QList<const CustomConversion *> ShibokenGenerator::getPrimitiveCustomConversions() +QList<CustomConversionPtr> ShibokenGenerator::getPrimitiveCustomConversions() { - QList<const CustomConversion *> conversions; - const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); - for (const PrimitiveTypeEntry *type : primitiveTypeList) { - if (!type->shouldGenerate() || !type->isUserPrimitive() || !type->customConversion()) - continue; - - conversions << type->customConversion(); + QList<CustomConversionPtr> conversions; + const auto &primitiveTypeList = primitiveTypes(); + for (const auto &type : primitiveTypeList) { + if (type->shouldGenerate() && isUserPrimitive(type) && type->hasCustomConversion()) + conversions << type->customConversion(); } return conversions; } @@ -1195,7 +1290,7 @@ static QString getArgumentsFromMethodCall(const QString &str) // For more information check this: // http://perl.plover.com/yak/regex/samples/slide083.html static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME"); - int pos = str.indexOf(funcCall); + auto pos = str.indexOf(funcCall); if (pos == -1) return QString(); pos = pos + funcCall.size(); @@ -1239,7 +1334,7 @@ void ShibokenGenerator::processClassCodeSnip(QString &code, const GeneratorConte code.replace(u"%TYPE"_s, className); code.replace(u"%CPPTYPE"_s, metaClass->name()); - processCodeSnip(code); + processCodeSnip(code, context.effectiveClassName()); } void ShibokenGenerator::processCodeSnip(QString &code) const @@ -1257,6 +1352,15 @@ void ShibokenGenerator::processCodeSnip(QString &code) const replaceTypeCheckTypeSystemVariable(code); } +void ShibokenGenerator::processCodeSnip(QString &code, const QString &context) const +{ + try { + processCodeSnip(code); + } catch (const std::exception &e) { + throw Exception(msgSnippetError(context, e.what())); + } +} + ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunctionCPtr &func, bool usePyArgs, TypeSystem::Language language, @@ -1266,7 +1370,7 @@ ShibokenGenerator::ArgumentVarReplacementList TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode) ? TypeSystem::NativeCode : TypeSystem::TargetLangCode; int removed = 0; - for (int i = 0; i < func->arguments().size(); ++i) { + for (qsizetype i = 0; i < func->arguments().size(); ++i) { const AbstractMetaArgument &arg = func->arguments().at(i); QString argValue; if (language == TypeSystem::TargetLangCode) { @@ -1277,7 +1381,7 @@ ShibokenGenerator::ArgumentVarReplacementList if (argRemoved && hasConversionRule) argValue = arg.name() + CONV_RULE_OUT_VAR_SUFFIX; else if (argRemoved || (lastArg && arg.argumentIndex() > lastArg->argumentIndex())) - argValue = CPP_ARG_REMOVED + QString::number(i); + argValue = CPP_ARG_REMOVED(i); if (!argRemoved && argValue.isEmpty()) { int argPos = i - removed; AbstractMetaType type = arg.modifiedType(); @@ -1287,9 +1391,9 @@ ShibokenGenerator::ArgumentVarReplacementList } else { argValue = hasConversionRule ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX - : CPP_ARG + QString::number(argPos); - auto deRef = type.shouldDereferenceArgument(); - AbstractMetaType::applyDereference(&argValue, deRef); + : CPP_ARG_N(argPos); + const auto generatorArg = GeneratorArgument::fromMetaType(type); + AbstractMetaType::applyDereference(&argValue, generatorArg.indirections); } } } else { @@ -1329,7 +1433,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, static void replacePyArg0(TypeSystem::Language language, QString *code) { - static const QString pyArg0 = u"%PYARG_0"_s; + static constexpr auto pyArg0 = "%PYARG_0"_L1; if (!code->contains(pyArg0)) return; @@ -1368,18 +1472,18 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, // Replace %PYARG_# variables. replacePyArg0(language, &code); - static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)")); + static const QRegularExpression pyArgsRegex("%PYARG_(\\d+)"_L1); Q_ASSERT(pyArgsRegex.isValid()); if (language == TypeSystem::TargetLangCode) { if (usePyArgs) { code.replace(pyArgsRegex, PYTHON_ARGS + u"[\\1-1]"_s); } else { - static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)")); + static const QRegularExpression pyArgsRegexCheck("%PYARG_([2-9]+)"_L1); Q_ASSERT(pyArgsRegexCheck.isValid()); const QRegularExpressionMatch match = pyArgsRegexCheck.match(code); if (match.hasMatch()) { qCWarning(lcShiboken).noquote().nospace() - << msgWrongIndex("%PYARG", match.captured(1), func.data()); + << msgWrongIndex("%PYARG", match.captured(1), func.get()); return; } code.replace(u"%PYARG_1"_s, PYTHON_ARG); @@ -1387,12 +1491,12 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, } else { // Replaces the simplest case of attribution to a // Python argument on the binding virtual method. - static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)")); + static const QRegularExpression pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"_L1); Q_ASSERT(pyArgsAttributionRegex.isValid()); code.replace(pyArgsAttributionRegex, u"PyTuple_SET_ITEM("_s - + PYTHON_ARGS + u", \\1-1, \\2)"_s); + + PYTHON_ARGS + u".object(), \\1-1, \\2)"_s); code.replace(pyArgsRegex, u"PyTuple_GET_ITEM("_s - + PYTHON_ARGS + u", \\1-1)"_s); + + PYTHON_ARGS + u".object(), \\1-1)"_s); } // Replace %ARG#_TYPE variables. @@ -1404,13 +1508,13 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, code.replace(argTypeVar, argTypeVal); } - static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE")); + static const QRegularExpression cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"_L1); Q_ASSERT(cppArgTypeRegexCheck.isValid()); QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code); while (rit.hasNext()) { QRegularExpressionMatch match = rit.next(); qCWarning(lcShiboken).noquote().nospace() - << msgWrongIndex("%ARG#_TYPE", match.captured(1), func.data()); + << msgWrongIndex("%ARG#_TYPE", match.captured(1), func.get()); } // Replace template variable for return variable name. @@ -1496,7 +1600,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, QStringList args; for (const ArgumentVarReplacementPair &pair : argReplacements) { - if (pair.second.startsWith(CPP_ARG_REMOVED)) + if (pair.second.startsWith(CPP_ARG_REMOVED_PREFIX)) continue; args << pair.second; } @@ -1508,7 +1612,8 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, AbstractMetaType type = arg.modifiedType(); if (type.isWrapperType()) { QString replacement = pair.second; - if (type.shouldDereferenceArgument() > 0) + const auto generatorArg = GeneratorArgument::fromMetaType(type); + if (generatorArg.indirections > 0) AbstractMetaType::stripDereference(&replacement); if (type.referenceType() == LValueReference || type.isPointer()) code.replace(u'%' + QString::number(idx) + u'.', replacement + u"->"_s); @@ -1545,8 +1650,8 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, if (isProtected) { code.replace(u"%TYPE::%FUNCTION_NAME"_s, - QStringLiteral("%1::%2_protected") - .arg(wrapperName(func->ownerClass()), func->originalName())); + wrapperName(func->ownerClass()) + "::"_L1 + + func->originalName() + "_protected"_L1); code.replace(u"%FUNCTION_NAME"_s, func->originalName() + u"_protected"_s); } @@ -1560,7 +1665,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, replaceTemplateVariables(code, func); - processCodeSnip(code); + processCodeSnip(code, func->classQualifiedSignature()); s << "// Begin code injection\n" << code << "// End of code injection\n\n"; } @@ -1568,7 +1673,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, // and false if it is a variable. static bool isVariable(const QString &code) { - static const QRegularExpression expr(QStringLiteral("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$")); + static const QRegularExpression expr("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"_L1); Q_ASSERT(expr.isValid()); return expr.match(code.trimmed()).hasMatch(); } @@ -1629,7 +1734,7 @@ const QHash<int, QString> &ShibokenGenerator::typeSystemConvName() return result; } -using StringPair = QPair<QString, QString>; +using StringPair = std::pair<QString, QString>; void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString &code) const @@ -1664,9 +1769,6 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa varType = miniNormalizer(varType); QString varName = list.at(1).trimmed(); if (!varType.isEmpty()) { - const QString conversionSignature = conversionType.cppSignature(); - if (varType != u"auto" && varType != conversionSignature) - throw Exception(msgConversionTypesDiffer(varType, conversionSignature)); c << getFullTypeName(conversionType) << ' ' << varName << minimalConstructorExpression(api(), conversionType) << ";\n"; } @@ -1683,7 +1785,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa case TypeSystemCheckFunction: conversion = cpythonCheckFunction(conversionType); if (conversionType.typeEntry()->isPrimitive() - && (conversionType.typeEntry()->name() == cPyObjectT() + && (conversionType.typeEntry()->name() == cPyObjectT || !conversion.endsWith(u' '))) { conversion += u'('; break; @@ -1714,9 +1816,9 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa } } } - replacements.append(qMakePair(conversionString, conversion)); + replacements.append(std::make_pair(conversionString, conversion)); } - for (const StringPair &rep : qAsConst(replacements)) + for (const StringPair &rep : std::as_const(replacements)) code.replace(rep.first, rep.second); } @@ -1741,12 +1843,13 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &con return func->injectedCodeContains(wrappedCtorCall); } -bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClass *metaClass) +bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClassCPtr &metaClass) { return metaClass->isPolymorphic(); } -ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const +ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds( + const AbstractMetaClassCPtr &metaClass) { AttroCheck result; if (metaClass->typeEntry()->isSmartPointer()) { @@ -1758,7 +1861,7 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A FunctionQueryOption::GetAttroFunction)) { result |= AttroCheckFlag::GetattroUser; } - if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT()) + if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT) result |= AttroCheckFlag::SetattroQObject; if (useOverrideCaching(metaClass)) result |= AttroCheckFlag::SetattroMethodOverride; @@ -1770,14 +1873,14 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A // QObject, the property code needs to be generated, too. if ((result & AttroCheckFlag::SetattroMask) != 0 && !result.testFlag(AttroCheckFlag::SetattroQObject) - && metaClass->isQObject()) { + && isQObject(metaClass)) { result |= AttroCheckFlag::SetattroQObject; } } return result; } -bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass) +bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClassCPtr &metaClass) { if (!metaClass) return false; @@ -1786,7 +1889,7 @@ bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass * const auto &functionGroup = getFunctionGroups(metaClass); for (auto it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) { AbstractMetaFunctionCList overloads; - for (const auto &func : qAsConst(it.value())) { + for (const auto &func : std::as_const(it.value())) { if (func->isAssignmentOperator() || func->isConversionOperator() || func->isModifiedRemoved() || func->isPrivate() || func->ownerClass() != func->implementingClass() @@ -1803,14 +1906,14 @@ bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass * } AbstractMetaFunctionCList - ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass *metaClass) + ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClassCPtr &metaClass) { AbstractMetaFunctionCList methods; if (metaClass) { const auto &functionGroups = getFunctionGroups(metaClass); for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { AbstractMetaFunctionCList overloads; - for (const auto &func : qAsConst(it.value())) { + for (const auto &func : std::as_const(it.value())) { if (func->isAssignmentOperator() || func->isConversionOperator() || func->isModifiedRemoved() || func->isPrivate() || func->ownerClass() != func->implementingClass() @@ -1827,7 +1930,8 @@ AbstractMetaFunctionCList return methods; } -const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass *metaClass) +AbstractMetaClassCPtr + ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClassCPtr &metaClass) { if (!metaClass || metaClass->baseClassNames().isEmpty()) return nullptr; @@ -1838,24 +1942,48 @@ const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const Abs QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName) { - return moduleCppPrefix(moduleName).toLower() + QStringLiteral("_python"); + return moduleCppPrefix(moduleName).toLower() + "_python"_L1; } QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName) { - return getModuleHeaderFileBaseName(moduleName) + QStringLiteral(".h"); + return getModuleHeaderFileBaseName(moduleName) + ".h"_L1; } QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName) { - return getModuleHeaderFileBaseName(moduleName) + QStringLiteral("_p.h"); + return getModuleHeaderFileBaseName(moduleName) + "_p.h"_L1; +} + +IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const +{ + IncludeGroupList result; + const auto typeEntry = metaClass->typeEntry(); + //Extra includes + result.append(IncludeGroup{u"Extra includes"_s, + typeEntry->extraIncludes()}); + + result.append({u"Enum includes"_s, {}}); + for (const auto &cppEnum : metaClass->enums()) + result.back().includes.append(cppEnum.typeEntry()->extraIncludes()); + + result.append({u"Argument includes"_s, typeEntry->argumentIncludes()}); + const auto implicitConvs = implicitConversions(typeEntry); + for (const auto &f : implicitConvs) { + if (f->isConversionOperator()) { + const auto source = f->ownerClass(); + Q_ASSERT(source); + result.back().append(source->typeEntry()->include()); + } + } + return result; } /* static void dumpFunction(AbstractMetaFunctionList lst) { qDebug() << "DUMP FUNCTIONS: "; - for (AbstractMetaFunction *func : qAsConst(lst)) + for (AbstractMetaFunction *func : std::as_const(lst)) qDebug() << "*" << func->ownerClass()->name() << func->signature() << "Private: " << func->isPrivate() @@ -1899,29 +2027,47 @@ ShibokenGenerator::FunctionGroups ShibokenGenerator::getGlobalFunctionGroups() c { FunctionGroups results; insertIntoFunctionGroups(api().globalFunctions(), &results); - for (auto nsp : invisibleTopNamespaces()) + for (const auto &nsp : invisibleTopNamespaces()) insertIntoFunctionGroups(nsp->functions(), &results); return results; } -const GeneratorClassInfoCacheEntry &ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClass *scope) +const GeneratorClassInfoCacheEntry & + ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClassCPtr &scope) { auto cache = generatorClassInfoCache(); auto it = cache->find(scope); if (it == cache->end()) { it = cache->insert(scope, {}); - it.value().functionGroups = getFunctionGroupsImpl(scope); - it.value().needsGetattroFunction = classNeedsGetattroFunctionImpl(scope); + auto &entry = it.value(); + entry.functionGroups = getFunctionGroupsImpl(scope); + entry.needsGetattroFunction = classNeedsGetattroFunctionImpl(scope); + entry.numberProtocolOperators = getNumberProtocolOperators(scope); + entry.boolCastFunctionO = getBoolCast(scope); } return it.value(); } -ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroups(const AbstractMetaClass *scope) +ShibokenGenerator::FunctionGroups + ShibokenGenerator::getFunctionGroups(const AbstractMetaClassCPtr &scope) { Q_ASSERT(scope); return getGeneratorClassInfo(scope).functionGroups; } +QList<AbstractMetaFunctionCList> + ShibokenGenerator::numberProtocolOperators(const AbstractMetaClassCPtr &scope) +{ + Q_ASSERT(scope); + return getGeneratorClassInfo(scope).numberProtocolOperators; +} + +BoolCastFunctionOptional ShibokenGenerator::boolCast(const AbstractMetaClassCPtr &scope) +{ + Q_ASSERT(scope); + return getGeneratorClassInfo(scope).boolCastFunctionO; +} + // Use non-const overloads only, for example, "foo()" and "foo()const" // the second is removed. static void removeConstOverloads(AbstractMetaFunctionCList *overloads) @@ -1930,7 +2076,7 @@ static void removeConstOverloads(AbstractMetaFunctionCList *overloads) const auto &f = overloads->at(i); if (f->isConstant()) { for (qsizetype c = 0, size = overloads->size(); c < size; ++c) { - if (f->isConstOverloadOf(overloads->at(c).data())) { + if (f->isConstOverloadOf(overloads->at(c).get())) { overloads->removeAt(i); break; } @@ -1939,7 +2085,8 @@ static void removeConstOverloads(AbstractMetaFunctionCList *overloads) } } -ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClass *scope) +ShibokenGenerator::FunctionGroups + ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope) { AbstractMetaFunctionCList lst = scope->functions(); scope->getFunctionsFromInvisibleNamespacesToBeGenerated(&lst); @@ -1970,13 +2117,156 @@ ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const return results; } +static bool removeNumberProtocolOperator(const AbstractMetaFunctionCPtr &f) +{ + return !f->generateBinding() + || (f->ownerClass() != f->implementingClass() && !f->isAbstract()); +} + +QList<AbstractMetaFunctionCList> + ShibokenGenerator::getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass) +{ + QList<AbstractMetaFunctionCList> result; + if (metaClass->isNamespace()) + return result; + result = filterGroupedOperatorFunctions( + metaClass, + OperatorQueryOption::ArithmeticOp + | OperatorQueryOption::IncDecrementOp + | OperatorQueryOption::LogicalOp + | OperatorQueryOption::BitwiseOp + | OperatorQueryOption::ConversionOp); + + for (auto i = result.size() - 1; i >= 0; --i) { + AbstractMetaFunctionCList &l = result[i]; + auto rend = std::remove_if(l.begin(), l.end(), removeNumberProtocolOperator); + l.erase(rend, l.end()); + if (l.isEmpty()) + result.removeAt(i); + } + + return result; +} + +BoolCastFunctionOptional +ShibokenGenerator::getBoolCast(const AbstractMetaClassCPtr &metaClass) +{ + if (metaClass->isNamespace()) + return std::nullopt; + + const auto te = metaClass->typeEntry(); + if (te->isSmartPointer()) { + auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(te); + + auto valueCheckMethod = ste->valueCheckMethod(); + if (!valueCheckMethod.isEmpty()) { + const auto func = metaClass->findFunction(valueCheckMethod); + if (!func) + throw Exception(msgMethodNotFound(metaClass, valueCheckMethod)); + return BoolCastFunction{func, false}; + } + + auto nullCheckMethod = ste->nullCheckMethod(); + if (!nullCheckMethod.isEmpty()) { + const auto func = metaClass->findFunction(nullCheckMethod); + if (!func) + throw Exception(msgMethodNotFound(metaClass, nullCheckMethod)); + return BoolCastFunction{func, true}; + } + } + + auto mode = te->operatorBoolMode(); + if (useOperatorBoolAsNbBool() + ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) { + const auto func = metaClass->findOperatorBool(); + if (func) + return BoolCastFunction{func, false}; + } + + mode = te->isNullMode(); + if (useIsNullAsNbBool() + ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) { + const auto func = metaClass->findQtIsNullMethod(); + if (func) + return BoolCastFunction{func, true}; + } + return std::nullopt; +} + +static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func) +{ + return func->name() == u"operator+="; +} + +static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func) +{ + return func->functionType() == AbstractMetaFunction::IncrementOperator; +} + +static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func) +{ + return func->functionType() == AbstractMetaFunction::DecrementOperator; +} + +// Filter predicate for operator functions +static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func) +{ + if (func->isModifiedRemoved() || func->usesRValueReferences()) + return true; + const auto &name = func->name(); + return name == u"operator[]" || name == u"operator->" || name == u"operator!" + || name == u"operator/="; // __idiv__ is not needed in Python3 +} + +QList<AbstractMetaFunctionCList> +ShibokenGenerator::filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &metaClass, + OperatorQueryOptions query) +{ + // ( func_name, num_args ) => func_list + QMap<std::pair<QString, int>, AbstractMetaFunctionCList> results; + auto funcs = metaClass->operatorOverloads(query); + auto end = std::remove_if(funcs.begin(), funcs.end(), skipOperatorFunc); + funcs.erase(end, funcs.end()); + // If we have operator+=, we remove the operator++/-- which would + // otherwise be used for emulating __iadd__, __isub__. + if (std::any_of(funcs.cbegin(), funcs.cend(), isInplaceAdd)) { + end = std::remove_if(funcs.begin(), funcs.end(), + [] (const AbstractMetaFunctionCPtr &func) { + return func->isIncDecrementOperator(); + }); + funcs.erase(end, funcs.end()); + } else { + // If both prefix/postfix ++/-- are present, remove one + if (std::count_if(funcs.begin(), funcs.end(), isIncrementOperator) > 1) + funcs.erase(std::find_if(funcs.begin(), funcs.end(), isIncrementOperator)); + if (std::count_if(funcs.begin(), funcs.end(), isDecrementOperator) > 1) + funcs.erase(std::find_if(funcs.begin(), funcs.end(), isDecrementOperator)); + } + for (const auto &func : funcs) { + int args; + if (func->isComparisonOperator()) { + args = -1; + } else { + args = func->arguments().size(); + } + auto op = std::make_pair(func->name(), args); + results[op].append(func); + } + QList<AbstractMetaFunctionCList> result; + result.reserve(results.size()); + for (auto it = results.cbegin(), end = results.cend(); it != end; ++it) + result.append(it.value()); + return result; +} + static bool hidesBaseClassFunctions(const AbstractMetaFunctionCPtr &f) { - return 0 == (f->attributes() - & (AbstractMetaFunction::OverriddenCppMethod | AbstractMetaFunction::FinalCppMethod)); + auto attributes = f->cppAttributes(); + return !attributes.testFlag(FunctionAttribute::Override) + && !attributes.testFlag(FunctionAttribute::Final); } -void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClass *scope, +void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope, AbstractMetaFunctionCList *overloads) { if (overloads->isEmpty() || scope->isNamespace() || scope->baseClasses().isEmpty()) @@ -2002,7 +2292,8 @@ void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClass *scope, AbstractMetaFunctionCList baseCandidates; - auto basePredicate = [&functionName, &seenSignatures, &baseCandidates](const AbstractMetaClass *b) { + auto basePredicate = [&functionName, &seenSignatures, &baseCandidates] + (const AbstractMetaClassCPtr &b) { for (const auto &f : b->functions()) { if (f->generateBinding() && f->name() == functionName) { const QString signature = f->minimalSignature(); @@ -2015,7 +2306,7 @@ void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClass *scope, return false; // Keep going }; - for (const auto *baseClass : scope->baseClasses()) + for (const auto &baseClass : scope->baseClasses()) recurseClassHierarchy(baseClass, basePredicate); // Remove the ones that are not made visible with using declarations @@ -2045,83 +2336,108 @@ void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClass *scope, } } -Generator::OptionDescriptions ShibokenGenerator::options() const +QList<OptionDescription> ShibokenGenerator::options() { - auto result = Generator::options(); - result.append({ - {QLatin1StringView(DISABLE_VERBOSE_ERROR_MESSAGES), + return { + {DISABLE_VERBOSE_ERROR_MESSAGES, u"Disable verbose error messages. Turn the python code hard to debug\n" "but safe few kB on the generated bindings."_s}, - {QLatin1StringView(PARENT_CTOR_HEURISTIC), + {PARENT_CTOR_HEURISTIC, u"Enable heuristics to detect parent relationship on constructors."_s}, - {QLatin1StringView(RETURN_VALUE_HEURISTIC), + {RETURN_VALUE_HEURISTIC, u"Enable heuristics to detect parent relationship on return values\n" "(USE WITH CAUTION!)"_s}, - {QLatin1StringView(USE_ISNULL_AS_NB_NONZERO), + {USE_ISNULL_AS_NB_BOOL, u"If a class have an isNull() const method, it will be used to compute\n" "the value of boolean casts"_s}, - {QLatin1StringView(USE_OPERATOR_BOOL_AS_NB_NONZERO), + {LEAN_HEADERS, + u"Forward declare classes in module headers"_s}, + {USE_OPERATOR_BOOL_AS_NB_BOOL, u"If a class has an operator bool, it will be used to compute\n" "the value of boolean casts"_s}, - {QLatin1StringView(NO_IMPLICIT_CONVERSIONS), + {NO_IMPLICIT_CONVERSIONS, u"Do not generate implicit_conversions for function arguments."_s}, - {QLatin1StringView(WRAPPER_DIAGNOSTICS), + {WRAPPER_DIAGNOSTICS, u"Generate diagnostic code around wrappers"_s} - }); - return result; + }; } -bool ShibokenGenerator::handleOption(const QString &key, const QString &value) +class ShibokenGeneratorOptionsParser : public OptionsParser { - if (Generator::handleOption(key, value)) - return true; - if (key == QLatin1StringView(PARENT_CTOR_HEURISTIC)) - return (m_useCtorHeuristic = true); - if (key == QLatin1StringView(RETURN_VALUE_HEURISTIC)) - return (m_userReturnValueHeuristic = true); - if (key == QLatin1StringView(DISABLE_VERBOSE_ERROR_MESSAGES)) - return (m_verboseErrorMessagesDisabled = true); - if (key == QLatin1StringView(USE_ISNULL_AS_NB_NONZERO)) - return (m_useIsNullAsNbNonZero = true); - if (key == QLatin1StringView(USE_OPERATOR_BOOL_AS_NB_NONZERO)) - return (m_useOperatorBoolAsNbNonZero = true); - if (key == QLatin1StringView(NO_IMPLICIT_CONVERSIONS)) { - return m_generateImplicitConversions = false; +public: + explicit ShibokenGeneratorOptionsParser(ShibokenGeneratorOptions *o) : m_options(o) {} + + bool handleBoolOption(const QString & key, OptionSource source) override; + +private: + ShibokenGeneratorOptions *m_options; +}; + +bool ShibokenGeneratorOptionsParser::handleBoolOption(const QString &key, OptionSource source) +{ + if (source == OptionSource::CommandLineSingleDash) + return false; + if (key == PARENT_CTOR_HEURISTIC) + return (m_options->useCtorHeuristic = true); + if (key == RETURN_VALUE_HEURISTIC) + return (m_options->userReturnValueHeuristic = true); + if (key == DISABLE_VERBOSE_ERROR_MESSAGES) + return (m_options->verboseErrorMessagesDisabled = true); + if (key == USE_ISNULL_AS_NB_BOOL || key == USE_ISNULL_AS_NB_NONZERO) { + return (m_options->useIsNullAsNbBool = true); + } + if (key == LEAN_HEADERS) + return (m_options->leanHeaders= true); + if (key == USE_OPERATOR_BOOL_AS_NB_BOOL || key == USE_OPERATOR_BOOL_AS_NB_NONZERO) { + return (m_options->useOperatorBoolAsNbBool = true); + } + if (key == NO_IMPLICIT_CONVERSIONS) { + m_options->generateImplicitConversions = false; return true; } - if (key == QLatin1StringView(WRAPPER_DIAGNOSTICS)) - return (m_wrapperDiagnostics = true); + if (key == WRAPPER_DIAGNOSTICS) + return (m_options->wrapperDiagnostics = true); return false; } +std::shared_ptr<OptionsParser> ShibokenGenerator::createOptionsParser() +{ + return std::make_shared<ShibokenGeneratorOptionsParser>(&m_options); +} + bool ShibokenGenerator::doSetup() { return true; } -bool ShibokenGenerator::useCtorHeuristic() const +bool ShibokenGenerator::useCtorHeuristic() +{ + return m_options.useCtorHeuristic; +} + +bool ShibokenGenerator::useReturnValueHeuristic() { - return m_useCtorHeuristic; + return m_options.userReturnValueHeuristic; } -bool ShibokenGenerator::useReturnValueHeuristic() const +bool ShibokenGenerator::useIsNullAsNbBool() { - return m_userReturnValueHeuristic; + return m_options.useIsNullAsNbBool; } -bool ShibokenGenerator::useIsNullAsNbNonZero() const +bool ShibokenGenerator::leanHeaders() { - return m_useIsNullAsNbNonZero; + return m_options.leanHeaders; } -bool ShibokenGenerator::useOperatorBoolAsNbNonZero() const +bool ShibokenGenerator::useOperatorBoolAsNbBool() { - return m_useOperatorBoolAsNbNonZero; + return m_options.useOperatorBoolAsNbBool; } -bool ShibokenGenerator::generateImplicitConversions() const +bool ShibokenGenerator::generateImplicitConversions() { - return m_generateImplicitConversions; + return m_options.generateImplicitConversions; } QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName) @@ -2131,19 +2447,24 @@ QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName) return result; } +QString ShibokenGenerator::cppApiVariableNameOld(const QString &moduleName) +{ + return "Sbk"_L1 + moduleCppPrefix(moduleName) + "Types"_L1; +} + QString ShibokenGenerator::cppApiVariableName(const QString &moduleName) { - return u"Sbk"_s + moduleCppPrefix(moduleName) + u"Types"_s; + return "Sbk"_L1 + moduleCppPrefix(moduleName) + "TypeStructs"_L1; } QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName) { - return u"Sbk"_s + moduleCppPrefix(moduleName) + u"ModuleObject"_s; + return "Sbk"_L1 + moduleCppPrefix(moduleName) + "ModuleObject"_L1; } QString ShibokenGenerator::convertersVariableName(const QString &moduleName) { - QString result = cppApiVariableName(moduleName); + QString result = cppApiVariableNameOld(moduleName); result.chop(1); result.append(u"Converters"_s); return result; @@ -2151,11 +2472,11 @@ QString ShibokenGenerator::convertersVariableName(const QString &moduleName) static QString processInstantiationsVariableName(const AbstractMetaType &type) { - QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()).toUpper(); + QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()); for (const auto &instantiation : type.instantiations()) { res += instantiation.isContainer() ? processInstantiationsVariableName(instantiation) - : u'_' + _fixedCppTypeName(instantiation.cppSignature()).toUpper(); + : u'_' + _fixedCppTypeName(instantiation.cppSignature()); } return res; } @@ -2164,29 +2485,30 @@ static void appendIndexSuffix(QString *s) { if (!s->endsWith(u'_')) s->append(u'_'); - s->append(QStringLiteral("IDX")); + s->append("IDX"_L1); } -QString ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClass *metaClass) +QString + ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass) { - const AbstractMetaClass *templateBaseClass = metaClass->templateBaseClass(); + const auto templateBaseClass = metaClass->templateBaseClass(); Q_ASSERT(templateBaseClass); QString result = u"SBK_"_s - + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); + + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()); for (const auto &instantiation : metaClass->templateBaseClassInstantiations()) result += processInstantiationsVariableName(instantiation); appendIndexSuffix(&result); return result; } -QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass) { return getTypeIndexVariableName(metaClass->typeEntry()); } -QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry *type) +QString ShibokenGenerator::getTypeIndexVariableName(TypeEntryCPtr type) { - if (type->isCppPrimitive()) - type = type->asPrimitive()->basicReferencedTypeEntry(); + if (isCppPrimitive(type)) + type = basicReferencedTypeEntry(type); QString result = u"SBK_"_s; // Disambiguate namespaces per module to allow for extending them. if (type->isNamespace()) { @@ -2194,7 +2516,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry *type) const int dot = package.lastIndexOf(u'.'); result += QStringView{package}.right(package.size() - (dot + 1)); } - result += _fixedCppTypeName(type->qualifiedCppName()).toUpper(); + result += _fixedCppTypeName(type->qualifiedCppName()); appendIndexSuffix(&result); return result; } @@ -2202,15 +2524,48 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType &type { QString result = u"SBK"_s; if (type.typeEntry()->isContainer()) - result += u'_' + moduleName().toUpper(); + result += u'_' + moduleName(); result += processInstantiationsVariableName(type); appendIndexSuffix(&result); return result; } -bool ShibokenGenerator::verboseErrorMessagesDisabled() const +void collectfromTypeEntry(TypeEntryCPtr entry, QStringList &typeNames) +{ + if (entry->shouldGenerate()) { + typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName(); + if (entry->isEnum()) { + auto ete = std::static_pointer_cast<const EnumTypeEntry>(entry); + if (ete->flags()) { + auto entry = ete->flags(); + typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName(); + } + } + } +} + +void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames) +{ + for (const auto &metaClass : api().classes()) { + collectfromTypeEntry(metaClass->typeEntry(), typeNames); + + for (const AbstractMetaEnum &metaEnum : metaClass->enums()) + collectfromTypeEntry(metaEnum.typeEntry(), typeNames); + + int smartPointerCountIndex = getMaxTypeIndex(); + for (const auto &smp : api().instantiatedSmartPointers()) { + auto entry = smp.type.typeEntry(); + typeNames[smartPointerCountIndex] = entry->qualifiedTargetLangName(); + ++smartPointerCountIndex; + } + } + for (const AbstractMetaEnum &metaEnum : api().globalEnums()) + collectfromTypeEntry(metaEnum.typeEntry(), typeNames); +} + +bool ShibokenGenerator::verboseErrorMessagesDisabled() { - return m_verboseErrorMessagesDisabled; + return m_options.verboseErrorMessagesDisabled; } bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const @@ -2240,9 +2595,9 @@ QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult } QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api, - const TypeEntry *type) + const TypeEntryCPtr &type) { - if (type->isExtendedCppPrimitive()) + if (isExtendedCppPrimitive(type)) return {}; const auto ctor = minimalConstructor(api, type); if (ctor.has_value()) @@ -2263,7 +2618,7 @@ QString ShibokenGenerator::pythonArgsAt(int i) void ShibokenGenerator::replaceTemplateVariables(QString &code, const AbstractMetaFunctionCPtr &func) const { - const AbstractMetaClass *cpp_class = func->ownerClass(); + const auto cpp_class = func->ownerClass(); if (cpp_class) code.replace(u"%TYPE"_s, cpp_class->name()); |