aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml10
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.cpp31
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.h19
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp8
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h3
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.cpp11
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.h12
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser.cpp32
-rw-r--r--sources/shiboken6/ApiExtractor/typesystemparser_p.h2
-rw-r--r--sources/shiboken6/doc/typesystem.rst1
-rw-r--r--sources/shiboken6/doc/typesystem_overloads.rst38
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst2
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp110
13 files changed, 261 insertions, 18 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index 0e5d8a1a1..ed981f8f7 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -21,6 +21,16 @@
<include file-name="qtcorehelper.h" location="local"/>
</extra-includes>
+ <overload-removal type="QString" replaces="QStringView"/>
+ <overload-removal type="double" replaces="float"/>
+ <overload-removal type="unsigned int" replaces="unsigned short"/> <!-- Order is important here -->
+ <overload-removal type="unsigned long" replaces="unsigned short"/>
+ <overload-removal type="unsigned" replaces="unsigned short"/>
+ <overload-removal type="unsigned long long" replaces="unsigned;unsigned int;unsigned long"/>
+ <overload-removal type="int" replaces="short;std::chrono::milliseconds"/>
+ <overload-removal type="long" replaces="short"/>
+ <overload-removal type="long long" replaces="long;int"/>
+
<function signature="qFastCos(qreal)" since="4.6"/>
<function signature="qFastSin(qreal)" since="4.6"/>
<function signature="qFuzzyCompare(double,double)"/>
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
index f3bfdeacb..d127a544e 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
@@ -340,12 +340,6 @@ void AbstractMetaFunction::setOwnerClass(const AbstractMetaClassCPtr &cls)
d->m_class = cls;
}
-static bool equalArgument(const AbstractMetaArgument &a1,
- const AbstractMetaArgument &a2)
-{
- return a1.type() == a2.type();
-}
-
/*!
Returns a mask of CompareResult describing how this function is
compares to another function
@@ -362,17 +356,34 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra
if (originalName() == other->originalName())
result.setFlag(EqualName);
+ if (isStatic() == other->isStatic())
+ result.setFlag(EqualStatic);
+
+ if (isConstant() == other->isConstant())
+ result.setFlag(EqualConst);
+
+ if (isVirtual() == other->isVirtual())
+ result.setFlag(EqualVirtual);
+
// compare name after modification...
if (modifiedName() == other->modifiedName())
result.setFlag(EqualModifiedName);
// Compare arguments...
- if (d->m_arguments.size() == other->arguments().size()) {
+ const auto argumentCount = d->m_arguments.size();
+ const auto &otherArguments = other->arguments();
+ if (argumentCount == otherArguments.size()) {
result.setFlag(EqualArgumentCount);
- if (std::equal(d->m_arguments.cbegin(), d->m_arguments.cend(),
- other->arguments().cbegin(), equalArgument)) {
- result.setFlag(EqualArguments);
+ bool equals = true;
+ for (qsizetype a = 0; a < argumentCount; ++a) {
+ if ((d->m_arguments.at(a).type() != otherArguments.at(a).type())) {
+ equals = false;
+ if (a < 4)
+ result.setFlag(CompareResultFlag(DifferArgument1 << a));
+ }
}
+ if (equals)
+ result.setFlag(EqualArguments);
}
return result;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.h b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
index 734fa0bb3..240bde335 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetafunction.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.h
@@ -73,11 +73,20 @@ public:
Q_ENUM(ComparisonOperatorType)
enum CompareResultFlag {
- EqualName = 0x00000001,
- EqualArgumentCount = 0x00000002,
- EqualArguments = 0x00000004,
- EqualReturnType = 0x00000010,
- EqualModifiedName = 0x00000040,
+ EqualName = 0x0001,
+ EqualModifiedName = 0x0002,
+ EqualVirtual = 0x0004,
+ EqualStatic = 0x0008,
+ EqualConst = 0x0010,
+ EqualReturnType = 0x0020,
+ EqualArgumentCount = 0x0040,
+ EqualArguments = 0x0080,
+ DifferArgument1 = 0x0100, // Argument 1 is different
+ DifferArgument2 = 0x0200,
+ DifferArgument3 = 0x0400,
+ DifferArgument4 = 0x0800,
+ Differ4ArgumentsMask = 0x0f00,
+ EqualAll = 0xffff
};
Q_DECLARE_FLAGS(CompareResult, CompareResultFlag)
Q_FLAG(CompareResultFlag)
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp
index 87dc4bd47..29cf6d091 100644
--- a/sources/shiboken6/ApiExtractor/messages.cpp
+++ b/sources/shiboken6/ApiExtractor/messages.cpp
@@ -1061,3 +1061,11 @@ QString msgCannotCall(const AbstractMetaFunctionCPtr &func,
str << " There is no conversion rule.";
return result;
}
+
+QString msgRemoveRedundantOverload(const AbstractMetaFunctionCPtr &func,
+ const QString &type)
+{
+ return "Removing \""_L1 + func->classQualifiedSignature()
+ + "\" due to presence of an overload taking a \""_L1
+ + type + "\" parameter."_L1;
+}
diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h
index d483a8c7d..5519c65b6 100644
--- a/sources/shiboken6/ApiExtractor/messages.h
+++ b/sources/shiboken6/ApiExtractor/messages.h
@@ -278,4 +278,7 @@ QString msgCannotFindQDocFile(const AbstractMetaClassCPtr &metaClass,
QString msgCannotCall(const AbstractMetaFunctionCPtr &func,
int arg, bool injectCodeCallsFunc, bool hasConversionRule);
+QString msgRemoveRedundantOverload(const AbstractMetaFunctionCPtr &func,
+ const QString &type);
+
#endif // MESSAGES_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp
index 91f5966c6..3abdfeb8c 100644
--- a/sources/shiboken6/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp
@@ -274,6 +274,7 @@ struct TypeDatabasePrivate : public TypeDatabaseOptions
AddedFunctionList m_globalUserFunctions;
FunctionModificationList m_functionMods;
+ OverloadRemovalRules m_overloadRemovalRules;
QStringList m_requiredTargetImports;
@@ -902,6 +903,16 @@ FunctionModificationList
return lst;
}
+const OverloadRemovalRules &TypeDatabase::overloadRemovalRules() const
+{
+ return d->m_overloadRemovalRules;
+}
+
+void TypeDatabase::addOverloadRemovalRule(const OverloadRemovalRule &r)
+{
+ d->m_overloadRemovalRules.append(r);
+}
+
bool TypeDatabase::addSuppressedWarning(const QString &warning, bool generate,
QString *errorMessage)
{
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.h b/sources/shiboken6/ApiExtractor/typedatabase.h
index 656a16ef5..726338b08 100644
--- a/sources/shiboken6/ApiExtractor/typedatabase.h
+++ b/sources/shiboken6/ApiExtractor/typedatabase.h
@@ -60,6 +60,15 @@ struct TypeRejection
QDebug operator<<(QDebug d, const TypeRejection &r);
#endif
+// Rule for removing overloads that differ in one type
+struct OverloadRemovalRule
+{
+ QString type;
+ QStringList redundantTypes;
+};
+
+using OverloadRemovalRules = QList<OverloadRemovalRule>;
+
class TypeDatabase
{
TypeDatabase();
@@ -161,6 +170,9 @@ public:
FunctionModificationList
globalFunctionModifications(const QStringList &signatures) const;
+ const OverloadRemovalRules &overloadRemovalRules() const;
+ void addOverloadRemovalRule(const OverloadRemovalRule &r);
+
bool addSuppressedWarning(const QString &warning, bool generate, QString *errorMessage);
bool isSuppressedWarning(QStringView s) const;
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
index ff3f3461c..2af1bab8c 100644
--- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp
+++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp
@@ -480,6 +480,7 @@ static const StackElementHash &stackElementHash()
{u"no-null-pointer", StackElement::NoNullPointers},
{u"object-type", StackElement::ObjectTypeEntry},
{u"opaque-container", StackElement::OpaqueContainer},
+ {u"overload-removal", StackElement::OverloadRemoval},
{u"parent", StackElement::ParentOwner},
{u"primitive-type", StackElement::PrimitiveTypeEntry},
{u"property", StackElement::Property},
@@ -1999,6 +2000,30 @@ bool TypeSystemParser::parseConfiguration(StackElement topElement,
return true;
}
+bool TypeSystemParser::parseOverloadRemoval(StackElement topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement != StackElement::Root) {
+ m_error = u"<overload-removal> can only appear under the root element."_s;
+ return false;
+ }
+ OverloadRemovalRule rule;
+ for (auto i = attributes->size() - 1; i >= 0; --i) {
+ const auto name = attributes->at(i).qualifiedName();
+ if (name == u"type") {
+ rule.type = attributes->takeAt(i).value().toString();
+ } else if (name == u"replaces") {
+ rule.redundantTypes = attributes->takeAt(i).value().toString().split(u';');
+ }
+ }
+ if (rule.type.isEmpty() || rule.redundantTypes.isEmpty()) {
+ m_error = u"<overload-removal> requires \"type\" and \"replaces\" attributes."_s;
+ return false;
+ }
+ TypeDatabase::instance()->addOverloadRemovalRule(rule);
+ return true;
+}
+
bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &,
QString *name, QXmlStreamAttributes *attributes)
{
@@ -3551,7 +3576,8 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
|| element == StackElement::AddFunction
|| element == StackElement::DeclareFunction
|| element == StackElement::Template
- || element == StackElement::OpaqueContainer;
+ || element == StackElement::OpaqueContainer
+ || element == StackElement::OverloadRemoval;
if (!topLevel && m_stack.at(m_stack.size() - 2) == StackElement::Root) {
m_error = u"Tag requires parent: '"_s + tagName.toString() + u'\'';
@@ -3728,6 +3754,10 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, Stack
if (!parseConfiguration(topElement, &attributes))
return false;
break;
+ case StackElement::OverloadRemoval:
+ if (!parseOverloadRemoval(topElement, &attributes))
+ return false;
+ break;
default:
break; // nada
}
diff --git a/sources/shiboken6/ApiExtractor/typesystemparser_p.h b/sources/shiboken6/ApiExtractor/typesystemparser_p.h
index b0e20913b..1f17c09a5 100644
--- a/sources/shiboken6/ApiExtractor/typesystemparser_p.h
+++ b/sources/shiboken6/ApiExtractor/typesystemparser_p.h
@@ -106,6 +106,7 @@ enum class StackElement {
ImportFile,
OpaqueContainer,
Configuration,
+ OverloadRemoval,
Unimplemented
};
@@ -213,6 +214,7 @@ private:
QXmlStreamAttributes *);
bool parseConfiguration(StackElement topElement,
QXmlStreamAttributes *attributes);
+ bool parseOverloadRemoval(StackElement topElement, QXmlStreamAttributes *attributes);
bool parseRenameFunction(const ConditionalStreamReader &, QString *name,
QXmlStreamAttributes *);
bool parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement,
diff --git a/sources/shiboken6/doc/typesystem.rst b/sources/shiboken6/doc/typesystem.rst
index 7c985b71f..07b5792ac 100644
--- a/sources/shiboken6/doc/typesystem.rst
+++ b/sources/shiboken6/doc/typesystem.rst
@@ -39,6 +39,7 @@ Modifying types
:maxdepth: 1
Function argument modifications <typesystem_arguments.rst>
+ typesystem_overloads.rst
typesystem_codeinjection.rst
typesystem_converters.rst
typesystem_containers.rst
diff --git a/sources/shiboken6/doc/typesystem_overloads.rst b/sources/shiboken6/doc/typesystem_overloads.rst
new file mode 100644
index 000000000..9b05bf9d5
--- /dev/null
+++ b/sources/shiboken6/doc/typesystem_overloads.rst
@@ -0,0 +1,38 @@
+.. _overload-removal:
+
+Restricting Function Overloads
+------------------------------
+
+Some class member functions have a number of overloads that differ in one parameter:
+
+.. code-block:: c++
+
+ class QByteArray {
+ public:
+ ...
+ static QByteArray number(int, int base = 10);
+ static QByteArray number(unsigned int, int base = 10);
+ static QByteArray number(long, int base = 10);
+ static QByteArray number(unsigned long, int base = 10);
+ static QByteArray number(long long, int base = 10);
+ static QByteArray number(unsigned long long, int base = 10);
+ ...
+
+In this case, it does not make sense to generate a binding for ``QByteArray number(int,...)``
+since it is equivalent to ``QByteArray number(long long,...)``.
+
+In the type system file, it is possible to specify a rule stating that the ``int``
+overload is to be removed when an ``long long`` overload exists by using
+the ``<overload-removal>`` element:
+
+.. code-block:: xml
+
+ <overload-removal type="long long" replaces="int"/>
+
+The ``type`` attribute specifies the preferred type and the
+``replaces`` attribute specifies a ';'-delimited list of types to be removed.
+
+.. note:: This is limited to the first 4 arguments of types that are passed by value or const-ref.
+
+.. note:: The rules are applied in the order specified. That is, a rule specifying that ``int``
+ replaces ``short`` should go before a rule rule specifying that ``long long`` replaces ``int``.
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
index 787a88008..1cb38fd0b 100644
--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -34,7 +34,7 @@ This is the root node containing all the type system information.
It may contain :ref:`add-function`, :ref:`container-type`,
:ref:`custom-type`, :ref:`enum-type`, :ref:`extra-includes`, :ref:`function`,
:ref:`load-typesystem`, :ref:`namespace`, :ref:`object-type`,
-:ref:`opaque-container`,
+:ref:`opaque-container`, :ref:`overload-removal`,
:ref:`primitive-type`, :ref:`rejection`, :ref:`smart-pointer-type`,
:ref:`suppress-warning`, :ref:`template`, :ref:`system_include`,
:ref:`typedef-type` or :ref:`value-type` child nodes.
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
index fdcfe3ea8..9f48cbb34 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -2245,15 +2245,121 @@ static void removeConstOverloads(AbstractMetaFunctionCList *overloads)
}
}
+// For a list of overloads of the same argument count, return a list of functions
+// that can be removed by the type system overload removal rules.
+static AbstractMetaFunctionCList filterFunctions(const OverloadRemovalRules &removalRules,
+ const AbstractMetaFunctionCList &overloads)
+{
+ const auto size = overloads.size();
+ Q_ASSERT(size > 1);
+ AbstractMetaFunctionCList result;
+
+ // Basic parameters that need to be equivalent
+ static constexpr AbstractMetaFunction::CompareResult expected =
+ AbstractMetaFunction::EqualName | AbstractMetaFunction::EqualVirtual
+ | AbstractMetaFunction::EqualConst | AbstractMetaFunction::EqualStatic
+ | AbstractMetaFunction::EqualReturnType;
+
+
+ // Find the varying argument and check if otherwise equivalent
+ AbstractMetaFunction::CompareResult differingArgMask{};
+ for (qsizetype a = 1; a < size; ++a) {
+ auto cr = overloads.constFirst()->compareTo(overloads.at(a).get());
+ if ((cr & expected) != expected)
+ return result;
+ auto argMask = cr & AbstractMetaFunction::Differ4ArgumentsMask;
+ if (a == 1)
+ differingArgMask = argMask;
+ else if (differingArgMask != argMask)
+ return result;
+ }
+
+ // Turn bit mask into argument number and check if only one argument differs
+ qsizetype argNo = -1;
+ if (differingArgMask == AbstractMetaFunction::DifferArgument1)
+ argNo = 0;
+ else if (differingArgMask == AbstractMetaFunction::DifferArgument2)
+ argNo = 1;
+ else if (differingArgMask == AbstractMetaFunction::DifferArgument3)
+ argNo = 2;
+ else if (differingArgMask == AbstractMetaFunction::DifferArgument4)
+ argNo = 3;
+ if (argNo < 0) // Several arguments differ
+ return result;
+
+ // Retrieve list of types of the varying argument
+ // FIXME PYSIDE-7: Refactor using C++ 20 views
+ QStringList types;
+ types.reserve(size);
+ for (const auto &f : overloads) {
+ auto amt = f->arguments().at(argNo).type();
+ if (!amt.passByValue() && !amt.passByConstRef()) // Only simple types so far
+ return result;
+ types.append(amt.isPrimitive()
+ ? basicReferencedTypeEntry(amt.typeEntry())->name() : amt.name());
+ }
+
+ // Apply rules and compile list of redundant functions
+ for (const auto &rule : removalRules) {
+ if (const auto index = types.indexOf(rule.type); index != -1) {
+ for (const auto &redundantType : rule.redundantTypes) {
+ if (const auto index2 = types.indexOf(redundantType); index2 != -1) {
+ auto redundant = overloads.at(index2);
+ if (!result.contains(redundant)) { // nested long->int->short rule?
+ ReportHandler::addGeneralMessage(msgRemoveRedundantOverload(redundant, rule.type));
+ result.append(redundant);
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static bool argCountLessThan(const AbstractMetaFunctionCPtr &f1, const AbstractMetaFunctionCPtr &f2)
+{
+ return f1->arguments().size() < f2->arguments().size();
+}
+
+// For a list of overloads of the same name, remove functions with redundant arguments.
+// as defined by the type system overload removal rules. It is important that the order
+// is preserved, else topological sorting in OverloadData will go haywire.
+static void filterAllFunctions(const OverloadRemovalRules &removalRules,
+ AbstractMetaFunctionCList *overloads)
+{
+ if (overloads->size() < 2)
+ return;
+ const auto maxArgsIt = std::max_element(overloads->cbegin(), overloads->cend(), argCountLessThan);
+ const auto maxArgs = (*maxArgsIt)->arguments().size();
+ if (maxArgs == 0)
+ return;
+
+ // FIXME PYSIDE-7: Refactor using C++ 20 views
+ for (qsizetype ac = 0; ac <= maxArgs; ++ac) {
+ // Check on lists of the same argument count.
+ AbstractMetaFunctionCList list;
+ auto sameArgumentCount = [ac](const AbstractMetaFunctionCPtr &f) {
+ return f->arguments().size() == ac; };
+ std::copy_if(overloads->cbegin(), overloads->cend(), std::back_inserter(list),
+ sameArgumentCount);
+ if (list.size() > 1) {
+ const auto redundant = filterFunctions(removalRules, list);
+ for (const auto &r : redundant)
+ overloads->removeAll(r);
+ }
+ }
+}
+
ShibokenGenerator::FunctionGroups
ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope,
AbstractMetaFunctionCList *constructors)
{
AbstractMetaFunctionCList lst = scope->functions();
scope->getFunctionsFromInvisibleNamespacesToBeGenerated(&lst);
+ const OverloadRemovalRules &removalRules = TypeDatabase::instance()->overloadRemovalRules();
FunctionGroups results;
- for (const auto &func : lst) {
+ for (const auto &func : std::as_const(lst)) {
if (isGroupable(func)
&& func->ownerClass() == func->implementingClass()
&& func->generateBinding()) {
@@ -2278,6 +2384,8 @@ ShibokenGenerator::FunctionGroups
}
getInheritedOverloads(scope, &it.value());
removeConstOverloads(&it.value());
+ if (!removalRules.isEmpty())
+ filterAllFunctions(removalRules, &it.value());
}
}
return results;