diff options
Diffstat (limited to 'sources/shiboken6/generator/shiboken/shibokengenerator.cpp')
-rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 2556 |
1 files changed, 1277 insertions, 1279 deletions
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index dc4648875..a1417e5d9 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -1,134 +1,119 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "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> #include <abstractmetafield.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetalang_helpers.h> +#include <usingmember.h> +#include <exception.h> #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> +#include <flagstypeentry.h> +#include <namespacetypeentry.h> +#include <primitivetypeentry.h> +#include <pythontypeentry.h> +#include <smartpointertypeentry.h> +#include <valuetypeentry.h> + #include <iostream> +#include "qtcompat.h" + #include <QtCore/QDir> #include <QtCore/QDebug> #include <QtCore/QRegularExpression> + +#include <algorithm> #include <limits> #include <memory> +#include <utility> -static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack"; -static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic"; -static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic"; -static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions"; -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 WRAPPER_DIAGNOSTICS[] = "wrapper-diagnostics"; - -const char *CPP_ARG = "cppArg"; -const char *CPP_ARG_REMOVED = "removed_cppArg"; -const char *CPP_RETURN_VAR = "cppResult"; -const char *CPP_SELF_VAR = "cppSelf"; -const char *NULL_PTR = "nullptr"; -const char *PYTHON_ARG = "pyArg"; -const char *PYTHON_ARGS = "pyArgs"; -const char *PYTHON_OVERRIDE_VAR = "pyOverride"; -const char *PYTHON_RETURN_VAR = "pyResult"; -const char *PYTHON_TO_CPP_VAR = "pythonToCpp"; -const char *SMART_POINTER_GETTER = "kSmartPointerGetter"; - -const char *CONV_RULE_OUT_VAR_SUFFIX = "_out"; -const char *BEGIN_ALLOW_THREADS = - "PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"; -const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"; - -// Return a prefix to fully qualify value, eg: -// resolveScopePrefix("Class::NestedClass::Enum::Value1", "Enum::Value1") -// -> "Class::NestedClass::") -static QString resolveScopePrefix(const QStringList &scopeList, const QString &value) -{ - QString name; - for (int i = scopeList.size() - 1 ; i >= 0; --i) { - const QString prefix = scopeList.at(i) + QLatin1String("::"); - if (value.startsWith(prefix)) - name.clear(); - else - name.prepend(prefix); - } - return name; -} +using namespace Qt::StringLiterals; + +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; -static inline QStringList splitClassScope(const AbstractMetaClass *scope) +QString CPP_ARG_N(int i) { - return scope->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts); + return CPP_ARG + QString::number(i); } -static QString resolveScopePrefix(const AbstractMetaClass *scope, const QString &value) +constexpr auto CPP_ARG_REMOVED_PREFIX = "removed_cppArg"_L1; + +QString CPP_ARG_REMOVED(int i) { - return scope - ? resolveScopePrefix(splitClassScope(scope), value) - : QString(); + return CPP_ARG_REMOVED_PREFIX + QString::number(i); } -static QString resolveScopePrefix(const AbstractMetaEnum &metaEnum, - const QString &value) +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 { - QStringList parts; - if (const AbstractMetaClass *scope = metaEnum.enclosingClass()) - parts.append(splitClassScope(scope)); - // Fully qualify the value which is required for C++ 11 enum classes. - if (!metaEnum.isAnonymous()) - parts.append(metaEnum.name()); - return resolveScopePrefix(parts, value); -} + 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) -using AbstractMetaTypeCache = QHash<QString, AbstractMetaType>; - -Q_GLOBAL_STATIC(AbstractMetaTypeCache, metaTypeFromStringCache) - static const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()"; static const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()"; static const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()"; @@ -141,14 +126,18 @@ const ShibokenGenerator::TypeSystemConverterRegExps & ShibokenGenerator::typeSystemConvRegExps() { static const TypeSystemConverterRegExps result = { - QRegularExpression(QLatin1String(CHECKTYPE_REGEX)), - QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX)), - QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX)), - QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX)) + QRegularExpression(QLatin1StringView(CHECKTYPE_REGEX)), + QRegularExpression(QLatin1StringView(ISCONVERTIBLE_REGEX)), + QRegularExpression(QLatin1StringView(CONVERTTOCPP_REGEX)), + QRegularExpression(QLatin1StringView(CONVERTTOPYTHON_REGEX)) }; 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; @@ -157,64 +146,65 @@ ShibokenGenerator::~ShibokenGenerator() = default; static const QHash<QString, QString> &primitiveTypesCorrespondences() { static const QHash<QString, QString> result = { - {QLatin1String("bool"), pyBoolT()}, - {QLatin1String("char"), sbkCharT()}, - {QLatin1String("signed char"), sbkCharT()}, - {QLatin1String("unsigned char"), sbkCharT()}, - {intT(), pyIntT()}, - {QLatin1String("signed int"), pyIntT()}, - {QLatin1String("uint"), pyIntT()}, - {QLatin1String("unsigned int"), pyIntT()}, - {shortT(), pyIntT()}, - {QLatin1String("ushort"), pyIntT()}, - {QLatin1String("signed short"), pyIntT()}, - {QLatin1String("signed short int"), pyIntT()}, - {unsignedShortT(), pyIntT()}, - {QLatin1String("unsigned short int"), pyIntT()}, - {longT(), pyIntT()}, - {doubleT(), pyFloatT()}, - {floatT(), pyFloatT()}, - {QLatin1String("unsigned long"), pyLongT()}, - {QLatin1String("signed long"), pyLongT()}, - {QLatin1String("ulong"), pyLongT()}, - {QLatin1String("unsigned long int"), pyLongT()}, - {QLatin1String("long long"), pyLongT()}, - {QLatin1String("__int64"), pyLongT()}, - {QLatin1String("unsigned long long"), pyLongT()}, - {QLatin1String("unsigned __int64"), pyLongT()}, - {QLatin1String("size_t"), 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; } -// Format units for C++->Python->C++ conversion -const QHash<QString, QString> &ShibokenGenerator::formatUnits() -{ - static const QHash<QString, QString> result = { - {QLatin1String("char"), QLatin1String("b")}, - {QLatin1String("unsigned char"), QLatin1String("B")}, - {intT(), QLatin1String("i")}, - {QLatin1String("unsigned int"), QLatin1String("I")}, - {shortT(), QLatin1String("h")}, - {unsignedShortT(), QLatin1String("H")}, - {longT(), QLatin1String("l")}, - {unsignedLongLongT(), QLatin1String("k")}, - {longLongT(), QLatin1String("L")}, - {QLatin1String("__int64"), QLatin1String("L")}, - {unsignedLongLongT(), QLatin1String("K")}, - {QLatin1String("unsigned __int64"), QLatin1String("K")}, - {doubleT(), QLatin1String("d")}, - {floatT(), QLatin1String("f")}, +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'}, + {u"unsigned int"_s, u'I'}, + {shortT, u'h'}, + {unsignedShortT, u'H'}, + {longT, u'l'}, + {unsignedLongLongT, u'k'}, + {longLongT, u'L'}, + {u"__int64"_s, u'L'}, + {unsignedLongLongT, u'K'}, + {u"unsigned __int64"_s, u'K'}, + {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()) - return translateTypeForWrapperMethod(*cType.arrayElementType(), context, options) + QLatin1String("[]"); + if (cType.isArray()) { + return translateTypeForWrapperMethod(*cType.arrayElementType(), context, options) + + u"[]"_s; + } if (avoidProtectedHack() && cType.isEnum()) { auto metaEnum = api().findAbstractMetaEnum(cType.typeEntry()); @@ -225,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) @@ -233,37 +223,158 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl && wrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper)); } -bool ShibokenGenerator::shouldWriteVirtualMethodNative(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) { - // PYSIDE-803: Extracted this because it is used multiple times. - const AbstractMetaClass *metaClass = func->ownerClass(); - return (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) - && ((func->isVirtual() || func->isAbstract()) - && !func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)); + FunctionGeneration result; + + const auto functionType = func->functionType(); + switch (functionType) { + case AbstractMetaFunction::ConversionOperator: + case AbstractMetaFunction::AssignmentOperatorFunction: + case AbstractMetaFunction::MoveAssignmentOperatorFunction: + case AbstractMetaFunction::DestructorFunction: + case AbstractMetaFunction::SignalFunction: + case AbstractMetaFunction::GetAttroFunction: + case AbstractMetaFunction::SetAttroFunction: + return result; + default: + if (func->isUserAdded() || func->usesRValueReferences() || !func->isWhiteListed()) + return result; + break; + } + + const bool notModifiedRemoved = !func->isModifiedRemoved(); + const bool isPrivate = func->isPrivate() && !func->isVisibilityModifiedToPrivate(); + switch (functionType) { + case AbstractMetaFunction::ConstructorFunction: + if (!isPrivate && notModifiedRemoved) + result.setFlag(FunctionGenerationFlag::WrapperConstructor); + return result; + case AbstractMetaFunction::CopyConstructorFunction: + if (!isPrivate && notModifiedRemoved) + result.setFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor); + return result; + case AbstractMetaFunction::NormalFunction: + case AbstractMetaFunction::SlotFunction: + if (avoidProtectedHack() && func->isProtected()) + result.setFlag(FunctionGenerationFlag::ProtectedWrapper); + break; + default: + break; + } + + // Check on virtuals (including operators). + const bool isAbstract = func->isAbstract(); + if (!(isAbstract || func->isVirtual()) + || 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() && isQObject(func->ownerClass())) { + const QString &name = func->name(); + if (name == u"metaObject"_s || name == u"qt_metacall") { + result.setFlag(FunctionGenerationFlag::QMetaObjectMethod); + return result; + } + } + + // Pure virtual functions need a default implementation even if private. + if (isAbstract || (notModifiedRemoved && !isPrivate)) + result.setFlag(FunctionGenerationFlag::VirtualMethod); + + return result; } -QString ShibokenGenerator::wrapperName(const AbstractMetaClass *metaClass) const +AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntryCPtr &t) const +{ + if (!generateImplicitConversions() || !t->isValue()) + return {}; + auto vte = std::static_pointer_cast<const ValueTypeEntry>(t); + auto customConversion = vte->customConversion(); + if (customConversion && customConversion->replaceOriginalTargetToNativeConversions()) + return {}; + + auto result = api().implicitConversions(t); + auto end = std::remove_if(result.begin(), result.end(), + [](const AbstractMetaFunctionCPtr &f) { + return f->isUserAdded(); + }); + result.erase(end, result.end()); + return result; +} + +QString ShibokenGenerator::wrapperName(const AbstractMetaClassCPtr &metaClass) { Q_ASSERT(shouldGenerateCppWrapper(metaClass)); QString result = metaClass->name(); if (metaClass->enclosingClass()) // is a inner class - result.replace(QLatin1String("::"), QLatin1String("_")); - return result + QLatin1String("Wrapper"); + result.replace(u"::"_s, u"_"_s); + 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() + QLatin1Char('.')); + fullClassName.prepend(enclosing->name() + u'.'); enclosing = enclosing->enclosingClass(); } - fullClassName.prepend(packageName() + QLatin1Char('.')); + 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; @@ -276,24 +387,29 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr if (func->isConstructor()) { funcName = fullClassName; if (forceFunc) - funcName.append(QLatin1String(".__init__")); + funcName.append(u".__init__"_s); } else { - funcName.prepend(fullClassName + QLatin1Char('.')); + funcName.prepend(fullClassName + u'.'); } } else { - funcName = packageName() + QLatin1Char('.') + func->name(); + funcName = packageName() + u'.' + func->name(); } return funcName; } +bool ShibokenGenerator::wrapperDiagnostics() +{ + return m_options.wrapperDiagnostics; +} + QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum) { QString result = metaEnum.fullName(); - result.replace(QLatin1Char('.'), QLatin1Char('_')); - result.replace(QLatin1String("::"), QLatin1String("_")); - return result + QLatin1String("_Surrogate"); + result.replace(u'.', u'_'); + result.replace(u"::"_s, u"_"_s); + return result + u"_Surrogate"_s; } QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &func) @@ -305,16 +421,16 @@ QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &f if (func->implementingClass()) { result = cpythonBaseName(func->implementingClass()->typeEntry()); if (func->isConstructor()) { - result += QLatin1String("_Init"); + result += u"_Init"_s; } else { - result += QLatin1String("Func_"); + result += u"Func_"_s; if (func->isOperatorOverload()) result += ShibokenGenerator::pythonOperatorFunctionName(func); else result += func->name(); } } else { - result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name(); + result = u"Sbk"_s + moduleName() + u"Module_"_s + func->name(); } return result; @@ -323,37 +439,37 @@ QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &f QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func) { if (!func->ownerClass()) - return QString(); - return cpythonBaseName(func->ownerClass()->typeEntry()) + QLatin1String("Method_") + 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) + QLatin1String("_getsetlist"); + return cpythonBaseName(metaClass) + u"_getsetlist"_s; } -QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass) { - return cpythonBaseName(metaClass) + QLatin1String("_setattro"); + return cpythonBaseName(metaClass) + u"_setattro"_s; } -QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass) { - return cpythonBaseName(metaClass) + QLatin1String("_getattro"); + 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) @@ -367,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); } @@ -381,159 +497,15 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec &proper static QString cpythonEnumFlagsName(const QString &moduleName, const QString &qualifiedCppName) { - QString result = QLatin1String("Sbk") + moduleName + QLatin1Char('_') + qualifiedCppName; - result.replace(QLatin1String("::"), QLatin1String("_")); + QString result = u"Sbk"_s + moduleName + u'_' + qualifiedCppName; + result.replace(u"::"_s, u"_"_s); return result; } -// Return the scope for fully qualifying the enumeration including trailing "::". -static QString searchForEnumScope(const AbstractMetaClass *metaClass, const QString &value) -{ - if (!metaClass) - return QString(); - for (const AbstractMetaEnum &metaEnum : metaClass->enums()) { - auto v = metaEnum.findEnumValue(value); - if (v.has_value()) - return resolveScopePrefix(metaEnum, value); - } - // PYSIDE-331: We need to also search the base classes. - QString ret = searchForEnumScope(metaClass->enclosingClass(), value); - if (ret.isEmpty()) - ret = searchForEnumScope(metaClass->baseClass(), value); - return ret; -} - -// Handle QFlags<> for guessScopeForDefaultValue() -QString ShibokenGenerator::guessScopeForDefaultFlagsValue(const AbstractMetaFunctionCPtr &func, - const AbstractMetaArgument &arg, - const QString &value) const -{ - // Numeric values -> "Options(42)" - static const QRegularExpression numberRegEx(QStringLiteral("^\\d+$")); // Numbers to flags - Q_ASSERT(numberRegEx.isValid()); - if (numberRegEx.match(value).hasMatch()) { - QString typeName = translateTypeForWrapperMethod(arg.type(), func->implementingClass()); - if (arg.type().isConstant()) - typeName.remove(0, sizeof("const ") / sizeof(char) - 1); - switch (arg.type().referenceType()) { - case NoReference: - break; - case LValueReference: - typeName.chop(1); - break; - case RValueReference: - typeName.chop(2); - break; - } - return typeName + QLatin1Char('(') + value + QLatin1Char(')'); - } - - // "Options(Option1 | Option2)" -> "Options(Class::Enum::Option1 | Class::Enum::Option2)" - static const QRegularExpression enumCombinationRegEx(QStringLiteral("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...) - Q_ASSERT(enumCombinationRegEx.isValid()); - const QRegularExpressionMatch match = enumCombinationRegEx.match(value); - if (match.hasMatch()) { - const QString expression = match.captured(2).trimmed(); - if (expression.isEmpty()) - return value; - const QStringList enumItems = expression.split(QLatin1Char('|')); - const QString scope = searchForEnumScope(func->implementingClass(), - enumItems.constFirst().trimmed()); - if (scope.isEmpty()) - return value; - QString result; - QTextStream str(&result); - str << match.captured(1) << '('; // Flag name - for (int i = 0, size = enumItems.size(); i < size; ++i) { - if (i) - str << '|'; - str << scope << enumItems.at(i).trimmed(); - } - str << ')'; - return result; - } - // A single flag "Option1" -> "Class::Enum::Option1" - return searchForEnumScope(func->implementingClass(), value) + value; -} - -/* - * This function uses some heuristics to find out the scope for a given - * argument default value since they must be fully qualified when used outside the class: - * class A { - * enum Enum { e1, e1 }; - * void foo(Enum e = e1); - * } - * should be qualified to: - * A::Enum cppArg0 = A::Enum::e1; - * - * New situations may arise in the future and - * this method should be updated, do it with care. - */ -QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunctionCPtr &func, - const AbstractMetaArgument &arg) const -{ - QString value = arg.defaultValueExpression(); - - if (value.isEmpty() || value == QLatin1String("{}") - || arg.hasModifiedDefaultValueExpression() - || arg.type().isPointer()) { - return value; - } - - static const QRegularExpression enumValueRegEx(QStringLiteral("^([A-Za-z_]\\w*)?$")); - Q_ASSERT(enumValueRegEx.isValid()); - // Do not qualify macros by class name, eg QSGGeometry(..., int t = GL_UNSIGNED_SHORT); - static const QRegularExpression macroRegEx(QStringLiteral("^[A-Z_][A-Z0-9_]*$")); - Q_ASSERT(macroRegEx.isValid()); - if (arg.type().isPrimitive() && macroRegEx.match(value).hasMatch()) - return value; - - QString prefix; - if (arg.type().isEnum()) { - auto metaEnum = api().findAbstractMetaEnum(arg.type().typeEntry()); - if (metaEnum.has_value()) - prefix = resolveScopePrefix(metaEnum.value(), value); - } else if (arg.type().isFlags()) { - value = guessScopeForDefaultFlagsValue(func, arg, value); - } else if (arg.type().typeEntry()->isValue()) { - auto metaClass = AbstractMetaClass::findClass(api().classes(), - arg.type().typeEntry()); - if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL")) - prefix = resolveScopePrefix(metaClass, value); - } else if (arg.type().isPrimitive() && arg.type().name() == intT()) { - if (enumValueRegEx.match(value).hasMatch() && func->implementingClass()) - prefix = resolveScopePrefix(func->implementingClass(), value); - } else if (arg.type().isPrimitive()) { - static const QRegularExpression unknowArgumentRegEx(QStringLiteral("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)] - Q_ASSERT(unknowArgumentRegEx.isValid()); - const QRegularExpressionMatch match = unknowArgumentRegEx.match(value); - if (match.hasMatch() && func->implementingClass()) { - for (const AbstractMetaField &field : func->implementingClass()->fields()) { - if (match.captured(1).trimmed() == field.name()) { - QString fieldName = field.name(); - if (field.isStatic()) { - prefix = resolveScopePrefix(func->implementingClass(), value); - fieldName.prepend(prefix); - prefix.clear(); - } else { - fieldName.prepend(QLatin1String(CPP_SELF_VAR) + QLatin1String("->")); - } - value.replace(match.captured(1), fieldName); - break; - } - } - } - } - - if (!prefix.isEmpty()) - value.prepend(prefix); - return value; -} - -QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry *enumEntry) +QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntryCPtr &enumEntry) { QString p = enumEntry->targetLangPackage(); - p.replace(QLatin1Char('.'), QLatin1Char('_')); + p.replace(u'.', u'_'); return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName()); } @@ -542,27 +514,25 @@ 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(QLatin1Char('.'), QLatin1Char('_')); + p.replace(u'.', u'_'); return cpythonEnumFlagsName(p, flagsEntry->originalName()); } 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()) + QLatin1String("SpecialCastFunction"); + 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); @@ -572,57 +542,58 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType &metaType, const QString &argName) { if (!metaType.isWrapperType()) - return QString(); - return QLatin1String("reinterpret_cast< ::") + metaType.cppSignature() - + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType) - + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))"); + 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 QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName() - + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type) - + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))"); + 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 ApiExtractorResult &api, - const AbstractMetaFunctionCPtr &func, int argIndex) +bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &func, + int argIndex) { - if (argIndex < 0 || argIndex >= func->arguments().count()) + if (argIndex < 0 || argIndex >= func->arguments().size()) return false; const AbstractMetaArgument &arg = func->arguments().at(argIndex); - if (isValueTypeWithCopyConstructorOnly(api, arg.type())) + if (arg.type().isValueTypeWithCopyConstructorOnly()) return true; // Argument type is not a pointer, a None rejection should not be // necessary because the type checking would handle that already. if (!arg.type().isPointer()) return false; - if (func->argumentRemoved(argIndex + 1)) + if (arg.isModifiedRemoved()) return false; for (const auto &funcMod : func->modifications()) { for (const ArgumentModification &argMod : funcMod.argument_mods()) { @@ -633,192 +604,152 @@ bool ShibokenGenerator::shouldRejectNullPointerArgument(const ApiExtractorResult return false; } -QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunctionCPtr &func, bool incRef) -{ - QString result; - const char objType = (incRef ? 'O' : 'N'); - const AbstractMetaArgumentList &arguments = func->arguments(); - for (const AbstractMetaArgument &arg : arguments) { - if (func->argumentRemoved(arg.argumentIndex() + 1)) - continue; - - const auto &type = arg.type(); - if (!func->typeReplaced(arg.argumentIndex() + 1).isEmpty()) { - result += QLatin1Char(objType); - } else if (arg.type().isObject() - || type.isValue() - || type.isValuePointer() - || type.isNativePointer() - || type.isEnum() - || type.isFlags() - || type.isContainer() - || type.isSmartPointer() - || type.referenceType() == LValueReference) { - result += QLatin1Char(objType); - } else if (type.isPrimitive()) { - const auto *ptype = - static_cast<const PrimitiveTypeEntry *>(type.typeEntry()); - if (ptype->basicReferencedTypeEntry()) - ptype = ptype->basicReferencedTypeEntry(); - const auto it = formatUnits().constFind(ptype->name()); - if (it != formatUnits().cend()) - result += it.value(); - else - result += QLatin1Char(objType); - } else if (type.isCString()) { - result += QLatin1Char('z'); - } else { - qCWarning(lcShiboken).noquote().nospace() - << "Method: " << func->ownerClass()->qualifiedCppName() - << "::" << func->signature() << " => Arg:" - << arg.name() << "index: " << arg.argumentIndex() - << " - cannot be handled properly. Use an inject-code to fix it!"; - result += QLatin1Char('?'); - } - } - return result; -} - QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType &type) { if (type.isCString()) - return QLatin1String("PyString"); + return u"PyString"_s; 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 = QLatin1String("Sbk_") + type->name(); + baseName = u"Sbk_"_s + type->name(); } else if (type->isPrimitive()) { - const auto *ptype = static_cast<const PrimitiveTypeEntry *>(type); - while (ptype->basicReferencedTypeEntry()) - ptype = ptype->basicReferencedTypeEntry(); - if (ptype->targetLangApiName() == ptype->name()) - baseName = pythonPrimitiveTypeName(ptype->name()); - else - baseName = ptype->targetLangApiName(); + 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: - case ContainerTypeEntry::StringListContainer: - case ContainerTypeEntry::LinkedListContainer: - case ContainerTypeEntry::VectorContainer: - case ContainerTypeEntry::StackContainer: - case ContainerTypeEntry::QueueContainer: - //baseName = "PyList"; - //break; - case ContainerTypeEntry::PairContainer: - //baseName = "PyTuple"; - baseName = cPySequenceT(); - break; - case ContainerTypeEntry::SetContainer: - baseName = QLatin1String("PySet"); - break; - case ContainerTypeEntry::MapContainer: - case ContainerTypeEntry::MultiMapContainer: - case ContainerTypeEntry::HashContainer: - case ContainerTypeEntry::MultiHashContainer: - baseName = QLatin1String("PyDict"); - 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(QLatin1String("::"), QLatin1String("_")); + 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) + QLatin1String("_TypeF()"); -} - -QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry *type) -{ - return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[') - + getTypeIndexVariableName(type) + QLatin1Char(']'); + return cpythonBaseName(type) + u"_TypeF()"_s; } QString ShibokenGenerator::converterObject(const AbstractMetaType &type) { if (type.isCString()) - return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<const char *>()"); + return u"Shiboken::Conversions::PrimitiveTypeConverter<const char *>()"_s; if (type.isVoidPointer()) - return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<void *>()"); + 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() - + QLatin1String(">(") + QString::number(nestedArrayTypes.size()) - + QLatin1Char(')'); + + u">("_s + QString::number(nestedArrayTypes.size()) + + u')'; } auto typeEntry = type.typeEntry(); if (typeEntry->isContainer() || typeEntry->isSmartPointer()) { return convertersVariableName(typeEntry->targetLangPackage()) - + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']'); + + u'[' + getTypeIndexVariableName(type) + u']'; } return converterObject(typeEntry); } -QString ShibokenGenerator::converterObject(const TypeEntry *type) +QString ShibokenGenerator::converterObject(const TypeEntryCPtr &type) { - if (type->isExtendedCppPrimitive()) - return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); - if (type->isWrapperType() || type->isEnum() || type->isFlags()) - return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type)); + 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() || type->isFlags()) + return QString::fromLatin1("PepType_SETP(reinterpret_cast<SbkEnumType *>(%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 = basicReferencedTypeEntry(pte); + if (pte->isPrimitive() && !isCppPrimitive(pte) && !pte->customConversion()) { + return u"Shiboken::Conversions::PrimitiveTypeConverter<"_s + + pte->qualifiedCppName() + u">()"_s; } - if (pte->basicReferencedTypeEntry()) - pte = pte->basicReferencedTypeEntry(); - if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion()) - return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName()); return convertersVariableName(type->targetLangPackage()) - + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']'); + + 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) + "].type"_L1; +} + +QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type) { - return cppApiVariableName(type.typeEntry()->targetLangPackage()) + QLatin1Char('[') - + getTypeIndexVariableName(type) + QLatin1Char(']'); + return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage()) + + u'[' + getTypeIndexVariableName(type) + "])"_L1; } -static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); } +QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type) +{ + return u"Shiboken::Module::get("_s + cppApiVariableName(type.typeEntry()->targetLangPackage()) + + u'[' + getTypeIndexVariableName(type) + "])"_L1; +} -QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion *toNative) +QString ShibokenGenerator::fixedCppTypeName(const TargetToNativeConversion &toNative) { - if (toNative->sourceType()) - return fixedCppTypeName(toNative->sourceType()); - return toNative->sourceTypeName(); + if (toNative.sourceType()) + return fixedCppTypeName(toNative.sourceType()); + return toNative.sourceTypeName(); } QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type) { @@ -827,22 +758,22 @@ QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type) static QString _fixedCppTypeName(QString typeName) { - typeName.remove(QLatin1Char(' ')); - typeName.replace(QLatin1Char('.'), QLatin1Char('_')); - typeName.replace(QLatin1Char(','), QLatin1Char('_')); - typeName.replace(QLatin1Char('<'), QLatin1Char('_')); - typeName.replace(QLatin1Char('>'), QLatin1Char('_')); - typeName.replace(QLatin1String("::"), QLatin1String("_")); - typeName.replace(QLatin1String("*"), QLatin1String("PTR")); - typeName.replace(QLatin1String("&"), QLatin1String("REF")); + typeName.remove(u' '); + typeName.replace(u'.', u'_'); + typeName.replace(u',', u'_'); + typeName.replace(u'<', u'_'); + typeName.replace(u'>', u'_'); + typeName.replace(u"::"_s, u"_"_s); + typeName.replace(u"*"_s, u"PTR"_s); + 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(); if (!type->generateCode()) { - typeName.prepend(QLatin1Char('_')); + typeName.prepend(u'_'); typeName.prepend(type->targetLangPackage()); } return _fixedCppTypeName(typeName); @@ -850,120 +781,66 @@ QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeN QString ShibokenGenerator::pythonPrimitiveTypeName(const QString &cppTypeName) { - QString rv = primitiveTypesCorrespondences().value(cppTypeName, QString()); - if (rv.isEmpty()) { - // activate this when some primitive types are missing, - // i.e. when shiboken itself fails to build. - // In general, this is valid while just called by isNumeric() - // used on Qt5, 2015-09-20 - if (false) { - std::cerr << "primitive type not found: " << qPrintable(cppTypeName) << std::endl; - abort(); - } - } - return rv; -} - -QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry *type) -{ - while (type->basicReferencedTypeEntry()) - type = type->basicReferencedTypeEntry(); - return pythonPrimitiveTypeName(type->name()); -} - -static const QHash<QString, QString> &pythonOperators() -{ - static const QHash<QString, QString> result = { - // call operator - {QLatin1String("operator()"), QLatin1String("call")}, - // Arithmetic operators - {QLatin1String("operator+"), QLatin1String("add")}, - {QLatin1String("operator-"), QLatin1String("sub")}, - {QLatin1String("operator*"), QLatin1String("mul")}, - {QLatin1String("operator/"), QLatin1String("div")}, - {QLatin1String("operator%"), QLatin1String("mod")}, - // Inplace arithmetic operators - {QLatin1String("operator+="), QLatin1String("iadd")}, - {QLatin1String("operator-="), QLatin1String("isub")}, - {QLatin1String("operator++"), QLatin1String("iadd")}, - {QLatin1String("operator--"), QLatin1String("isub")}, - {QLatin1String("operator*="), QLatin1String("imul")}, - {QLatin1String("operator/="), QLatin1String("idiv")}, - {QLatin1String("operator%="), QLatin1String("imod")}, - // Bitwise operators - {QLatin1String("operator&"), QLatin1String("and")}, - {QLatin1String("operator^"), QLatin1String("xor")}, - {QLatin1String("operator|"), QLatin1String("or")}, - {QLatin1String("operator<<"), QLatin1String("lshift")}, - {QLatin1String("operator>>"), QLatin1String("rshift")}, - {QLatin1String("operator~"), QLatin1String("invert")}, - // Inplace bitwise operators - {QLatin1String("operator&="), QLatin1String("iand")}, - {QLatin1String("operator^="), QLatin1String("ixor")}, - {QLatin1String("operator|="), QLatin1String("ior")}, - {QLatin1String("operator<<="), QLatin1String("ilshift")}, - {QLatin1String("operator>>="), QLatin1String("irshift")}, - // Comparison operators - {QLatin1String("operator=="), QLatin1String("eq")}, - {QLatin1String("operator!="), QLatin1String("ne")}, - {QLatin1String("operator<"), QLatin1String("lt")}, - {QLatin1String("operator>"), QLatin1String("gt")}, - {QLatin1String("operator<="), QLatin1String("le")}, - {QLatin1String("operator>="), QLatin1String("ge")}, - }; - return result; -} - -QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName) -{ - QString value = pythonOperators().value(cppOpFuncName); - if (value.isEmpty()) - return unknownOperator(); - value.prepend(QLatin1String("__")); - value.append(QLatin1String("__")); - return value; + const auto &mapping = primitiveTypesCorrespondences(); + const auto it = mapping.constFind(cppTypeName); + if (it == mapping.cend()) + throw Exception(u"Primitive type not found: "_s + cppTypeName); + return it.value(); } QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunctionCPtr &func) { - QString op = pythonOperatorFunctionName(func->originalName()); - if (op == unknownOperator()) - qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.data()); + QString op = Generator::pythonOperatorFunctionName(func->originalName()); + if (op.isEmpty()) { + qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.get()); + return "__UNKNOWN_OPERATOR__"_L1; + } if (func->arguments().isEmpty()) { - if (op == QLatin1String("__sub__")) - op = QLatin1String("__neg__"); - else if (op == QLatin1String("__add__")) - op = QLatin1String("__pos__"); + if (op == u"__sub__") + op = u"__neg__"_s; + else if (op == u"__add__") + op = u"__pos__"_s; } else if (func->isStatic() && func->arguments().size() == 2) { // If a operator overload function has 2 arguments and // is static we assume that it is a reverse operator. - op = op.insert(2, QLatin1Char('r')); + op = op.insert(2, u'r'); } return op; } -QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName) -{ - return QLatin1String("Py_") + pythonOperators().value(cppOpFuncName).toUpper(); -} - -QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunctionCPtr &func) +bool ShibokenGenerator::isNumber(const QString &cpythonApiName) { - return pythonRichCompareOperatorId(func->originalName()); + return cpythonApiName == pyFloatT || cpythonApiName == pyLongT + || cpythonApiName == pyBoolT; } -bool ShibokenGenerator::isNumber(const QString &cpythonApiName) +static std::optional<TypeSystem::CPythonType> + targetLangApiCPythonType(const PrimitiveTypeEntryCPtr &t) { - return cpythonApiName == pyIntT() - || cpythonApiName == pyFloatT() || cpythonApiName == pyLongT() - || cpythonApiName == pyBoolT(); + if (!t->hasTargetLangApiType()) + return {}; + const auto cte = t->targetLangApiType(); + if (cte->type() != TypeEntry::PythonType) + return {}; + 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; - return isNumber(pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))); + 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() && isNumber(it.value()); + } + const auto cPythonType = cPythonTypeOpt.value(); + return cPythonType == TypeSystem::CPythonType::Bool + || cPythonType == TypeSystem::CPythonType::Float + || cPythonType == TypeSystem::CPythonType::Integer; } bool ShibokenGenerator::isNumber(const AbstractMetaType &type) @@ -971,12 +848,19 @@ 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; - return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)) - == QLatin1String("PyInt"); + 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 cPythonTypeOpt.value() == TypeSystem::CPythonType::Integer; } bool ShibokenGenerator::isPyInt(const AbstractMetaType &type) @@ -984,305 +868,267 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType &type) return isPyInt(type.typeEntry()); } -bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api, - const TypeEntry *type) -{ - if (!type || !type->isValue()) - return false; - auto klass = AbstractMetaClass::findClass(api.classes(), type); - return klass != nullptr && klass->isValueTypeWithCopyConstructorOnly(); -} - -bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api, - const AbstractMetaType &type) -{ - return type.typeEntry()->isValue() - && isValueTypeWithCopyConstructorOnly(api, type.typeEntry()); -} - -bool ShibokenGenerator::valueTypeWithCopyConstructorOnlyPassed(const ApiExtractorResult &api, - const AbstractMetaType &type) -{ - return (type.passByValue() || type.passByConstRef()) - && isValueTypeWithCopyConstructorOnly(api, type); -} - bool ShibokenGenerator::isNullPtr(const QString &value) { - return value == QLatin1String("0") || value == QLatin1String("nullptr") - || value == QLatin1String("NULLPTR") || value == QLatin1String("{}"); + return value == u"0" || value == u"nullptr" + || value == u"NULLPTR" || value == u"{}"; } -QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType, - bool genericNumberType) const +QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType) { - if (metaType.typeEntry()->isCustom()) { - auto customCheckResult = guessCPythonCheckFunction(metaType.typeEntry()->name()); - if (!customCheckResult.checkFunction.isEmpty()) - return customCheckResult.checkFunction; - if (customCheckResult.type.has_value()) - metaType = customCheckResult.type.value(); + const auto typeEntry = metaType.typeEntry(); + if (typeEntry->isCustom()) { + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry); + if (cte->hasCheckFunction()) + return cte->checkFunction(); + throw Exception(msgUnknownCheckFunction(typeEntry)); } if (metaType.isExtendedCppPrimitive()) { if (metaType.isCString()) - return QLatin1String("Shiboken::String::check"); + return u"Shiboken::String::check"_s; if (metaType.isVoidPointer()) - return QLatin1String("PyObject_Check"); - return cpythonCheckFunction(metaType.typeEntry(), genericNumberType); + return u"true"_s; + return cpythonCheckFunction(typeEntry); } - auto typeEntry = metaType.typeEntry(); + if (typeEntry->isContainer()) { - QString typeCheck = QLatin1String("Shiboken::Conversions::"); + 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::StringListContainer - || type == ContainerTypeEntry::LinkedListContainer - || type == ContainerTypeEntry::VectorContainer - || type == ContainerTypeEntry::StackContainer - || type == ContainerTypeEntry::SetContainer - || type == ContainerTypeEntry::QueueContainer) { + || type == ContainerTypeEntry::SetContainer) { + const QString containerType = type == ContainerTypeEntry::SetContainer + ? u"Iterable"_s : u"Sequence"_s; const AbstractMetaType &type = metaType.instantiations().constFirst(); if (type.isPointerToWrapperType()) { - typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); + typeCheck += u"check"_s + containerType + u"Types("_s + + cpythonTypeNameExt(type) + u", "_s; } else if (type.isWrapperType()) { - typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>("); - typeCheck += cpythonTypeNameExt(type); - typeCheck += QLatin1String("), "); + typeCheck += u"convertible"_s + containerType + + u"Types("_s + cpythonTypeNameExt(type) + u", "_s; } else { - typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type)); + typeCheck += u"convertible"_s + containerType + + u"Types("_s + converterObject(type) + u", "_s; } } else if (type == ContainerTypeEntry::MapContainer || type == ContainerTypeEntry::MultiMapContainer - || type == ContainerTypeEntry::HashContainer - || type == ContainerTypeEntry::MultiHashContainer || type == ContainerTypeEntry::PairContainer) { - QString pyType = (type == ContainerTypeEntry::PairContainer) ? QLatin1String("Pair") : QLatin1String("Dict"); + + QString pyType; + if (type == ContainerTypeEntry::PairContainer) + pyType = u"Pair"_s; + else if (type == ContainerTypeEntry::MultiMapContainer) + pyType = u"MultiDict"_s; + else + pyType = u"Dict"_s; + const AbstractMetaType &firstType = metaType.instantiations().constFirst(); const AbstractMetaType &secondType = metaType.instantiations().constLast(); if (firstType.isPointerToWrapperType() && secondType.isPointerToWrapperType()) { - typeCheck += QString::fromLatin1("check%1Types(%2, %3, ") - .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType)); + QTextStream(&typeCheck) << "check" << pyType << "Types(" + << cpythonTypeNameExt(firstType) << ", " + << cpythonTypeNameExt(secondType) << ", "; } else { - typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ") - .arg(pyType, converterObject(firstType), - firstType.isPointerToWrapperType() ? QLatin1String("true") : QLatin1String("false"), - converterObject(secondType), - secondType.isPointerToWrapperType() ? QLatin1String("true") : QLatin1String("false")); + QTextStream(&typeCheck) << "convertible" << pyType << "Types(" + << converterObject(firstType) << ", " + << (firstType.isPointerToWrapperType() ? "true" : "false") + << ", " << converterObject(secondType) << ", " + << (secondType.isPointerToWrapperType() ? "true" :"false") + << ", "; } } return typeCheck; } - return cpythonCheckFunction(typeEntry, genericNumberType); + return cpythonCheckFunction(typeEntry); } -QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type, bool genericNumberType) const +QString ShibokenGenerator::cpythonCheckFunction(TypeEntryCPtr type) { if (type->isCustom()) { - AbstractMetaType metaType; - auto customCheckResult = guessCPythonCheckFunction(type->name()); - if (customCheckResult.type.has_value()) - return cpythonCheckFunction(customCheckResult.type.value(), genericNumberType); - return customCheckResult.checkFunction; + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(type); + if (cte->hasCheckFunction()) + return cte->checkFunction(); + throw Exception(msgUnknownCheckFunction(type)); } if (type->isEnum() || type->isFlags() || type->isWrapperType()) - return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type)); - if (type->isExtendedCppPrimitive()) { - return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)) - + QLatin1String("_Check"); - } - QString typeCheck; - if (type->targetLangApiName() == type->name()) - typeCheck = cpythonIsConvertibleFunction(api(), type); - else if (type->targetLangApiName() == QLatin1String("PyUnicode")) - typeCheck = QLatin1String("Shiboken::String::check"); - else - typeCheck = type->targetLangApiName() + QLatin1String("_Check"); - return typeCheck; -} - -ShibokenGenerator::CPythonCheckFunctionResult - ShibokenGenerator::guessCPythonCheckFunction(const QString &type) -{ - // PYSIDE-795: We abuse PySequence for iterables. - // This part handles the overrides in the XML files. - if (type == cPySequenceT()) - return {QLatin1String("Shiboken::String::checkIterable"), {}}; + return u"SbkObject_TypeCheck("_s + cpythonTypeNameExt(type) + u", "_s; - if (type == cPyTypeObjectT()) - return {QLatin1String("PyType_Check"), {}}; + if (type->isPrimitive()) + type = basicReferencedTypeEntry(type); - if (type == cPyBufferT()) - return {QLatin1String("Shiboken::Buffer::checkType"), {}}; + if (auto tla = type->targetLangApiType()) { + if (tla->hasCheckFunction()) + return tla->checkFunction(); + } - if (type == pyStrT()) - return {QLatin1String("Shiboken::String::check"), {}}; + if (isExtendedCppPrimitive(type)) + return pythonPrimitiveTypeName(type->name()) + u"_Check"_s; - CPythonCheckFunctionResult result; - result.type = buildAbstractMetaTypeFromString(type); - if (!result.type.has_value() || result.type->typeEntry()->isCustom()) - result.checkFunction = type + QLatin1String("_Check"); - return result; + return cpythonIsConvertibleFunction(type); } -QString ShibokenGenerator::cpythonIsConvertibleFunction(const ApiExtractorResult &api, const TypeEntry *type, - bool /* genericNumberType */, - bool /* checkExact */) +QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntryCPtr &type) { if (type->isWrapperType()) { - QString result = QLatin1String("Shiboken::Conversions::"); - result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(api, type)) - ? QLatin1String("isPythonToCppValueConvertible") - : QLatin1String("isPythonToCppPointerConvertible"); - result += QLatin1String("(reinterpret_cast<SbkObjectType *>(") - + cpythonTypeNameExt(type) + QLatin1String("), "); + QString result = u"Shiboken::Conversions::"_s; + bool isValue = false; + if (type->isValue()) { + const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(type); + isValue = !cte->isValueTypeWithCopyConstructorOnly(); + } + result += isValue ? u"isPythonToCppValueConvertible"_s + : u"isPythonToCppPointerConvertible"_s; + result += u"("_s + cpythonTypeNameExt(type) + u", "_s; return result; } return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ") .arg(converterObject(type)); } -QString ShibokenGenerator::cpythonIsConvertibleFunction(AbstractMetaType metaType, - bool /* genericNumberType */) const + +QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType &metaType) { - if (metaType.typeEntry()->isCustom()) { - auto customCheckResult = guessCPythonCheckFunction(metaType.typeEntry()->name()); - if (!customCheckResult.checkFunction.isEmpty()) - return customCheckResult.checkFunction; - if (customCheckResult.type.has_value()) - metaType = customCheckResult.type.value(); + const auto typeEntry = metaType.typeEntry(); + if (typeEntry->isCustom()) { + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry); + if (cte->hasCheckFunction()) + return cte->checkFunction(); + throw Exception(msgUnknownCheckFunction(typeEntry)); } - QString result = QLatin1String("Shiboken::Conversions::"); + QString result = u"Shiboken::Conversions::"_s; + if (metaType.generateOpaqueContainer()) { + result += u"pythonToCppReferenceConversion("_s + + converterObject(metaType) + u", "_s; + return result; + } if (metaType.isWrapperType()) { - if (metaType.isPointer() || isValueTypeWithCopyConstructorOnly(api(), metaType)) - result += QLatin1String("isPythonToCppPointerConvertible"); - else if (metaType.referenceType() == LValueReference) - result += QLatin1String("isPythonToCppReferenceConvertible"); - else - result += QLatin1String("isPythonToCppValueConvertible"); - result += QLatin1String("(reinterpret_cast<SbkObjectType *>(") - + cpythonTypeNameExt(metaType) + QLatin1String("), "); + if (metaType.isPointer() || metaType.isValueTypeWithCopyConstructorOnly()) { + result += u"pythonToCppPointerConversion"_s; + } else if (metaType.referenceType() == LValueReference + || (metaType.referenceType() == RValueReference && typeEntry->isObject())) { + result += u"pythonToCppReferenceConversion"_s; + } else { + result += u"pythonToCppValueConversion"_s; + } + result += u'(' + cpythonTypeNameExt(metaType) + u", "_s; return result; } - result += QLatin1String("isPythonToCppConvertible(") + converterObject(metaType); + result += u"pythonToCppConversion("_s + converterObject(metaType); // Write out array sizes if known const AbstractMetaTypeList nestedArrayTypes = metaType.nestedArrayTypes(); if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) { const int dim1 = metaType.arrayElementCount(); const int dim2 = nestedArrayTypes.constFirst().isArray() ? nestedArrayTypes.constFirst().arrayElementCount() : -1; - result += QLatin1String(", ") + QString::number(dim1) - + QLatin1String(", ") + QString::number(dim2); + result += u", "_s + QString::number(dim1) + + u", "_s + QString::number(dim2); } - result += QLatin1String(", "); + result += u", "_s; return result; } -QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg, - bool genericNumberType) const +QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg) { - return cpythonIsConvertibleFunction(metaArg.type(), genericNumberType); + return cpythonIsConvertibleFunction(metaArg.type()); } -QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass *metaClass) +QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass) { - return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast<SbkObjectType *>(") - + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), "); + 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 QLatin1String("Shiboken::Conversions::pythonToCpp") - + (type.isPointer() ? QLatin1String("Pointer") : QLatin1String("Copy")) - + QLatin1String("(reinterpret_cast<SbkObjectType *>(") - + cpythonTypeNameExt(type) + QLatin1String("), "); + 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; if (type.referenceType() == LValueReference && !(type.isValue() && type.isConstant()) && !type.isPointer()) { - conversion = QLatin1String("reference"); + conversion = u"reference"_s; } else if (type.isValue() || type.isSmartPointer()) { - conversion = QLatin1String("copy"); + conversion = u"copy"_s; } else { - conversion = QLatin1String("pointer"); + conversion = u"pointer"_s; } - QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") - + cpythonTypeNameExt(type) + QLatin1String("), "); - if (conversion != QLatin1String("pointer")) - result += QLatin1Char('&'); + QString result = u"Shiboken::Conversions::"_s + conversion + + u"ToPython("_s + + cpythonTypeNameExt(type) + u", "_s; + if (conversion != u"pointer") + result += u'&'; return result; } - return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2") - .arg(converterObject(type), - (type.isCString() || type.isVoidPointer()) ? QString() : QLatin1String("&")); + + 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() ? QLatin1String("copy") : QLatin1String("pointer"); - QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) - + QLatin1String("), "); - if (conversion != QLatin1String("pointer")) - result += QLatin1Char('&'); + const QString conversion = type->isValue() ? u"copy"_s : u"pointer"_s; + QString result = u"Shiboken::Conversions::"_s + conversion + + u"ToPython("_s + cpythonTypeNameExt(type) + + u", "_s; + if (conversion != u"pointer") + result += u'&'; return result; } - return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type)); + return u"Shiboken::Conversions::copyToPython("_s + + converterObject(type) + u", &"_s; } QString ShibokenGenerator::argumentString(const AbstractMetaFunctionCPtr &func, const AbstractMetaArgument &argument, Options options) const { - QString modified_type; - if (!(options & OriginalTypeDescription)) - modified_type = func->typeReplaced(argument.argumentIndex() + 1); - QString arg; + auto type = options.testFlag(OriginalTypeDescription) + ? argument.type() : argument.modifiedType(); - if (modified_type.isEmpty()) - arg = translateType(argument.type(), func->implementingClass(), options); - else - arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.')); + + QString arg = translateType(type, func->implementingClass(), options); + + if (argument.isTypeModified()) + arg.replace(u'$', u'.'); // Haehh? // "int a", "int a[]" - const int arrayPos = arg.indexOf(QLatin1Char('[')); + const auto arrayPos = arg.indexOf(u'['); if (arrayPos != -1) - arg.insert(arrayPos, QLatin1Char(' ') + argument.name()); + arg.insert(arrayPos, u' ' + argument.name()); else - arg.append(QLatin1Char(' ') + argument.name()); + arg.append(u' ' + argument.name()); if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues && !argument.originalDefaultValueExpression().isEmpty()) { QString default_value = argument.originalDefaultValueExpression(); - if (default_value == QLatin1String("NULL")) - default_value = QLatin1String(NULL_PTR); + if (default_value == u"NULL") + default_value = NULL_PTR; //WORKAROUND: fix this please - if (default_value.startsWith(QLatin1String("new "))) + if (default_value.startsWith(u"new ")) default_value.remove(0, 4); - arg += QLatin1String(" = ") + default_value; + arg += u" = "_s + default_value; } return arg; @@ -1300,21 +1146,23 @@ 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) { - if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1)) + 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; if (argUsed != 0) s << ", "; - writeArgument(s, func, arguments[i], options); + writeArgument(s, func, arg, options); argUsed++; } } -GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClass *c) const +GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClassCPtr &c) const { GeneratorContext result = Generator::contextForClass(c); if (shouldGenerateCppWrapper(c)) { @@ -1326,9 +1174,8 @@ GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClass *c) QString ShibokenGenerator::functionReturnType(const AbstractMetaFunctionCPtr &func, Options options) const { - QString modifiedReturnType = QString(func->typeReplaced(0)); - if (!modifiedReturnType.isEmpty() && !(options & OriginalTypeDescription)) - return modifiedReturnType; + if (func->isTypeModified() && !options.testFlag(OriginalTypeDescription)) + return func->modifiedTypeName(); return translateType(func->type(), func->implementingClass(), options); } @@ -1340,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 @@ -1371,14 +1220,18 @@ void ShibokenGenerator::writeArgumentNames(TextStream &s, int argCount = 0; for (const auto &argument : arguments) { const int index = argument.argumentIndex() + 1; - if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(index))) + if (options.testFlag(Generator::SkipRemovedArguments) && argument.isModifiedRemoved()) continue; + const auto &type = argument.type(); + if (argCount > 0) + s << ", "; + const bool isVirtualCall = options.testFlag(Option::VirtualCall); + const bool useStdMove = isVirtualCall && type.isUniquePointer() && type.passByValue(); + s << (useStdMove ? stdMove(argument.name()) : argument.name()); - s << ((argCount > 0) ? ", " : "") << argument.name(); - - if (((options & Generator::VirtualCall) == 0) - && (!func->conversionRule(TypeSystem::NativeCode, index).isEmpty() - || !func->conversionRule(TypeSystem::TargetLangCode, index).isEmpty()) + if (!isVirtualCall + && (func->hasConversionRule(TypeSystem::NativeCode, index) + || func->hasConversionRule(TypeSystem::TargetLangCode, index)) && !func->isConstructor()) { s << CONV_RULE_OUT_VAR_SUFFIX; } @@ -1397,55 +1250,18 @@ void ShibokenGenerator::writeFunctionCall(TextStream &s, s << ')'; } -void ShibokenGenerator::writeUnusedVariableCast(TextStream &s, const QString &variableName) -{ - s << "SBK_UNUSED(" << variableName<< ")\n"; -} - -static bool filterFunction(const AbstractMetaFunctionCPtr &func, bool avoidProtectedHack) -{ - switch (func->functionType()) { - case AbstractMetaFunction::DestructorFunction: - case AbstractMetaFunction::SignalFunction: - case AbstractMetaFunction::GetAttroFunction: - case AbstractMetaFunction::SetAttroFunction: - return false; - default: - break; - } - if (func->usesRValueReferences()) - return false; - if (func->isModifiedRemoved() && !func->isAbstract() - && (!avoidProtectedHack || !func->isProtected())) { - return false; - } - return true; -} - -AbstractMetaFunctionCList ShibokenGenerator::filterFunctions(const AbstractMetaClass *metaClass) const -{ - AbstractMetaFunctionCList result; - const AbstractMetaFunctionCList &funcs = metaClass->functions(); - result.reserve(funcs.size()); - for (const auto &func : funcs) { - if (filterFunction(func, avoidProtectedHack())) - result.append(func); - } - return result; -} - 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)) + if (!shouldGenerate(metaClass->typeEntry())) continue; const auto &overloads = metaClass->operatorOverloads(OperatorQueryOption::ConversionOp); 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; @@ -1455,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 (!shouldGenerateTypeEntry(type) || !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; } @@ -1476,20 +1290,20 @@ 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(); - while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t')) + while (str.at(pos) == u' ' || str.at(pos) == u'\t') ++pos; - if (str.at(pos) == QLatin1Char('(')) + if (str.at(pos) == u'(') ++pos; int begin = pos; int counter = 1; while (counter != 0) { - if (str.at(pos) == QLatin1Char('(')) + if (str.at(pos) == u'(') ++counter; - else if (str.at(pos) == QLatin1Char(')')) + else if (str.at(pos) == u')') --counter; ++pos; } @@ -1514,14 +1328,13 @@ void ShibokenGenerator::processClassCodeSnip(QString &code, const GeneratorConte auto metaClass = context.metaClass(); // Replace template variable by the Python Type object // for the class context in which the variable is used. - code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(metaClass) + QLatin1String("->type")); - const QString className = context.useWrapper() - ? context.wrapperName() : metaClass->qualifiedCppName(); - code.replace(QLatin1String("%TYPE"), className); - code.replace(QLatin1String("%CPPTYPE"), metaClass->name()); + code.replace(u"%PYTHONTYPEOBJECT"_s, + u"(*"_s + cpythonTypeName(metaClass) + u')'); + const QString className = context.effectiveClassName(); + 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 @@ -1539,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, @@ -1548,38 +1370,30 @@ 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) { - bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty(); - const bool argRemoved = func->argumentRemoved(i+1); + const bool hasConversionRule = func->hasConversionRule(convLang, i + 1); + const bool argRemoved = arg.isModifiedRemoved(); if (argRemoved) ++removed; if (argRemoved && hasConversionRule) - argValue = arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); + argValue = arg.name() + CONV_RULE_OUT_VAR_SUFFIX; else if (argRemoved || (lastArg && arg.argumentIndex() > lastArg->argumentIndex())) - argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i); + argValue = CPP_ARG_REMOVED(i); if (!argRemoved && argValue.isEmpty()) { int argPos = i - removed; - AbstractMetaType type = arg.type(); - QString typeReplaced = func->typeReplaced(arg.argumentIndex() + 1); - if (!typeReplaced.isEmpty()) { - auto builtType = buildAbstractMetaTypeFromString(typeReplaced); - if (builtType.has_value()) - type = builtType.value(); - } + AbstractMetaType type = arg.modifiedType(); if (type.typeEntry()->isCustom()) { argValue = usePyArgs - ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG); + ? pythonArgsAt(argPos) : PYTHON_ARG; } else { argValue = hasConversionRule - ? arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX) - : QLatin1String(CPP_ARG) + QString::number(argPos); - if (type.isWrapperType()) { - if (type.referenceType() == LValueReference && !type.isPointer()) - argValue.prepend(QLatin1Char('*')); - } + ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX + : CPP_ARG_N(argPos); + const auto generatorArg = GeneratorArgument::fromMetaType(type); + AbstractMetaType::applyDereference(&argValue, generatorArg.indirections); } } } else { @@ -1617,138 +1431,153 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, s << "// Begin code injection\n" << code << "// End of code injection\n\n"; } +static void replacePyArg0(TypeSystem::Language language, QString *code) +{ + static constexpr auto pyArg0 = "%PYARG_0"_L1; + + if (!code->contains(pyArg0)) + return; + if (language != TypeSystem::NativeCode) { + code->replace(pyArg0, PYTHON_RETURN_VAR); + return; + } + + // pyResult is an AutoDecRef in overridden methods of wrapper classes which + // has a cast operator for PyObject *. This may however not work in all + // situations (fex _PyVarObject_CAST(op) defined as ((PyVarObject*)(op))). + // Append ".object()" unless it is followed by a '.' indicating explicit + // AutoDecRef member invocation. + static const QString pyObject = PYTHON_RETURN_VAR + u".object()"_s; + qsizetype pos{}; + while ( (pos = code->indexOf(pyArg0)) >= 0) { + const auto next = pos + pyArg0.size(); + const bool memberInvocation = next < code->size() && code->at(next) == u'.'; + code->replace(pos, pyArg0.size(), + memberInvocation ? PYTHON_RETURN_VAR : pyObject); + } +} + void ShibokenGenerator::writeCodeSnips(TextStream &s, const CodeSnipList &codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language, const AbstractMetaFunctionCPtr &func, + bool usePyArgs, const AbstractMetaArgument *lastArg) const { QString code = getCodeSnippets(codeSnips, position, language); if (code.isEmpty()) return; - // Calculate the real number of arguments. - int argsRemoved = 0; - for (int i = 0; i < func->arguments().size(); i++) { - if (func->argumentRemoved(i+1)) - argsRemoved++; - } - - const auto &groups = func->implementingClass() - ? getFunctionGroups(func->implementingClass()) - : getGlobalFunctionGroups(); - OverloadData od(groups[func->name()], api()); - bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od); - // Replace %PYARG_# variables. - code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR)); + 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, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]")); + 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(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG)); + code.replace(u"%PYARG_1"_s, PYTHON_ARG); } } 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, QLatin1String("PyTuple_SET_ITEM(") - + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1, \\2)")); - code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(") - + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1)")); + code.replace(pyArgsAttributionRegex, u"PyTuple_SET_ITEM("_s + + PYTHON_ARGS + u".object(), \\1-1, \\2)"_s); + code.replace(pyArgsRegex, u"PyTuple_GET_ITEM("_s + + PYTHON_ARGS + u".object(), \\1-1)"_s); } // Replace %ARG#_TYPE variables. const AbstractMetaArgumentList &arguments = func->arguments(); for (const AbstractMetaArgument &arg : arguments) { - QString argTypeVar = QStringLiteral("%ARG%1_TYPE").arg(arg.argumentIndex() + 1); + QString argTypeVar = u"%ARG"_s + QString::number(arg.argumentIndex() + 1) + + u"_TYPE"_s; QString argTypeVal = arg.type().cppSignature(); 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. if (func->isConstructor()) { - code.replace(QLatin1String("%0."), QLatin1String("cptr->")); - code.replace(QLatin1String("%0"), QLatin1String("cptr")); + code.replace(u"%0."_s, u"cptr->"_s); + code.replace(u"%0"_s, u"cptr"_s); } else if (!func->isVoid()) { QString returnValueOp = func->type().isPointerToWrapperType() - ? QLatin1String("%1->") : QLatin1String("%1."); + ? u"%1->"_s : u"%1."_s; if (func->type().isWrapperType()) - code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR))); - code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR)); + code.replace(u"%0."_s, returnValueOp.arg(CPP_RETURN_VAR)); + code.replace(u"%0"_s, CPP_RETURN_VAR); } // Replace template variable for self Python object. QString pySelf = language == TypeSystem::NativeCode - ? QLatin1String("pySelf") : QLatin1String("self"); - code.replace(QLatin1String("%PYSELF"), pySelf); + ? u"pySelf"_s : u"self"_s; + code.replace(u"%PYSELF"_s, pySelf); // Replace template variable for a pointer to C++ of this object. if (func->implementingClass()) { - QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->"); + QString replacement = func->isStatic() ? u"%1::"_s : u"%1->"_s; QString cppSelf; if (func->isStatic()) cppSelf = func->ownerClass()->qualifiedCppName(); else if (language == TypeSystem::NativeCode) - cppSelf = QLatin1String("this"); + cppSelf = u"this"_s; else - cppSelf = QLatin1String(CPP_SELF_VAR); + cppSelf = CPP_SELF_VAR; // On comparison operator CPP_SELF_VAR is always a reference. if (func->isComparisonOperator()) - replacement = QLatin1String("%1."); + replacement = u"%1."_s; if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) { QString methodCallArgs = getArgumentsFromMethodCall(code); if (!methodCallArgs.isEmpty()) { - const QString pattern = QStringLiteral("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs); - if (func->name() == QLatin1String("metaObject")) { + const QString pattern = u"%CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u')'; + QString replacement = u"(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>("_s + + pySelf + u")) ? "_s; + if (func->name() == u"metaObject") { QString wrapperClassName = wrapperName(func->ownerClass()); QString cppSelfVar = avoidProtectedHack() - ? QLatin1String("%CPPSELF") - : QStringLiteral("reinterpret_cast<%1 *>(%CPPSELF)").arg(wrapperClassName); - code.replace(pattern, - QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(%1))" - " ? %2->::%3::%FUNCTION_NAME(%4)" - " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf, cppSelfVar, wrapperClassName, methodCallArgs)); + ? u"%CPPSELF"_s + : u"reinterpret_cast<"_s + wrapperClassName + u" *>(%CPPSELF)"_s; + replacement += cppSelfVar + u"->::"_s + wrapperClassName + + u"::%FUNCTION_NAME("_s + methodCallArgs + + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s; } else { - code.replace(pattern, - QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(%1))" - " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)" - " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf, methodCallArgs)); + replacement += u"%CPPSELF->::%TYPE::%FUNCTION_NAME("_s + methodCallArgs + + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s; } + code.replace(pattern, replacement); } } - code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf)); - code.replace(QLatin1String("%CPPSELF"), cppSelf); + code.replace(u"%CPPSELF."_s, replacement.arg(cppSelf)); + code.replace(u"%CPPSELF"_s, cppSelf); - if (code.indexOf(QLatin1String("%BEGIN_ALLOW_THREADS")) > -1) { - if (code.count(QLatin1String("%BEGIN_ALLOW_THREADS")) == code.count(QLatin1String("%END_ALLOW_THREADS"))) { - code.replace(QLatin1String("%BEGIN_ALLOW_THREADS"), QLatin1String(BEGIN_ALLOW_THREADS)); - code.replace(QLatin1String("%END_ALLOW_THREADS"), QLatin1String(END_ALLOW_THREADS)); + if (code.indexOf(u"%BEGIN_ALLOW_THREADS") > -1) { + if (code.count(u"%BEGIN_ALLOW_THREADS"_s) == code.count(u"%END_ALLOW_THREADS"_s)) { + code.replace(u"%BEGIN_ALLOW_THREADS"_s, BEGIN_ALLOW_THREADS); + code.replace(u"%END_ALLOW_THREADS"_s, END_ALLOW_THREADS); } else { qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch"; } @@ -1757,11 +1586,11 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, // replace template variable for the Python Type object for the // class implementing the method in which the code snip is written if (func->isStatic()) { - code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(func->implementingClass()) + QLatin1String("->type")); + code.replace(u"%PYTHONTYPEOBJECT"_s, + u"(*"_s + cpythonTypeName(func->implementingClass()) + u')'); } else { - code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->")); - code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type")); + code.replace(u"%PYTHONTYPEOBJECT."_s, pySelf + u"->ob_type->"_s); + code.replace(u"%PYTHONTYPEOBJECT"_s, pySelf + u"->ob_type"_s); } } @@ -1771,28 +1600,23 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, QStringList args; for (const ArgumentVarReplacementPair &pair : argReplacements) { - if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED))) + if (pair.second.startsWith(CPP_ARG_REMOVED_PREFIX)) continue; args << pair.second; } - code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", "))); + code.replace(u"%ARGUMENT_NAMES"_s, args.join(u", "_s)); for (const ArgumentVarReplacementPair &pair : argReplacements) { const AbstractMetaArgument &arg = pair.first; int idx = arg.argumentIndex() + 1; - AbstractMetaType type = arg.type(); - QString typeReplaced = func->typeReplaced(arg.argumentIndex() + 1); - if (!typeReplaced.isEmpty()) { - auto builtType = buildAbstractMetaTypeFromString(typeReplaced); - if (builtType.has_value()) - type = builtType.value(); - } + AbstractMetaType type = arg.modifiedType(); if (type.isWrapperType()) { QString replacement = pair.second; - if (type.referenceType() == LValueReference && !type.isPointer()) - replacement.remove(0, 1); + const auto generatorArg = GeneratorArgument::fromMetaType(type); + if (generatorArg.indirections > 0) + AbstractMetaType::stripDereference(&replacement); if (type.referenceType() == LValueReference || type.isPointer()) - code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->")); + code.replace(u'%' + QString::number(idx) + u'.', replacement + u"->"_s); } code.replace(CodeSnipAbstract::placeHolderRegex(idx), pair.second); } @@ -1801,11 +1625,11 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple // containing the converted virtual method arguments received from C++ to be passed // to the Python override. - code.replace(QLatin1String("%PYTHON_ARGUMENTS"), QLatin1String(PYTHON_ARGS)); + code.replace(u"%PYTHON_ARGUMENTS"_s, PYTHON_ARGS); // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method // override for the C++ virtual method in which this piece of code was inserted - code.replace(QLatin1String("%PYTHON_METHOD_OVERRIDE"), QLatin1String(PYTHON_OVERRIDE_VAR)); + code.replace(u"%PYTHON_METHOD_OVERRIDE"_s, PYTHON_OVERRIDE_VAR); } if (avoidProtectedHack()) { @@ -1814,31 +1638,34 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, // name and if any of them is of the protected visibility. This is used to replace // calls to %FUNCTION_NAME on user written custom code for calls to the protected // dispatcher. - bool hasProtectedOverload = false; - if (func->isUserAdded()) { - const auto &funcs = getFunctionOverloads(func->ownerClass(), func->name()); - for (const auto &f : funcs) - hasProtectedOverload |= f->isProtected(); + bool isProtected = func->isProtected(); + auto owner = func->ownerClass(); + if (!isProtected && func->isUserAdded() && owner != nullptr) { + const auto &funcs = getFunctionGroups(owner).value(func->name()); + isProtected = std::any_of(funcs.cbegin(), funcs.cend(), + [](const AbstractMetaFunctionCPtr &f) { + return f->isProtected(); + }); } - if (func->isProtected() || hasProtectedOverload) { - code.replace(QLatin1String("%TYPE::%FUNCTION_NAME"), - QStringLiteral("%1::%2_protected") - .arg(wrapperName(func->ownerClass()), func->originalName())); - code.replace(QLatin1String("%FUNCTION_NAME"), - func->originalName() + QLatin1String("_protected")); + if (isProtected) { + code.replace(u"%TYPE::%FUNCTION_NAME"_s, + wrapperName(func->ownerClass()) + "::"_L1 + + func->originalName() + "_protected"_L1); + code.replace(u"%FUNCTION_NAME"_s, + func->originalName() + u"_protected"_s); } } if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) - code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass())); + code.replace(u"%TYPE"_s, wrapperName(func->ownerClass())); if (func->ownerClass()) - code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name()); + code.replace(u"%CPPTYPE"_s, func->ownerClass()->name()); replaceTemplateVariables(code, func); - processCodeSnip(code); + processCodeSnip(code, func->classQualifiedSignature()); s << "// Begin code injection\n" << code << "// End of code injection\n\n"; } @@ -1846,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(); } @@ -1859,15 +1686,15 @@ static QString miniNormalizer(const QString &varType) QString normalized = varType.trimmed(); if (normalized.isEmpty()) return normalized; - if (normalized.startsWith(QLatin1String("::"))) + if (normalized.startsWith(u"::")) normalized.remove(0, 2); QString suffix; - while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) { - suffix.prepend(normalized.at(normalized.count() - 1)); + while (normalized.endsWith(u'*') || normalized.endsWith(u'&')) { + suffix.prepend(normalized.at(normalized.size() - 1)); normalized.chop(1); normalized = normalized.trimmed(); } - const QString result = normalized + QLatin1Char(' ') + suffix; + const QString result = normalized + u' ' + suffix; return result.trimmed(); } // The position must indicate the first character after the opening '('. @@ -1878,7 +1705,7 @@ static QString getConverterTypeSystemVariableArgument(const QString &code, int p QString arg; int parenthesisDepth = 0; int count = 0; - while (pos + count < code.count()) { + while (pos + count < code.size()) { char c = code.at(pos+count).toLatin1(); // toAscii is gone if (c == '(') { ++parenthesisDepth; @@ -1892,22 +1719,22 @@ static QString getConverterTypeSystemVariableArgument(const QString &code, int p ++count; } if (parenthesisDepth != 0) - qFatal("Unbalanced parenthesis on type system converter variable call."); + throw Exception("Unbalanced parenthesis on type system converter variable call."); return arg; } const QHash<int, QString> &ShibokenGenerator::typeSystemConvName() { static const QHash<int, QString> result = { - {TypeSystemCheckFunction, QLatin1String("checkType")}, - {TypeSystemIsConvertibleFunction, QLatin1String("isConvertible")}, - {TypeSystemToCppFunction, QLatin1String("toCpp")}, - {TypeSystemToPythonFunction, QLatin1String("toPython")} + {TypeSystemCheckFunction, u"checkType"_s}, + {TypeSystemIsConvertibleFunction, u"isConvertible"_s}, + {TypeSystemToCppFunction, u"toCpp"_s}, + {TypeSystemToPythonFunction, u"toPython"_s} }; return result; } -using StringPair = QPair<QString, QString>; +using StringPair = std::pair<QString, QString>; void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString &code) const @@ -1920,11 +1747,11 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa QString conversionString = list.constFirst(); const QString &conversionTypeName = list.constLast(); QString message; - const auto conversionTypeO = buildAbstractMetaTypeFromString(conversionTypeName, &message); + const auto conversionTypeO = AbstractMetaType::fromString(conversionTypeName, &message); if (!conversionTypeO.has_value()) { - qFatal("%s", qPrintable(msgCannotFindType(conversionTypeName, - typeSystemConvName().value(converterVariable), - message))); + throw Exception(msgCannotFindType(conversionTypeName, + typeSystemConvName().value(converterVariable), + message)); } const auto conversionType = conversionTypeO.value(); QString conversion; @@ -1933,7 +1760,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa StringStream c(TextStream::Language::Cpp); int end = match.capturedStart(); int start = end; - while (start > 0 && code.at(start) != QLatin1Char('\n')) + while (start > 0 && code.at(start) != u'\n') --start; while (code.at(start).isSpace()) ++start; @@ -1942,21 +1769,13 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa varType = miniNormalizer(varType); QString varName = list.at(1).trimmed(); if (!varType.isEmpty()) { - const QString conversionSignature = conversionType.cppSignature(); - if (varType != QLatin1String("auto") && varType != conversionSignature) - qFatal("%s", qPrintable(msgConversionTypesDiffer(varType, conversionSignature))); - c << getFullTypeName(conversionType) << ' ' << varName; - writeMinimalConstructorExpression(c, api(), conversionType); - c << ";\n"; + c << getFullTypeName(conversionType) << ' ' << varName + << minimalConstructorExpression(api(), conversionType) << ";\n"; } c << cpythonToCppConversionFunction(conversionType); QString prefix; - if (varName.startsWith(QLatin1Char('*'))) { - varName.remove(0, 1); - varName = varName.trimmed(); - } else { - prefix = QLatin1Char('&'); - } + if (!AbstractMetaType::stripDereference(&varName)) + prefix = u'&'; QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd()); conversionString += arg; c << arg << ", " << prefix << '(' << varName << ')'; @@ -1966,8 +1785,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa case TypeSystemCheckFunction: conversion = cpythonCheckFunction(conversionType); if (conversionType.typeEntry()->isPrimitive() - && (conversionType.typeEntry()->name() == cPyObjectT() - || !conversion.endsWith(QLatin1Char(' ')))) { + && (conversionType.typeEntry()->name() == cPyObjectT + || !conversion.endsWith(u' '))) { conversion += u'('; break; } @@ -1984,20 +1803,22 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd()); conversionString += arg; if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) { - qFatal("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%s'", - qPrintable(code)); + QString m; + QTextStream(&m) << "Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '" + << code << '\''; + throw Exception(m); } - if (conversion.contains(QLatin1String("%in"))) { - conversion.prepend(QLatin1Char('(')); - conversion.replace(QLatin1String("%in"), arg); + if (conversion.contains(u"%in")) { + conversion.prepend(u'('); + conversion.replace(u"%in"_s, arg); } else { conversion += arg; } } } - 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); } @@ -2006,9 +1827,9 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &con { if (func->injectedCodeContains(u"%FUNCTION_NAME(")) return true; - QString funcCall = func->originalName() + QLatin1Char('('); + QString funcCall = func->originalName() + u'('; if (func->isConstructor()) - funcCall.prepend(QLatin1String("new ")); + funcCall.prepend(u"new "_s); if (func->injectedCodeContains(funcCall)) return true; if (!func->isConstructor()) @@ -2018,18 +1839,17 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &con const auto owner = func->ownerClass(); if (!owner->isPolymorphic()) return false; - const QString className = context.useWrapper() - ? context.wrapperName() : owner->qualifiedCppName(); - const QString wrappedCtorCall = QLatin1String("new ") + className + QLatin1Char('('); + const QString wrappedCtorCall = u"new "_s + context.effectiveClassName() + u'('; 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()) { @@ -2041,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; @@ -2053,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; @@ -2069,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() @@ -2086,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() @@ -2110,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; @@ -2119,64 +1940,50 @@ const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const Abs return getMultipleInheritingClass(metaClass->baseClass()); } -QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName) +QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName) { - return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h"); + return moduleCppPrefix(moduleName).toLower() + "_python"_L1; } -std::optional<AbstractMetaType> - ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature, - QString *errorMessage) +QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName) { - typeSignature = typeSignature.trimmed(); - if (typeSignature.startsWith(QLatin1String("::"))) - typeSignature.remove(0, 2); - - auto &cache = *metaTypeFromStringCache(); - auto it = cache.find(typeSignature); - if (it == cache.end()) { - auto metaType = - AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage); - if (Q_UNLIKELY(!metaType.has_value())) { - if (errorMessage) - errorMessage->prepend(msgCannotBuildMetaType(typeSignature)); - return {}; - } - it = cache.insert(typeSignature, metaType.value()); - } - return it.value(); + return getModuleHeaderFileBaseName(moduleName) + ".h"_L1; } -AbstractMetaType - ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry *typeEntry) +QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName) { - QString typeName = typeEntry->qualifiedCppName(); - if (typeName.startsWith(QLatin1String("::"))) - typeName.remove(0, 2); - auto &cache = *metaTypeFromStringCache(); - auto it = cache.find(typeName); - if (it != cache.end()) - return it.value(); - AbstractMetaType metaType(typeEntry); - metaType.clearIndirections(); - metaType.setReferenceType(NoReference); - metaType.setConstant(false); - metaType.decideUsagePattern(); - cache.insert(typeName, metaType); - return metaType; + return getModuleHeaderFileBaseName(moduleName) + "_p.h"_L1; } -AbstractMetaType - ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass *metaClass) +IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const { - return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry()); + 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() @@ -2220,40 +2027,78 @@ 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; } -ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClass *scope) +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) +{ + for (qsizetype i = overloads->size() - 1; i >= 0; --i) { + 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).get())) { + overloads->removeAt(i); + break; + } + } + } + } +} + +ShibokenGenerator::FunctionGroups + ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope) { AbstractMetaFunctionCList lst = scope->functions(); scope->getFunctionsFromInvisibleNamespacesToBeGenerated(&lst); FunctionGroups results; for (const auto &func : lst) { - if (isGroupable(func)) { + if (isGroupable(func) + && func->ownerClass() == func->implementingClass() + && func->generateBinding()) { auto it = results.find(func->name()); if (it == results.end()) { - results.insert(func->name(), AbstractMetaFunctionCList(1, func)); + it = results.insert(func->name(), AbstractMetaFunctionCList(1, func)); } else { // If there are virtuals methods in the mix (PYSIDE-570, // QFileSystemModel::index(QString,int) and @@ -2265,387 +2110,540 @@ ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const else it.value().append(func); } + getInheritedOverloads(scope, &it.value()); + removeConstOverloads(&it.value()); } } return results; } -AbstractMetaFunctionCList - ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunctionCPtr &func, QSet<QString> *seen) -{ - AbstractMetaFunctionCList results; - AbstractMetaClass *basis; - if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) { - for (; basis; basis = basis->baseClass()) { - const auto inFunc = basis->findFunction(func->name()); - if (!inFunc.isNull() && !seen->contains(inFunc->minimalSignature())) { - seen->insert(inFunc->minimalSignature()); - AbstractMetaFunction *newFunc = inFunc->copy(); - newFunc->setImplementingClass(func->implementingClass()); - results << AbstractMetaFunctionCPtr(newFunc); - } - } - } - return results; +static bool removeNumberProtocolOperator(const AbstractMetaFunctionCPtr &f) +{ + return !f->generateBinding() + || (f->ownerClass() != f->implementingClass() && !f->isAbstract()); } -AbstractMetaFunctionCList - ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunctionCPtr &func, - QSet<QString> *seen) +QList<AbstractMetaFunctionCList> + ShibokenGenerator::getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass) { - AbstractMetaFunctionCList results; - seen->insert(func->minimalSignature()); - results << func << getInheritedOverloads(func, seen); - return results; + 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; } -AbstractMetaFunctionCList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass *scope, - const QString &functionName) const +BoolCastFunctionOptional +ShibokenGenerator::getBoolCast(const AbstractMetaClassCPtr &metaClass) { - const auto &lst = scope ? scope->functions() : api().globalFunctions(); + if (metaClass->isNamespace()) + return std::nullopt; - AbstractMetaFunctionCList results; - QSet<QString> seenSignatures; - for (const auto &func : qAsConst(lst)) { - if (func->name() != functionName) - continue; - if (isGroupable(func)) { - // PYSIDE-331: look also into base classes. - results << getFunctionAndInheritedOverloads(func, &seenSignatures); + 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}; } } - return results; + + 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; } -Generator::OptionDescriptions ShibokenGenerator::options() const +static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func) { - return { - {QLatin1String(AVOID_PROTECTED_HACK), - QLatin1String("Avoid the use of the '#define protected public' hack.")}, - {QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES), - QLatin1String("Disable verbose error messages. Turn the python code hard to debug\n" - "but safe few kB on the generated bindings.")}, - {QLatin1String(PARENT_CTOR_HEURISTIC), - QLatin1String("Enable heuristics to detect parent relationship on constructors.")}, - {QLatin1String(ENABLE_PYSIDE_EXTENSIONS), - QLatin1String("Enable PySide extensions, such as support for signal/slots,\n" - "use this if you are creating a binding for a Qt-based library.")}, - {QLatin1String(RETURN_VALUE_HEURISTIC), - QLatin1String("Enable heuristics to detect parent relationship on return values\n" - "(USE WITH CAUTION!)")}, - {QLatin1String(USE_ISNULL_AS_NB_NONZERO), - QLatin1String("If a class have an isNull() const method, it will be used to compute\n" - "the value of boolean casts")}, - {QLatin1String(WRAPPER_DIAGNOSTICS), - QLatin1String("Generate diagnostic code around wrappers")} - }; + return func->name() == u"operator+="; } -bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */) -{ - if (key == QLatin1String(PARENT_CTOR_HEURISTIC)) - return (m_useCtorHeuristic = true); - if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS)) - return (m_usePySideExtensions = true); - if (key == QLatin1String(RETURN_VALUE_HEURISTIC)) - return (m_userReturnValueHeuristic = true); - if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES)) - return (m_verboseErrorMessagesDisabled = true); - if (key == QLatin1String(USE_ISNULL_AS_NB_NONZERO)) - return (m_useIsNullAsNbNonZero = true); - if (key == QLatin1String(AVOID_PROTECTED_HACK)) - return (m_avoidProtectedHack = true); - if (key == QLatin1String(WRAPPER_DIAGNOSTICS)) - return (m_wrapperDiagnostics = true); - return false; +static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func) +{ + return func->functionType() == AbstractMetaFunction::IncrementOperator; } -static void getCode(QStringList &code, const CodeSnipList &codeSnips) +static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func) { - for (const CodeSnip &snip : qAsConst(codeSnips)) - code.append(snip.code()); + return func->functionType() == AbstractMetaFunction::DecrementOperator; } -static void getCode(QStringList &code, const TypeEntry *type) +// Filter predicate for operator functions +static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func) { - getCode(code, type->codeSnips()); + 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) +{ + auto attributes = f->cppAttributes(); + return !attributes.testFlag(FunctionAttribute::Override) + && !attributes.testFlag(FunctionAttribute::Final); +} - CustomConversion *customConversion = type->customConversion(); - if (!customConversion) +void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope, + AbstractMetaFunctionCList *overloads) +{ + if (overloads->isEmpty() || scope->isNamespace() || scope->baseClasses().isEmpty()) return; - if (!customConversion->nativeToTargetConversion().isEmpty()) - code.append(customConversion->nativeToTargetConversion()); + // PYSIDE-331: look also into base classes. Check for any non-overriding + // function hiding the base class functions. + const bool hideBaseClassFunctions = + std::any_of(overloads->cbegin(), overloads->cend(), hidesBaseClassFunctions); - const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions(); - if (toCppConversions.isEmpty()) - return; + const QString &functionName = overloads->constFirst()->name(); + const bool hasUsingDeclarations = scope->hasUsingMemberFor(functionName); + if (hideBaseClassFunctions && !hasUsingDeclarations) + return; // No base function is visible - for (CustomConversion::TargetToNativeConversion *toNative : qAsConst(toCppConversions)) - code.append(toNative->conversion()); + // Collect base candidates by name and signature + bool staticEncountered = false; + QSet<QString> seenSignatures; + for (const auto &func : *overloads) { + seenSignatures.insert(func->minimalSignature()); + staticEncountered |= func->isStatic(); + } + + AbstractMetaFunctionCList baseCandidates; + + 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(); + if (!seenSignatures.contains(signature)) { + seenSignatures.insert(signature); + baseCandidates.append(f); + } + } + } + return false; // Keep going + }; + + for (const auto &baseClass : scope->baseClasses()) + recurseClassHierarchy(baseClass, basePredicate); + + // Remove the ones that are not made visible with using declarations + if (hideBaseClassFunctions && hasUsingDeclarations) { + const auto pred = [scope](const AbstractMetaFunctionCPtr &f) { + return !scope->isUsingMember(f->ownerClass(), f->name(), f->access()); + }; + auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(), pred); + baseCandidates.erase(end, baseCandidates.end()); + } + + // PYSIDE-886: If the method does not have any static overloads declared + // in the class in question, remove all inherited static methods as setting + // METH_STATIC in that case can cause crashes for the instance methods. + // Manifested as crash when calling QPlainTextEdit::find() (clash with + // static QWidget::find(WId)). + if (!staticEncountered) { + auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(), + [](const AbstractMetaFunctionCPtr &f) { return f->isStatic(); }); + baseCandidates.erase(end, baseCandidates.end()); + } + + for (const auto &baseCandidate : baseCandidates) { + AbstractMetaFunction *newFunc = baseCandidate->copy(); + newFunc->setImplementingClass(scope); + overloads->append(AbstractMetaFunctionCPtr(newFunc)); + } } -bool ShibokenGenerator::doSetup() +QList<OptionDescription> ShibokenGenerator::options() +{ + 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}, + {PARENT_CTOR_HEURISTIC, + u"Enable heuristics to detect parent relationship on constructors."_s}, + {RETURN_VALUE_HEURISTIC, + u"Enable heuristics to detect parent relationship on return values\n" + "(USE WITH CAUTION!)"_s}, + {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}, + {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}, + {NO_IMPLICIT_CONVERSIONS, + u"Do not generate implicit_conversions for function arguments."_s}, + {WRAPPER_DIAGNOSTICS, + u"Generate diagnostic code around wrappers"_s} + }; +} + +class ShibokenGeneratorOptionsParser : public OptionsParser { - QStringList snips; - const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes(); - for (const PrimitiveTypeEntry *type : primitiveTypeList) - getCode(snips, type); - const ContainerTypeEntryList &containerTypeList = containerTypes(); - for (const ContainerTypeEntry *type : containerTypeList) - getCode(snips, type); - for (auto metaClass : api().classes()) - getCode(snips, metaClass->typeEntry()); +public: + explicit ShibokenGeneratorOptionsParser(ShibokenGeneratorOptions *o) : m_options(o) {} - const TypeSystemTypeEntry *moduleEntry = TypeDatabase::instance()->defaultTypeSystemType(); - Q_ASSERT(moduleEntry); - getCode(snips, moduleEntry); + bool handleBoolOption(const QString & key, OptionSource source) override; - const auto &functionGroups = getGlobalFunctionGroups(); - for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { - for (const auto &func : it.value()) - getCode(snips, func->injectedCodeSnips()); - } +private: + ShibokenGeneratorOptions *m_options; +}; - for (const QString &code : qAsConst(snips)) { - collectContainerTypesFromConverterMacros(code, true); - collectContainerTypesFromConverterMacros(code, false); +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 == 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; } -void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro) +bool ShibokenGenerator::useCtorHeuristic() { - QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP["); - int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP"); - int start = 0; - QString errorMessage; - while ((start = code.indexOf(convMacro, start)) != -1) { - int end = code.indexOf(QLatin1Char(']'), start); - start += offset; - if (code.at(start) != QLatin1Char('%')) { - QString typeString = code.mid(start, end - start); - auto type = buildAbstractMetaTypeFromString(typeString, &errorMessage); - if (type.has_value()) { - addInstantiatedContainersAndSmartPointers(type.value(), type->originalTypeDescription()); - } else { - qFatal("%s: Cannot translate type \"%s\": %s", __FUNCTION__, - qPrintable(typeString), qPrintable(errorMessage)); - } - } - start = end; - } + return m_options.useCtorHeuristic; } -bool ShibokenGenerator::useCtorHeuristic() const +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::usePySideExtensions() const +bool ShibokenGenerator::leanHeaders() { - return m_usePySideExtensions; + return m_options.leanHeaders; } -bool ShibokenGenerator::useIsNullAsNbNonZero() const +bool ShibokenGenerator::useOperatorBoolAsNbBool() { - return m_useIsNullAsNbNonZero; + return m_options.useOperatorBoolAsNbBool; } -bool ShibokenGenerator::avoidProtectedHack() const +bool ShibokenGenerator::generateImplicitConversions() { - return m_avoidProtectedHack; + return m_options.generateImplicitConversions; } QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName) { QString result = moduleName.isEmpty() ? packageName() : moduleName; - result.replace(QLatin1Char('.'), QLatin1Char('_')); + result.replace(u'.', u'_'); return result; } +QString ShibokenGenerator::cppApiVariableNameOld(const QString &moduleName) +{ + return "Sbk"_L1 + moduleCppPrefix(moduleName) + "Types"_L1; +} + QString ShibokenGenerator::cppApiVariableName(const QString &moduleName) { - return QLatin1String("Sbk") + moduleCppPrefix(moduleName) - + QLatin1String("Types"); + return "Sbk"_L1 + moduleCppPrefix(moduleName) + "TypeStructs"_L1; } QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName) { - return QLatin1String("Sbk") + moduleCppPrefix(moduleName) - + QLatin1String("ModuleObject"); + 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(QLatin1String("Converters")); + result.append(u"Converters"_s); return result; } static QString processInstantiationsVariableName(const AbstractMetaType &type) { - QString res = QLatin1Char('_') + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()).toUpper(); + QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()); for (const auto &instantiation : type.instantiations()) { res += instantiation.isContainer() ? processInstantiationsVariableName(instantiation) - : QLatin1Char('_') + _fixedCppTypeName(instantiation.cppSignature()).toUpper(); + : u'_' + _fixedCppTypeName(instantiation.cppSignature()); } return res; } static void appendIndexSuffix(QString *s) { - if (!s->endsWith(QLatin1Char('_'))) - s->append(QLatin1Char('_')); - s->append(QStringLiteral("IDX")); + if (!s->endsWith(u'_')) + s->append(u'_'); + s->append("IDX"_L1); } -QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass *metaClass, - bool alternativeTemplateName) +QString + ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass) +{ + const auto templateBaseClass = metaClass->templateBaseClass(); + Q_ASSERT(templateBaseClass); + QString result = u"SBK_"_s + + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()); + for (const auto &instantiation : metaClass->templateBaseClassInstantiations()) + result += processInstantiationsVariableName(instantiation); + appendIndexSuffix(&result); + return result; +} + +QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass) { - if (alternativeTemplateName) { - const AbstractMetaClass *templateBaseClass = metaClass->templateBaseClass(); - if (!templateBaseClass) - return QString(); - QString result = QLatin1String("SBK_") - + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); - for (const auto &instantiation : metaClass->templateBaseClassInstantiations()) - result += processInstantiationsVariableName(instantiation); - appendIndexSuffix(&result); - return result; - } return getTypeIndexVariableName(metaClass->typeEntry()); } -QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry *type) +QString ShibokenGenerator::getTypeIndexVariableName(TypeEntryCPtr type) { - if (type->isCppPrimitive()) { - const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type); - if (trueType->basicReferencedTypeEntry()) - type = trueType->basicReferencedTypeEntry(); - } - QString result = QLatin1String("SBK_"); + if (isCppPrimitive(type)) + type = basicReferencedTypeEntry(type); + QString result = u"SBK_"_s; // Disambiguate namespaces per module to allow for extending them. if (type->isNamespace()) { QString package = type->targetLangPackage(); - const int dot = package.lastIndexOf(QLatin1Char('.')); + 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; } QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType &type) { - QString result = QLatin1String("SBK"); + QString result = u"SBK"_s; if (type.typeEntry()->isContainer()) - result += QLatin1Char('_') + moduleName().toUpper(); + result += u'_' + moduleName(); result += processInstantiationsVariableName(type); appendIndexSuffix(&result); return result; } -bool ShibokenGenerator::verboseErrorMessagesDisabled() const +void collectfromTypeEntry(TypeEntryCPtr entry, QStringList &typeNames) { - return m_verboseErrorMessagesDisabled; + 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(); + } + } + } } -bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData &overloadData) +void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames) { - if (overloadData.referenceFunction()->isCallOperator()) - return true; - if (overloadData.referenceFunction()->isOperatorOverload()) - return false; - int maxArgs = overloadData.maxArgs(); - int minArgs = overloadData.minArgs(); - return (minArgs != maxArgs) - || (maxArgs > 1) - || overloadData.referenceFunction()->isConstructor() - || overloadData.hasArgumentWithDefaultValue(); + 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); } -void ShibokenGenerator::writeMinimalConstructorExpression(TextStream &s, - const ApiExtractorResult &api, - const AbstractMetaType &type, - const QString &defaultCtor) +bool ShibokenGenerator::verboseErrorMessagesDisabled() +{ + return m_options.verboseErrorMessagesDisabled; +} + +bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const +{ + const auto &groups = func->implementingClass() + ? getFunctionGroups(func->implementingClass()) + : getGlobalFunctionGroups(); + OverloadData od(groups.value(func->name()), api()); + return od.pythonFunctionWrapperUsesListOfArguments(); +} + +QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api, + const AbstractMetaType &type) { - if (!defaultCtor.isEmpty()) { - s << " = " << defaultCtor; - return; - } if (type.isExtendedCppPrimitive() || type.isSmartPointer()) - return; + return {}; QString errorMessage; const auto ctor = minimalConstructor(api, type, &errorMessage); - if (ctor.has_value()) { - s << ctor->initialization(); - } else { - const QString message = - msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), - type.cppSignature(), errorMessage); - qCWarning(lcShiboken()).noquote() << message; - s << ";\n#error " << message << '\n'; - } + if (ctor.has_value()) + return ctor->initialization(); + + const QString message = + msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__), + type.cppSignature(), errorMessage); + qCWarning(lcShiboken()).noquote() << message; + return u";\n#error "_s + message + u'\n'; } -void ShibokenGenerator::writeMinimalConstructorExpression(TextStream &s, - const ApiExtractorResult &api, - const TypeEntry *type, - const QString &defaultCtor) +QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api, + const TypeEntryCPtr &type) { - if (!defaultCtor.isEmpty()) { - s << " = " << defaultCtor; - return; - } - if (type->isExtendedCppPrimitive()) - return; + if (isExtendedCppPrimitive(type)) + return {}; const auto ctor = minimalConstructor(api, type); - if (ctor.has_value()) { - s << ctor->initialization(); - } else { - const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName()); - qCWarning(lcShiboken()).noquote() << message; - s << ";\n#error " << message << '\n'; - } + if (ctor.has_value()) + return ctor->initialization(); + + const QString message = + msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__), + type->qualifiedCppName()); + qCWarning(lcShiboken()).noquote() << message; + return u";\n#error "_s + message + u'\n'; } QString ShibokenGenerator::pythonArgsAt(int i) { - return QLatin1String(PYTHON_ARGS) + QLatin1Char('[') - + QString::number(i) + QLatin1Char(']'); + return PYTHON_ARGS + u'[' + QString::number(i) + u']'; } 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(QLatin1String("%TYPE"), cpp_class->name()); + code.replace(u"%TYPE"_s, cpp_class->name()); const AbstractMetaArgumentList &argument = func->arguments(); for (const AbstractMetaArgument &arg : argument) - code.replace(QLatin1Char('%') + QString::number(arg.argumentIndex() + 1), arg.name()); + code.replace(u'%' + QString::number(arg.argumentIndex() + 1), arg.name()); //template values - code.replace(QLatin1String("%RETURN_TYPE"), translateType(func->type(), cpp_class)); - code.replace(QLatin1String("%FUNCTION_NAME"), func->originalName()); + code.replace(u"%RETURN_TYPE"_s, translateType(func->type(), cpp_class)); + code.replace(u"%FUNCTION_NAME"_s, func->originalName()); - if (code.contains(QLatin1String("%ARGUMENT_NAMES"))) { + if (code.contains(u"%ARGUMENT_NAMES")) { StringStream aux_stream; writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments); - code.replace(QLatin1String("%ARGUMENT_NAMES"), aux_stream); + code.replace(u"%ARGUMENT_NAMES"_s, aux_stream); } - if (code.contains(QLatin1String("%ARGUMENTS"))) { + if (code.contains(u"%ARGUMENTS")) { StringStream aux_stream; writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments); - code.replace(QLatin1String("%ARGUMENTS"), aux_stream); + code.replace(u"%ARGUMENTS"_s, aux_stream); } } + +QString ShibokenGenerator::stdMove(const QString &c) +{ + return u"std::move("_s + c + u')'; +} |