aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2022-09-27 13:45:29 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2022-10-05 14:27:18 +0200
commite1a2fd9524578f4f4e27eb92a8646f7d53a4c1b8 (patch)
tree98a5f46204d4b555a6cb16a6374fecc7bbe94c5a /sources
parenta097b2b1dbf8901ab26a80c9619f679c689677a8 (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.cpp19
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetatype.h4
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp6
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h2
-rw-r--r--sources/shiboken6/generator/CMakeLists.txt3
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp124
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h15
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.cpp110
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.h60
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp8
-rw-r--r--sources/shiboken6/tests/libsample/objecttype.h1
-rw-r--r--sources/shiboken6/tests/samplebinding/enum_test.py2
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):