diff options
| -rw-r--r-- | sources/pyside6/PySide6/QtCore/typesystem_core_common.xml | 10 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetafunction.cpp | 31 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetafunction.h | 19 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/messages.cpp | 8 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/messages.h | 3 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typedatabase.cpp | 11 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typedatabase.h | 12 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typesystemparser.cpp | 32 | ||||
| -rw-r--r-- | sources/shiboken6/ApiExtractor/typesystemparser_p.h | 2 | ||||
| -rw-r--r-- | sources/shiboken6/doc/typesystem.rst | 1 | ||||
| -rw-r--r-- | sources/shiboken6/doc/typesystem_overloads.rst | 38 | ||||
| -rw-r--r-- | sources/shiboken6/doc/typesystem_specifying_types.rst | 2 | ||||
| -rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 110 |
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; |
