diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-27 13:45:29 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-10-05 14:27:18 +0200 |
commit | e1a2fd9524578f4f4e27eb92a8646f7d53a4c1b8 (patch) | |
tree | 98a5f46204d4b555a6cb16a6374fecc7bbe94c5a /sources | |
parent | a097b2b1dbf8901ab26a80c9619f679c689677a8 (diff) |
shiboken6: Fix indirections of enums/flag arguments
The information about how arguments are converted (pointer
indirections, etc.) was in
CppGenerator::writePythonToCppTypeConversion() and partially
duplicated in AbstractMetaType::shouldDereferenceArgument(), leading
to discrepancies in the indirections generated for the function calls.
To fix this, introduce a struct GeneratorArgument with type,
conversion mode, indirections and a few flags storing this information
and use that everywhere, replacing
AbstractMetaType::shouldDereferenceArgument().
Pass the argument indirections obtained from
writePythonToCppTypeConversion() via writeArgumentConversion() as a
list into writeMethodCall().
Add a test for passing enums by pointer.
Fixes: PYSIDE-2065
Change-Id: I495c2bc04ebc0162648d74b75e321609ecd00963
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources')
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetatype.cpp | 19 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetatype.h | 4 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/messages.cpp | 6 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/messages.h | 2 | ||||
-rw-r--r-- | sources/shiboken6/generator/CMakeLists.txt | 3 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/cppgenerator.cpp | 124 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/cppgenerator.h | 15 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/generatorargument.cpp | 110 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/generatorargument.h | 60 | ||||
-rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 8 | ||||
-rw-r--r-- | sources/shiboken6/tests/libsample/objecttype.h | 1 | ||||
-rw-r--r-- | sources/shiboken6/tests/samplebinding/enum_test.py | 2 |
12 files changed, 254 insertions, 100 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp index 6b0732bbf..a7ee6aa31 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp @@ -852,25 +852,6 @@ bool AbstractMetaType::isWrapperPassedByReference() const && !isPointer(); } -qsizetype AbstractMetaType::shouldDereferenceArgument() const -{ - if (isWrapperPassedByReference() || valueTypeWithCopyConstructorOnlyPassed() - || isObjectTypeUsedAsValueType()) { - return 1; - } - - if (!d->m_typeEntry->isContainer()) - return 0; - - qsizetype result = -d->m_indirections.size(); - - // For opaque containers, the cppArg in the generated code is a pointer - if (generateOpaqueContainer()) - ++result; - - return result; -} - bool AbstractMetaType::isCppIntegralPrimitive() const { return d->m_typeEntry->isCppIntegralPrimitive(); diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.h b/sources/shiboken6/ApiExtractor/abstractmetatype.h index 8510da687..1d1845a34 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetatype.h +++ b/sources/shiboken6/ApiExtractor/abstractmetatype.h @@ -215,10 +215,6 @@ public: bool isPointerToWrapperType() const; /// Wrapper type passed by reference bool isWrapperPassedByReference() const; - /// Checks if the meta type of an argument should be dereferenced by the Python - /// method wrapper passing it to C++. - /// \return positive numbers for dereferencing, negative for referencing - qsizetype shouldDereferenceArgument() const; /// Returns true if the type is a C++ integral primitive, /// i.e. bool, char, int, long, and their unsigned counterparts. bool isCppIntegralPrimitive() const; diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index 29fb23edb..4e9f5ad9a 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -939,3 +939,9 @@ QString msgMissingCustomConversion(const TypeEntry *t) << "\" is missing a custom conversion."; return result; } + +QString msgUnknownArrayPointerConversion(const QString &s) +{ + return u"Warning: Falling back to pointer conversion for unknown array type \""_s + + s + u"\""_s; +} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index 0c09f4bc1..1d40dc76c 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -247,4 +247,6 @@ QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func, QString msgMissingCustomConversion(const TypeEntry *t); +QString msgUnknownArrayPointerConversion(const QString &s); + #endif // MESSAGES_H diff --git a/sources/shiboken6/generator/CMakeLists.txt b/sources/shiboken6/generator/CMakeLists.txt index d0c5cdeb3..bac998ae5 100644 --- a/sources/shiboken6/generator/CMakeLists.txt +++ b/sources/shiboken6/generator/CMakeLists.txt @@ -1,6 +1,8 @@ project(shibokengenerator) set(package_name "Shiboken6Tools") +set(CMAKE_AUTOMOC ON) + if(NOT (Qt${QT_MAJOR_VERSION}Core_FOUND AND PYTHONINTERP_FOUND)) message(WARNING "Some dependencies were not found: shiboken6 generator compilation disabled!") return() @@ -12,6 +14,7 @@ generatorcontext.cpp defaultvalue.cpp shiboken/cppgenerator.cpp shiboken/cppgenerator_container.cpp +shiboken/generatorargument.cpp shiboken/headergenerator.cpp shiboken/overloaddata.cpp shiboken/shibokengenerator.cpp diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index c7158c124..eeafbd60b 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "cppgenerator.h" +#include "generatorargument.h" #include "defaultvalue.h" #include "generatorcontext.h" #include "codesnip.h" @@ -2824,21 +2825,24 @@ void CppGenerator::writeTypeCheck(TextStream &s, writeTypeCheck(s, argType, argumentName, numberType, rejectNull); } -void CppGenerator::writeArgumentConversion(TextStream &s, - const AbstractMetaType &argType, - const QString &argName, const QString &pyArgName, - ErrorReturn errorReturn, - const AbstractMetaClass *context, - const QString &defaultValue, - bool castArgumentAsUnused) const +qsizetype CppGenerator::writeArgumentConversion(TextStream &s, + const AbstractMetaType &argType, + const QString &argName, + const QString &pyArgName, + ErrorReturn errorReturn, + const AbstractMetaClass *context, + const QString &defaultValue, + bool castArgumentAsUnused) const { + qsizetype result = 0; if (argType.typeEntry()->isCustom() || argType.typeEntry()->isVarargs()) - return; + return result; if (argType.isWrapperType()) writeInvalidPyObjectCheck(s, pyArgName, errorReturn); - writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue); + result = writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue); if (castArgumentAsUnused) s << sbkUnusedVariableCast(argName); + return result; } AbstractMetaType @@ -2909,44 +2913,17 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, if (typeEntry->isCustom() || typeEntry->isVarargs()) return 0; - qsizetype indirections = -type.indirectionsV().size(); + const auto arg = GeneratorArgument::fromMetaType(type); + const bool isPrimitive = arg.type == GeneratorArgument::Type::Primitive; QString cppOutAux = cppOut + u"_local"_s; - const bool isPrimitive = typeEntry->isPrimitive(); - const bool isEnum = typeEntry->isEnum(); - const bool isFlags = typeEntry->isFlags(); - const bool treatAsPointer = type.valueTypeWithCopyConstructorOnlyPassed(); - const bool isContainer = typeEntry->isContainer(); - bool isPointerOrObjectType = (type.isObjectType() || type.isPointer()) - && !type.isUserPrimitive() && !type.isExtendedCppPrimitive() - && !isEnum && !isFlags; - const bool isNotContainerEnumOrFlags = !isContainer - && !isEnum && !isFlags; - const bool mayHaveImplicitConversion = type.referenceType() == LValueReference - && !type.isUserPrimitive() - && !type.isExtendedCppPrimitive() - && isNotContainerEnumOrFlags - && !(treatAsPointer || isPointerOrObjectType); - - // For implicit conversions or containers, either value or pointer conversion - // may occur. An implicit conversion uses value conversion whereas the object - // itself uses pointer conversion. For containers, the PyList/container - // conversion is by value whereas opaque containers use pointer conversion. - // For a container passed by pointer, a local variable is also needed. - const bool valueOrPointer = mayHaveImplicitConversion - || type.generateOpaqueContainer() - || (isContainer && indirections != 0); - - const AbstractMetaTypeList &nestedArrayTypes = type.nestedArrayTypes(); - const bool isCppPrimitiveArray = !nestedArrayTypes.isEmpty() - && nestedArrayTypes.constLast().isCppPrimitive(); - QString typeName = isCppPrimitiveArray - ? arrayHandleType(nestedArrayTypes) - : getFullTypeNameWithoutModifiers(type); + QString typeName = arg.type == GeneratorArgument::Type::CppPrimitiveArray + ? arrayHandleType(type.nestedArrayTypes()) + : getFullTypeNameWithoutModifiers(type); bool isProtectedEnum = false; - if (isEnum && avoidProtectedHack()) { + if (arg.type == GeneratorArgument::Type::Enum && avoidProtectedHack()) { auto metaEnum = api().findAbstractMetaEnum(type.typeEntry()); if (metaEnum.has_value() && metaEnum->isProtected()) { typeName = wrapperName(context) + u"::"_s @@ -2956,19 +2933,21 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, } s << typeName; - if (isCppPrimitiveArray) { + switch (arg.conversion) { + case GeneratorArgument::Conversion::CppPrimitiveArray: s << ' ' << cppOut; - } else if (valueOrPointer) { - ++indirections; + break; + case GeneratorArgument::Conversion::ValueOrPointer: { // Generate either value conversion for &cppOutAux or pointer // conversion for &cppOut s << ' ' << cppOutAux; // No default value for containers which can also be passed by pointer. - if (!isContainer) + if (arg.type != GeneratorArgument::Type::Container) writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue); s << ";\n" << typeName << " *" << cppOut << " = &" << cppOutAux; - } else if (treatAsPointer || isPointerOrObjectType) { - ++indirections; + } + break; + case GeneratorArgument::Conversion::Pointer: { s << " *" << cppOut; if (!defaultValue.isEmpty()) { const bool needsConstCast = !isNullPtr(defaultValue) @@ -2981,7 +2960,9 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, if (needsConstCast) s << ')'; } - } else { + } + break; + case GeneratorArgument::Conversion::Default: s << ' ' << cppOut; if (isProtectedEnum && avoidProtectedHack()) { s << " = "; @@ -2989,11 +2970,14 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, s << "{}"; else s << defaultValue; - } else if (type.isUserPrimitive() || isEnum || isFlags) { + } else if (type.isUserPrimitive() + || arg.type == GeneratorArgument::Type::Enum + || arg.type == GeneratorArgument::Type::Flags) { writeMinimalConstructorExpression(s, api(), typeEntry, isPrimitive, defaultValue); } else if (!type.isContainer() && !type.isSmartPointer()) { writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue); } + break; } s << ";\n"; @@ -3001,7 +2985,7 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, QString pythonToCppCall = pythonToCppFunc + u'(' + pyIn + u", &"_s + cppOut + u')'; - if (!valueOrPointer) { + if (arg.conversion != GeneratorArgument::Conversion::ValueOrPointer) { // pythonToCppFunc may be 0 when less parameters are passed and // the defaultValue takes effect. if (!defaultValue.isEmpty()) @@ -3009,7 +2993,7 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, s << pythonToCppCall << ";\n"; if (!defaultValue.isEmpty()) s << outdent; - return indirections; + return arg.indirections; } // pythonToCppFunc may be 0 when less parameters are passed and @@ -3027,7 +3011,7 @@ qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s, else s << "}\n" << outdent; - return indirections; + return arg.indirections; } static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rule, @@ -3330,7 +3314,10 @@ void CppGenerator::writeSingleFunctionCall(TextStream &s, bool injectCodeCallsFunc = injectedCodeCallsCppFunction(context, func); bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc; int removedArgs = 0; - for (qsizetype argIdx = 0; argIdx < func->arguments().size(); ++argIdx) { + + const auto argCount = func->arguments().size(); + QList<qsizetype> indirections(argCount, 0); + for (qsizetype argIdx = 0; argIdx < argCount; ++argIdx) { const bool hasConversionRule = func->hasConversionRule(TypeSystem::NativeCode, int(argIdx + 1)); const AbstractMetaArgument &arg = func->arguments().at(argIdx); @@ -3361,9 +3348,10 @@ void CppGenerator::writeSingleFunctionCall(TextStream &s, int argPos = argIdx - removedArgs; QString argName = CPP_ARG + QString::number(argPos); QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : PYTHON_ARG; - writeArgumentConversion(s, argType, argName, pyArgName, errorReturn, - func->implementingClass(), arg.defaultValueExpression(), - func->isUserAdded()); + indirections[argIdx] = + writeArgumentConversion(s, argType, argName, pyArgName, errorReturn, + func->implementingClass(), arg.defaultValueExpression(), + func->isUserAdded()); } s << '\n'; @@ -3373,7 +3361,7 @@ void CppGenerator::writeSingleFunctionCall(TextStream &s, s << "if (!PyErr_Occurred()) {\n" << indent; writeMethodCall(s, func, context, overloadData.pythonFunctionWrapperUsesListOfArguments(), - func->arguments().size() - numRemovedArgs, errorReturn); + func->arguments().size() - numRemovedArgs, indirections, errorReturn); if (!func->isConstructor()) writeNoneReturn(s, func, overloadData.hasNonVoidReturnType()); @@ -3626,7 +3614,8 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const Abst const AbstractMetaType &type = containerType.instantiations().at(i); QString typeName = getFullTypeName(type); // Containers of opaque containers are not handled here. - if (type.shouldDereferenceArgument() > 0 && !type.generateOpaqueContainer()) { + const auto generatorArg = GeneratorArgument::fromMetaType(type); + if (generatorArg.indirections > 0 && !type.generateOpaqueContainer()) { for (int pos = 0; ; ) { const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos); if (!match.hasMatch()) @@ -3836,7 +3825,9 @@ if (errorType != nullptr) void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func, const GeneratorContext &context, bool usesPyArgs, - int maxArgs, ErrorReturn errorReturn) const + int maxArgs, + const QList<qsizetype> &argumentIndirections, + ErrorReturn errorReturn) const { s << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << '\n'; if (func->isConstructor()) { @@ -3911,7 +3902,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr userArgs.append(arg.name() + CONV_RULE_OUT_VAR_SUFFIX); } else { const int idx = arg.argumentIndex() - removedArgs; - const auto deRef = arg.type().shouldDereferenceArgument(); + const auto deRef = argumentIndirections.at(i); QString argName = AbstractMetaType::dereferencePrefix(deRef) + CPP_ARG + QString::number(idx); userArgs.append(argName); @@ -3959,10 +3950,8 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr firstArg += CPP_SELF_VAR; firstArg += u')'; QString secondArg = CPP_ARG0; - if (!func->isUnaryOperator()) { - auto deRef = func->arguments().constFirst().type().shouldDereferenceArgument(); - AbstractMetaType::applyDereference(&secondArg, deRef); - } + if (!func->isUnaryOperator()) + AbstractMetaType::applyDereference(&secondArg, argumentIndirections.at(0)); if (func->isUnaryOperator()) std::swap(firstArg, secondArg); @@ -5261,8 +5250,9 @@ void CppGenerator::writeRichCompareFunction(TextStream &s, s << '&'; s << CPP_SELF_VAR << ' ' << AbstractMetaFunction::cppComparisonOperator(op) << " ("; - if (auto deRef = argType.shouldDereferenceArgument(); deRef > 0) - s << QByteArray(deRef, '*'); + auto generatorArg = GeneratorArgument::fromMetaType(argType); + if (generatorArg.indirections != 0) + s << QByteArray(generatorArg.indirections, '*'); s << CPP_ARG0 << ");\n" << PYTHON_RETURN_VAR << " = "; if (!func->isVoid()) { diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 914a73ec3..b101d2ef3 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -209,12 +209,12 @@ private: * \param defaultValue an optional default value to be used instead of the conversion result * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings */ - void writeArgumentConversion(TextStream &s, const AbstractMetaType &argType, - const QString &argName, const QString &pyArgName, - ErrorReturn errorReturn, - const AbstractMetaClass *context = nullptr, - const QString &defaultValue = QString(), - bool castArgumentAsUnused = false) const; + qsizetype writeArgumentConversion(TextStream &s, const AbstractMetaType &argType, + const QString &argName, const QString &pyArgName, + ErrorReturn errorReturn, + const AbstractMetaClass *context = nullptr, + const QString &defaultValue = QString(), + bool castArgumentAsUnused = false) const; /** * Returns the AbstractMetaType for a function argument. @@ -352,7 +352,8 @@ private: void writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func, const GeneratorContext &context, bool usesPyArgs, - int maxArgs, ErrorReturn errorReturn) const; + int maxArgs, const QList<qsizetype> &argumentIndirections, + ErrorReturn errorReturn) const; static QString getInitFunctionName(const GeneratorContext &context) ; static QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) ; diff --git a/sources/shiboken6/generator/shiboken/generatorargument.cpp b/sources/shiboken6/generator/shiboken/generatorargument.cpp new file mode 100644 index 000000000..5c8f12458 --- /dev/null +++ b/sources/shiboken6/generator/shiboken/generatorargument.cpp @@ -0,0 +1,110 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "generatorargument.h" +#include <abstractmetatype.h> +#include <messages.h> +#include <typesystem.h> + +#include <QtCore/QDebug> +#include <QtCore/QSet> + +static bool isCppPrimitiveString(const AbstractMetaType &type) +{ + return type.referenceType() == NoReference && type.indirections() == 1 + && AbstractMetaType::cppSignedCharTypes().contains(type.name()); +} + +GeneratorArgument GeneratorArgument::fromMetaType(const AbstractMetaType &type) +{ + GeneratorArgument result; + + const TypeEntry *typeEntry = type.typeEntry(); + if (typeEntry->isCustom() || typeEntry->isVarargs()) + return result; + + result.indirections = -type.indirectionsV().size(); + if (isCppPrimitiveString(type) + || type.isVoidPointer() + || type.typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern) { + result.indirections += 1; + } + + if (typeEntry->isEnum()) { + result.type = Type::Enum; + } else if (typeEntry->isFlags()) { + result.type = Type::Flags; + } else if (typeEntry->isContainer()) { + result.type = Type::Container; + } else { + if (typeEntry->isPrimitive()) + result.type = Type::Primitive; + + const AbstractMetaTypeList &nestedArrayTypes = type.nestedArrayTypes(); + if (!nestedArrayTypes.isEmpty()) { + if (nestedArrayTypes.constLast().isCppPrimitive()) { + result.type = Type::CppPrimitiveArray; + } else { + static QSet<QString> warnedTypes; + const QString &signature = type.cppSignature(); + if (!warnedTypes.contains(signature)) { + warnedTypes.insert(signature); + qWarning("%s", qPrintable(msgUnknownArrayPointerConversion(signature))); + } + result.indirections -= 1; + } + } + } + + if (result.type == Type::Other || result.type == Type::Primitive) { + if (type.valueTypeWithCopyConstructorOnlyPassed()) { + result.flags.setFlag(Flag::TreatAsPointer); + } else if ((type.isObjectType() || type.isPointer()) + && !type.isUserPrimitive() && !type.isExtendedCppPrimitive()) { + result.flags.setFlag(Flag::PointerOrObjectType); + } else if (type.referenceType() == LValueReference + && !type.isUserPrimitive() + && !type.isExtendedCppPrimitive()) { + result.flags.setFlag(Flag::MayHaveImplicitConversion); + } + } + + // For implicit conversions or containers, either value or pointer conversion + // may occur. An implicit conversion uses value conversion whereas the object + // itself uses pointer conversion. For containers, the PyList/container + // conversion is by value whereas opaque containers use pointer conversion. + // For a container passed by pointer, a local variable is also needed. + if (result.flags.testFlag(Flag::MayHaveImplicitConversion) + || type.generateOpaqueContainer() + || (result.type == Type::Container && result.indirections != 0)) { + result.flags.setFlag(Flag::ValueOrPointer); + } + + if (result.type == Type::CppPrimitiveArray) { + result.conversion = Conversion::CppPrimitiveArray; + } else if (result.flags.testFlag(Flag::ValueOrPointer)) { + result.conversion = Conversion::ValueOrPointer; + ++result.indirections; + } else if (result.flags.testAnyFlags(Flag::TreatAsPointer | Flag::PointerOrObjectType)) { + result.conversion = Conversion::Pointer; + ++result.indirections; + } + + return result; +} + +QDebug operator<<(QDebug debug, const GeneratorArgument &a) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "GeneratorArgument(" << a.type; + if (a.conversion != GeneratorArgument::Conversion::Default) + debug << ", conversion=" << a.conversion; + if (a.flags) + debug << ", flags(" << a.flags; + if (a.indirections != 0) + debug << ", indirections=" << a.indirections; + debug << ')'; + return debug; +} diff --git a/sources/shiboken6/generator/shiboken/generatorargument.h b/sources/shiboken6/generator/shiboken/generatorargument.h new file mode 100644 index 000000000..385ad0f63 --- /dev/null +++ b/sources/shiboken6/generator/shiboken/generatorargument.h @@ -0,0 +1,60 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef GENERATORARGUMENT_H +#define GENERATORARGUMENT_H + +#include <QtCore/QFlags> +#include <QtCore/qobjectdefs.h> + +QT_FORWARD_DECLARE_CLASS(QDebug) + +class AbstractMetaType; + +/// A struct containing information on how the generator processes a function argument. +struct GeneratorArgument +{ + Q_GADGET + +public: + enum class Type { + Other, + Primitive, + Enum, + Flags, + Container, + CppPrimitiveArray + }; + Q_ENUM(Type) + + enum class Conversion { + Default, + CppPrimitiveArray, // Similar to Default except default values + Pointer, + ValueOrPointer + }; + Q_ENUM(Conversion) + + enum class Flag { + TreatAsPointer = 0x1, + PointerOrObjectType = 0x2, + MayHaveImplicitConversion = 0x4, + ValueOrPointer = 0x8, + }; + Q_ENUM(Flag) + Q_DECLARE_FLAGS(Flags, Flag) + + static GeneratorArgument fromMetaType(const AbstractMetaType &type); + + Flags flags; + /// Indirections from generated "cppArg<n>" variable to function argument. + qsizetype indirections = 0; + Type type = Type::Other; + Conversion conversion = Conversion::Default; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(GeneratorArgument::Flags) + +QDebug operator<<(QDebug debug, const GeneratorArgument &a); + +#endif // GENERATORARGUMENT_H diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 1b9299a4f..438437c24 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "shibokengenerator.h" +#include "generatorargument.h" #include "defaultvalue.h" #include "generatorcontext.h" #include "apiextractorresult.h" @@ -1285,8 +1286,8 @@ ShibokenGenerator::ArgumentVarReplacementList argValue = hasConversionRule ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX : CPP_ARG + QString::number(argPos); - auto deRef = type.shouldDereferenceArgument(); - AbstractMetaType::applyDereference(&argValue, deRef); + const auto generatorArg = GeneratorArgument::fromMetaType(type); + AbstractMetaType::applyDereference(&argValue, generatorArg.indirections); } } } else { @@ -1505,7 +1506,8 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s, AbstractMetaType type = arg.modifiedType(); if (type.isWrapperType()) { QString replacement = pair.second; - if (type.shouldDereferenceArgument() > 0) + const auto generatorArg = GeneratorArgument::fromMetaType(type); + if (generatorArg.indirections > 0) AbstractMetaType::stripDereference(&replacement); if (type.referenceType() == LValueReference || type.isPointer()) code.replace(u'%' + QString::number(idx) + u'.', replacement + u"->"_s); diff --git a/sources/shiboken6/tests/libsample/objecttype.h b/sources/shiboken6/tests/libsample/objecttype.h index 0f732a60a..221fb7eea 100644 --- a/sources/shiboken6/tests/libsample/objecttype.h +++ b/sources/shiboken6/tests/libsample/objecttype.h @@ -31,6 +31,7 @@ struct Event void setEventType(EventType et) { m_eventType = et; } void setEventTypeByConstRef(const EventType &et) { m_eventType = et; } + void setEventTypeByConstPtr(const EventType *etPtr) { m_eventType = *etPtr; } private: EventType m_eventType; diff --git a/sources/shiboken6/tests/samplebinding/enum_test.py b/sources/shiboken6/tests/samplebinding/enum_test.py index 8275b0edf..90f36a186 100644 --- a/sources/shiboken6/tests/samplebinding/enum_test.py +++ b/sources/shiboken6/tests/samplebinding/enum_test.py @@ -104,6 +104,8 @@ class EnumTest(unittest.TestCase): self.assertEqual(event.eventType(), Event.BASIC_EVENT) event.setEventTypeByConstRef(Event.SOME_EVENT) self.assertEqual(event.eventType(), Event.SOME_EVENT) + event.setEventTypeByConstPtr(Event.BASIC_EVENT) + self.assertEqual(event.eventType(), Event.BASIC_EVENT) @unittest.skipIf(sys.pyside63_option_python_enum, "test not suitable for Python enum") def testEnumTpPrintImplementation(self): |