diff options
Diffstat (limited to 'sources/shiboken6/generator/shiboken/overloaddata.cpp')
-rw-r--r-- | sources/shiboken6/generator/shiboken/overloaddata.cpp | 867 |
1 files changed, 413 insertions, 454 deletions
diff --git a/sources/shiboken6/generator/shiboken/overloaddata.cpp b/sources/shiboken6/generator/shiboken/overloaddata.cpp index 468906d37..c28fcdc1a 100644 --- a/sources/shiboken6/generator/shiboken/overloaddata.cpp +++ b/sources/shiboken6/generator/shiboken/overloaddata.cpp @@ -1,79 +1,52 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <abstractmetafunction.h> #include <apiextractorresult.h> #include <abstractmetalang.h> +#include <dotview.h> #include <reporthandler.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <containertypeentry.h> +#include <primitivetypeentry.h> #include <graph.h> #include "overloaddata.h" +#include "messages.h" #include "ctypenames.h" #include "pytypenames.h" #include "textstream.h" +#include "exception.h" + +#include "qtcompat.h" #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QTemporaryFile> #include <algorithm> +#include <utility> -static const TypeEntry *getReferencedTypeEntry(const TypeEntry *typeEntry) -{ - if (typeEntry->isPrimitive()) { - auto pte = dynamic_cast<const PrimitiveTypeEntry *>(typeEntry); - while (pte->referencedTypeEntry()) - pte = pte->referencedTypeEntry(); - typeEntry = pte; - } - return typeEntry; -} +using namespace Qt::StringLiterals; static QString getTypeName(const AbstractMetaType &type) { - const TypeEntry *typeEntry = getReferencedTypeEntry(type.typeEntry()); + TypeEntryCPtr typeEntry = type.typeEntry(); + if (typeEntry->isPrimitive()) + typeEntry = basicReferencedTypeEntry(typeEntry); QString typeName = typeEntry->name(); if (typeEntry->isContainer()) { QStringList types; for (const auto &cType : type.instantiations()) { - const TypeEntry *typeEntry = getReferencedTypeEntry(cType.typeEntry()); + TypeEntryCPtr typeEntry = cType.typeEntry(); + if (typeEntry->isPrimitive()) + typeEntry = basicReferencedTypeEntry(typeEntry); types << typeEntry->name(); } - typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >"); + typeName += u'<' + types.join(u',') + u" >"_s; } return typeName; } -static QString getTypeName(const OverloadData *ov) -{ - return ov->hasArgumentTypeReplace() ? ov->argumentTypeReplaced() : getTypeName(ov->argType()); -} - static bool typesAreEqual(const AbstractMetaType &typeA, const AbstractMetaType &typeB) { if (typeA.typeEntry() == typeB.typeEntry()) { @@ -81,7 +54,7 @@ static bool typesAreEqual(const AbstractMetaType &typeA, const AbstractMetaType if (typeA.instantiations().size() != typeB.instantiations().size()) return false; - for (int i = 0; i < typeA.instantiations().size(); ++i) { + for (qsizetype i = 0; i < typeA.instantiations().size(); ++i) { if (!typesAreEqual(typeA.instantiations().at(i), typeB.instantiations().at(i))) return false; } @@ -115,48 +88,23 @@ static QString getImplicitConversionTypeName(const AbstractMetaType &containerTy for (const auto &otherType : containerType.instantiations()) types << (otherType == instantiation ? impConv : getTypeName(otherType)); - return containerType.typeEntry()->qualifiedCppName() + QLatin1Char('<') - + types.join(QLatin1String(", ")) + QLatin1String(" >"); -} - -// overloaddata.cpp -static QString msgCyclicDependency(const QString &funcName, const QString &graphName, - const AbstractMetaFunctionCList &cyclic, - const AbstractMetaFunctionCList &involvedConversions) -{ - QString result; - QTextStream str(&result); - str << "Cyclic dependency found on overloaddata for \"" << funcName - << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName) - << "\". Cyclic functions:"; - for (const auto &c : cyclic) - str << ' ' << c->signature(); - if (const int count = involvedConversions.size()) { - str << " Implicit conversions (" << count << "): "; - for (int i = 0; i < count; ++i) { - if (i) - str << ", \""; - str << involvedConversions.at(i)->signature() << '"'; - if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass()) - str << '(' << c->name() << ')'; - } - } - return result; + return containerType.typeEntry()->qualifiedCppName() + u'<' + + types.join(u", "_s) + u" >"_s; } -static inline int overloadNumber(const OverloadData *o) +static inline int overloadNumber(const OverloadDataNodePtr &o) { return o->referenceFunction()->overloadNumber(); } -bool OverloadData::sortByOverloadNumberModification() +static bool sortByOverloadNumberModification(OverloadDataList &list) { - if (std::all_of(m_nextOverloadData.cbegin(), m_nextOverloadData.cend(), - [](const OverloadData *o) { return overloadNumber(o) == TypeSystem::OverloadNumberDefault; })) { + if (std::all_of(list.cbegin(), list.cend(), + [](const OverloadDataNodePtr &o) { return overloadNumber(o) == TypeSystem::OverloadNumberDefault; })) { return false; } - std::stable_sort(m_nextOverloadData.begin(), m_nextOverloadData.end(), - [] (const OverloadData *o1, const OverloadData *o2) { + std::stable_sort(list.begin(), list.end(), + [] (const OverloadDataNodePtr &o1, const OverloadDataNodePtr &o2) { return overloadNumber(o1) < overloadNumber(o2); }); return true; @@ -174,9 +122,10 @@ using OverloadGraph = Graph<QString>; * * Side effects: Modifies m_nextOverloadData */ -void OverloadData::sortNextOverloads() +void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api) { QHash<QString, OverloadDataList> typeToOverloads; + using Edge = std::pair<QString, QString>; bool checkPyObject = false; bool checkPySequence = false; @@ -186,16 +135,16 @@ void OverloadData::sortNextOverloads() // Primitive types that are not int, long, short, // char and their respective unsigned counterparts. - static const QStringList nonIntegerPrimitives{floatT(), doubleT(), boolT()}; + static const QStringList nonIntegerPrimitives{floatT, doubleT, boolT}; // Signed integer primitive types. - static const QStringList signedIntegerPrimitives{intT(), shortT(), longT(), longLongT()}; + static const QStringList signedIntegerPrimitives{intT, shortT, longT, longLongT}; // sort the children overloads - for (OverloadData *ov : qAsConst(m_nextOverloadData)) - ov->sortNextOverloads(); + for (const auto &ov : std::as_const(m_children)) + ov->sortNextOverloads(api); - if (m_nextOverloadData.size() <= 1 || sortByOverloadNumberModification()) + if (m_children.size() <= 1 || sortByOverloadNumberModification(m_children)) return; // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids, @@ -203,8 +152,8 @@ void OverloadData::sortNextOverloads() // with graph sorting using integers. OverloadGraph graph; - for (OverloadData *ov : qAsConst(m_nextOverloadData)) { - const QString typeName = getTypeName(ov); + for (const auto &ov : std::as_const(m_children)) { + const QString typeName = getTypeName(ov->modifiedArgType()); auto it = typeToOverloads.find(typeName); if (it == typeToOverloads.end()) { typeToOverloads.insert(typeName, {ov}); @@ -213,15 +162,15 @@ void OverloadData::sortNextOverloads() it.value().append(ov); } - if (!checkPyObject && typeName == cPyObjectT()) + if (!checkPyObject && typeName == cPyObjectT) checkPyObject = true; - else if (!checkPySequence && typeName == cPySequenceT()) + else if (!checkPySequence && typeName == cPySequenceT) checkPySequence = true; - else if (!checkPyBuffer && typeName == cPyBufferT()) + else if (!checkPyBuffer && typeName == cPyBufferT) checkPyBuffer = true; - else if (!checkQVariant && typeName == qVariantT()) + else if (!checkQVariant && typeName == qVariantT) checkQVariant = true; - else if (!checkQString && typeName == qStringT()) + else if (!checkQString && typeName == qStringT) checkQString = true; for (const auto &instantiation : ov->argType().instantiations()) { @@ -234,10 +183,10 @@ void OverloadData::sortNextOverloads() // as Point must come before the PointF instantiation, or else list<Point> will never // be called. In the case of primitive types, list<double> must come before list<int>. if (instantiation.isPrimitive() && (signedIntegerPrimitives.contains(instantiation.name()))) { - for (const QString &primitive : qAsConst(nonIntegerPrimitives)) + for (const QString &primitive : std::as_const(nonIntegerPrimitives)) graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive)); } else { - const auto &funcs = m_api.implicitConversions(instantiation); + const auto &funcs = api.implicitConversions(instantiation); for (const auto &function : funcs) graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, function)); } @@ -247,9 +196,9 @@ void OverloadData::sortNextOverloads() // Create the graph of type dependencies based on implicit conversions. // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST! - static const QStringList primitiveTypes{intT(), unsignedIntT(), longT(), unsignedLongT(), - shortT(), unsignedShortT(), boolT(), unsignedCharT(), charT(), floatT(), - doubleT(), constCharPtrT()}; + static const QStringList primitiveTypes{intT, unsignedIntT, longT, unsignedLongT, + shortT, unsignedShortT, boolT, unsignedCharT, charT, floatT, + doubleT, constCharPtrT}; QStringList foundPrimitiveTypeIds; for (const auto &p : primitiveTypes) { @@ -258,18 +207,18 @@ void OverloadData::sortNextOverloads() } if (checkPySequence && checkPyObject) - graph.addEdge(cPySequenceT(), cPyObjectT()); + graph.addEdge(cPySequenceT, cPyObjectT); QStringList classesWithIntegerImplicitConversion; AbstractMetaFunctionCList involvedConversions; - for (OverloadData *ov : qAsConst(m_nextOverloadData)) { + for (const auto &ov : std::as_const(m_children)) { const AbstractMetaType &targetType = ov->argType(); - const QString targetTypeEntryName = getTypeName(ov); + const QString targetTypeEntryName = getTypeName(ov->modifiedArgType()); // Process implicit conversions - const auto &functions = m_api.implicitConversions(targetType); + const auto &functions = api.implicitConversions(targetType); for (const auto &function : functions) { QString convertibleType; if (function->isConversionOperator()) @@ -277,7 +226,7 @@ void OverloadData::sortNextOverloads() else convertibleType = getTypeName(function->arguments().constFirst().type()); - if (convertibleType == intT() || convertibleType == unsignedIntT()) + if (convertibleType == intT || convertibleType == unsignedIntT) classesWithIntegerImplicitConversion << targetTypeEntryName; if (!graph.hasNode(convertibleType)) @@ -292,10 +241,12 @@ void OverloadData::sortNextOverloads() // Process inheritance relationships if (targetType.isValue() || targetType.isObject()) { - auto metaClass = AbstractMetaClass::findClass(m_api.classes(), - targetType.typeEntry()); - const AbstractMetaClassList &ancestors = metaClass->allTypeSystemAncestors(); - for (const AbstractMetaClass *ancestor : ancestors) { + const auto te = targetType.typeEntry(); + auto metaClass = AbstractMetaClass::findClass(api.classes(), te); + if (!metaClass) + throw Exception(msgArgumentClassNotFound(m_overloads.constFirst(), te)); + const auto &ancestors = metaClass->allTypeSystemAncestors(); + for (const auto &ancestor : ancestors) { QString ancestorTypeName = ancestor->typeEntry()->name(); if (!graph.hasNode(ancestorTypeName)) continue; @@ -312,7 +263,7 @@ void OverloadData::sortNextOverloads() graph.addEdge(convertible, targetTypeEntryName); if (instantiation.isPrimitive() && (signedIntegerPrimitives.contains(instantiation.name()))) { - for (const QString &primitive : qAsConst(nonIntegerPrimitives)) { + for (const QString &primitive : std::as_const(nonIntegerPrimitives)) { QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive); // Avoid cyclic dependency. @@ -321,7 +272,7 @@ void OverloadData::sortNextOverloads() } } else { - const auto &funcs = m_api.implicitConversions(instantiation); + const auto &funcs = api.implicitConversions(instantiation); for (const auto &function : funcs) { QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function); @@ -337,28 +288,28 @@ void OverloadData::sortNextOverloads() if ((checkPySequence || checkPyObject || checkPyBuffer) - && !targetTypeEntryName.contains(cPyObjectT()) - && !targetTypeEntryName.contains(cPyBufferT()) - && !targetTypeEntryName.contains(cPySequenceT())) { + && !targetTypeEntryName.contains(cPyObjectT) + && !targetTypeEntryName.contains(cPyBufferT) + && !targetTypeEntryName.contains(cPySequenceT)) { if (checkPySequence) { // PySequence will be checked after all more specific types, but before PyObject. - graph.addEdge(targetTypeEntryName, cPySequenceT()); + graph.addEdge(targetTypeEntryName, cPySequenceT); } else if (checkPyBuffer) { // PySequence will be checked after all more specific types, but before PyObject. - graph.addEdge(targetTypeEntryName, cPyBufferT()); + graph.addEdge(targetTypeEntryName, cPyBufferT); } else { // Add dependency on PyObject, so its check is the last one (too generic). - graph.addEdge(targetTypeEntryName, cPyObjectT()); + graph.addEdge(targetTypeEntryName, cPyObjectT); } - } else if (checkQVariant && targetTypeEntryName != qVariantT()) { - if (!graph.containsEdge(qVariantT(), targetTypeEntryName)) // Avoid cyclic dependency. - graph.addEdge(targetTypeEntryName, qVariantT()); + } else if (checkQVariant && targetTypeEntryName != qVariantT) { + if (!graph.containsEdge(qVariantT, targetTypeEntryName)) // Avoid cyclic dependency. + graph.addEdge(targetTypeEntryName, qVariantT); } else if (checkQString && ov->argType().isPointer() - && targetTypeEntryName != qStringT() - && targetTypeEntryName != qByteArrayT() - && (!checkPyObject || targetTypeEntryName != cPyObjectT())) { - if (!graph.containsEdge(qStringT(), targetTypeEntryName)) // Avoid cyclic dependency. - graph.addEdge(targetTypeEntryName, qStringT()); + && targetTypeEntryName != qStringT + && targetTypeEntryName != qByteArrayT + && (!checkPyObject || targetTypeEntryName != cPyObjectT)) { + if (!graph.containsEdge(qStringT, targetTypeEntryName)) // Avoid cyclic dependency. + graph.addEdge(targetTypeEntryName, qStringT); } if (targetType.isEnum()) { @@ -369,25 +320,36 @@ void OverloadData::sortNextOverloads() } // QByteArray args need to be checked after QString args - if (graph.hasNode(qStringT()) && graph.hasNode(qByteArrayT())) - graph.addEdge(qStringT(), qByteArrayT()); + if (graph.hasNode(qStringT) && graph.hasNode(qByteArrayT)) + graph.addEdge(qStringT, qByteArrayT); - for (OverloadData *ov : qAsConst(m_nextOverloadData)) { + static const Edge rangeOrder[] = + {{doubleT, floatT}, + {longLongT, longT}, {longLongT, intT}, {intT, shortT}, + {unsignedLongLongT, unsignedLongT}, {unsignedLongLongT, unsignedT}, + {unsignedLongLongT, unsignedIntT}, {unsignedT, unsignedShortT} + }; + for (const auto &r : rangeOrder) { + if (graph.hasNode(r.first) && graph.hasNode(r.second)) + graph.addEdge(r.first, r.second); + } + + for (const auto &ov : std::as_const(m_children)) { const AbstractMetaType &targetType = ov->argType(); if (!targetType.isEnum()) continue; QString targetTypeEntryName = getTypeName(targetType); // Enum values must precede types implicitly convertible from "int" or "unsigned int". - for (const QString &implicitFromInt : qAsConst(classesWithIntegerImplicitConversion)) + for (const QString &implicitFromInt : std::as_const(classesWithIntegerImplicitConversion)) graph.addEdge(targetTypeEntryName, implicitFromInt); } // Special case for double(int i) (not tracked by m_generator->implicitConversions - for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) { + for (const QString &signedIntegerName : std::as_const(signedIntegerPrimitives)) { if (graph.hasNode(signedIntegerName)) { - for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) { + for (const QString &nonIntegerName : std::as_const(nonIntegerPrimitives)) { if (graph.hasNode(nonIntegerName)) graph.addEdge(nonIntegerName, signedIntegerName); } @@ -398,11 +360,11 @@ void OverloadData::sortNextOverloads() const auto unmappedResult = graph.topologicalSort(); if (!unmappedResult.isValid()) { QString funcName = referenceFunction()->name(); - if (referenceFunction()->ownerClass()) - funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.')); + if (auto owner = referenceFunction()->ownerClass()) + funcName.prepend(owner->name() + u'.'); // Dump overload graph - QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot"); + QString graphName = QDir::tempPath() + u'/' + funcName + u".dot"_s; graph.dumpDot(graphName, [] (const QString &n) { return n; }); AbstractMetaFunctionCList cyclic; for (const auto &typeName : unmappedResult.cyclic) { @@ -413,21 +375,45 @@ void OverloadData::sortNextOverloads() qCWarning(lcShiboken, "%s", qPrintable(msgCyclicDependency(funcName, graphName, cyclic, involvedConversions))); } - m_nextOverloadData.clear(); + m_children.clear(); for (const auto &typeName : unmappedResult.result) { const auto oit = typeToOverloads.constFind(typeName); if (oit != typeToOverloads.cend()) { std::copy(oit.value().crbegin(), oit.value().crend(), - std::back_inserter(m_nextOverloadData)); + std::back_inserter(m_children)); + } + } +} + +// Determine the minimum (first default argument)/maximum arguments (size) +// of a function (taking into account the removed arguments). +static std::pair<int, int> getMinMaxArgs(const AbstractMetaFunctionCPtr &func) +{ + int defaultValueIndex = -1; + const auto &arguments = func->arguments(); + int argIndex = 0; + for (const auto &arg : arguments) { + if (!arg.isModifiedRemoved()) { + if (defaultValueIndex < 0 && arg.hasDefaultValueExpression()) + defaultValueIndex = argIndex; + ++argIndex; } } + const int maxArgs = argIndex; + const int minArgs = defaultValueIndex >= 0 ? defaultValueIndex : maxArgs; + return {minArgs, maxArgs}; +} + +const OverloadDataRootNode *OverloadDataNode::parent() const +{ + return m_parent; } /** * Root constructor for OverloadData * * This constructor receives the list of overloads for a given function and iterates generating - * the graph of OverloadData instances. Each OverloadData instance references an argument/type + * the graph of OverloadData instances. Each OverloadDataNode instance references an argument/type * combination. * * Example: @@ -441,86 +427,58 @@ void OverloadData::sortNextOverloads() * */ OverloadData::OverloadData(const AbstractMetaFunctionCList &overloads, - const ApiExtractorResult &api) - : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(nullptr), - m_headOverloadData(this), m_previousOverloadData(nullptr), - m_api(api) + const ApiExtractorResult &api) : + OverloadDataRootNode(overloads) { for (const auto &func : overloads) { - m_overloads.append(func); - int argSize = func->arguments().size() - numberOfRemovedArguments(func); - if (m_minArgs > argSize) - m_minArgs = argSize; - else if (m_maxArgs < argSize) - m_maxArgs = argSize; - OverloadData *currentOverloadData = this; + const auto minMaxArgs = getMinMaxArgs(func); + if (minMaxArgs.first < m_minArgs) + m_minArgs = minMaxArgs.first; + if (minMaxArgs.second > m_maxArgs) + m_maxArgs = minMaxArgs.second; + OverloadDataRootNode *currentOverloadData = this; const AbstractMetaArgumentList &arguments = func->arguments(); for (const AbstractMetaArgument &arg : arguments) { - if (func->argumentRemoved(arg.argumentIndex() + 1)) - continue; - currentOverloadData = currentOverloadData->addOverloadData(func, arg); + if (!arg.isModifiedRemoved()) + currentOverloadData = currentOverloadData->addOverloadDataNode(func, arg); } } // Sort the overload possibilities so that the overload decisor code goes for the most // important cases first, based on the topological order of the implicit conversions - sortNextOverloads(); - - // Fix minArgs - if (minArgs() > maxArgs()) - m_headOverloadData->m_minArgs = maxArgs(); + sortNextOverloads(api); } -OverloadData::OverloadData(OverloadData *headOverloadData, const AbstractMetaFunctionCPtr &func, - const AbstractMetaType &argType, int argPos, - const ApiExtractorResult &api) : - m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType), - m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr), m_api(api) +OverloadDataNode::OverloadDataNode(const AbstractMetaFunctionCPtr &func, + OverloadDataRootNode *parent, + const AbstractMetaArgument &argument, + int argPos, + const QString argTypeReplaced) : + m_argument(argument), + m_argTypeReplaced(argTypeReplaced), + m_parent(parent), + m_argPos(argPos) { if (func) this->addOverload(func); } -void OverloadData::addOverload(const AbstractMetaFunctionCPtr &func) +void OverloadDataNode::addOverload(const AbstractMetaFunctionCPtr &func) { - int origNumArgs = func->arguments().size(); - int removed = numberOfRemovedArguments(func); - int numArgs = origNumArgs - removed; - - if (numArgs > m_headOverloadData->m_maxArgs) - m_headOverloadData->m_maxArgs = numArgs; - - if (numArgs < m_headOverloadData->m_minArgs) - m_headOverloadData->m_minArgs = numArgs; - - for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) { - if (func->argumentRemoved(i + 1)) - continue; - if (func->arguments().at(i).hasDefaultValueExpression()) { - int fixedArgIndex = i - removed; - if (fixedArgIndex < m_headOverloadData->m_minArgs) - m_headOverloadData->m_minArgs = fixedArgIndex; - } - } - m_overloads.append(func); } -OverloadData *OverloadData::addOverloadData(const AbstractMetaFunctionCPtr &func, - const AbstractMetaArgument &arg) +OverloadDataNode *OverloadDataRootNode::addOverloadDataNode(const AbstractMetaFunctionCPtr &func, + const AbstractMetaArgument &arg) { - const AbstractMetaType &argType = arg.type(); - OverloadData *overloadData = nullptr; + OverloadDataNodePtr overloadData; if (!func->isOperatorOverload()) { - for (OverloadData *tmp : qAsConst(m_nextOverloadData)) { + for (const auto &tmp : std::as_const(m_children)) { // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry? // If an argument have a type replacement, then we should create a new overloaddata // for it, unless the next argument also have a identical type replacement. - QString replacedArg = func->typeReplaced(tmp->m_argPos + 1); - bool argsReplaced = !replacedArg.isEmpty() || !tmp->m_argTypeReplaced.isEmpty(); - if ((!argsReplaced && typesAreEqual(tmp->m_argType, argType)) - || (argsReplaced && replacedArg == tmp->argumentTypeReplaced())) { + if (typesAreEqual(tmp->modifiedArgType(), arg.modifiedType())) { tmp->addOverload(func); overloadData = tmp; } @@ -528,34 +486,26 @@ OverloadData *OverloadData::addOverloadData(const AbstractMetaFunctionCPtr &func } if (!overloadData) { - overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1, m_api); - overloadData->m_previousOverloadData = this; - QString typeReplaced = func->typeReplaced(arg.argumentIndex() + 1); - - if (!typeReplaced.isEmpty()) - overloadData->m_argTypeReplaced = typeReplaced; - m_nextOverloadData.append(overloadData); + const int argpos = argPos() + 1; + overloadData.reset(new OverloadDataNode(func, this, arg, argpos)); + m_children.append(overloadData); } - return overloadData; + return overloadData.get(); } -QStringList OverloadData::returnTypes() const +bool OverloadData::hasNonVoidReturnType() const { - QSet<QString> retTypes; for (const auto &func : m_overloads) { - if (!func->typeReplaced(0).isEmpty()) - retTypes << func->typeReplaced(0); - else if (!func->argumentRemoved(0)) - retTypes << func->type().cppSignature(); + if (func->isTypeModified()) { + if (func->modifiedTypeName() != u"void") + return true; + } else { + if (!func->argumentRemoved(0) && !func->type().isVoid()) + return true; + } } - return retTypes.values(); -} - -bool OverloadData::hasNonVoidReturnType() const -{ - QStringList retTypes = returnTypes(); - return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1; + return false; } bool OverloadData::hasVarargs() const @@ -568,15 +518,6 @@ bool OverloadData::hasVarargs() const return false; } -bool OverloadData::hasAllowThread() const -{ - for (const auto &func : m_overloads) { - if (func->allowThread()) - return true; - } - return false; -} - bool OverloadData::hasStaticFunction(const AbstractMetaFunctionCList &overloads) { for (const auto &func : overloads) { @@ -641,20 +582,27 @@ bool OverloadData::hasStaticAndInstanceFunctions() const return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction(); } -AbstractMetaFunctionCPtr OverloadData::referenceFunction() const +OverloadDataRootNode::OverloadDataRootNode(const AbstractMetaFunctionCList &o) : + m_overloads(o) +{ +} + +OverloadDataRootNode::~OverloadDataRootNode() = default; + +AbstractMetaFunctionCPtr OverloadDataRootNode::referenceFunction() const { return m_overloads.constFirst(); } -const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunctionCPtr &func) const +const AbstractMetaArgument *OverloadDataNode::overloadArgument(const AbstractMetaFunctionCPtr &func) const { - if (isHeadOverloadData() || !m_overloads.contains(func)) + if (isRoot() || !m_overloads.contains(func)) return nullptr; int argPos = 0; int removed = 0; for (int i = 0; argPos <= m_argPos; i++) { - if (func->argumentRemoved(i + 1)) + if (func->arguments().at(i).isModifiedRemoved()) removed++; else argPos++; @@ -663,89 +611,54 @@ const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunctionCPt return &func->arguments().at(m_argPos + removed); } -OverloadDataList OverloadData::overloadDataOnPosition(OverloadData *overloadData, int argPos) const -{ - OverloadDataList overloadDataList; - if (overloadData->argPos() == argPos) { - overloadDataList.append(overloadData); - } else if (overloadData->argPos() < argPos) { - const OverloadDataList &data = overloadData->nextOverloadData(); - for (OverloadData *pd : data) - overloadDataList += overloadDataOnPosition(pd, argPos); - } - return overloadDataList; -} - -OverloadDataList OverloadData::overloadDataOnPosition(int argPos) const +bool OverloadDataRootNode::nextArgumentHasDefaultValue() const { - OverloadDataList overloadDataList; - overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos); - return overloadDataList; -} - -bool OverloadData::nextArgumentHasDefaultValue() const -{ - for (OverloadData *overloadData : m_nextOverloadData) { - if (!overloadData->getFunctionWithDefaultValue().isNull()) + for (const auto &overloadData : m_children) { + if (overloadData->getFunctionWithDefaultValue()) return true; } return false; } -static OverloadData *_findNextArgWithDefault(OverloadData *overloadData) +static const OverloadDataRootNode *_findNextArgWithDefault(const OverloadDataRootNode *overloadData) { - if (!overloadData->getFunctionWithDefaultValue().isNull()) + if (overloadData->getFunctionWithDefaultValue()) return overloadData; - OverloadData *result = nullptr; - const OverloadDataList &data = overloadData->nextOverloadData(); - for (OverloadData *odata : data) { - OverloadData *tmp = _findNextArgWithDefault(odata); + const OverloadDataRootNode *result = nullptr; + const OverloadDataList &data = overloadData->children(); + for (const auto &odata : data) { + const auto *tmp = _findNextArgWithDefault(odata.get()); if (!result || (tmp && result->argPos() > tmp->argPos())) result = tmp; } return result; } -OverloadData *OverloadData::findNextArgWithDefault() +const OverloadDataRootNode *OverloadDataRootNode::findNextArgWithDefault() const { return _findNextArgWithDefault(this); } -bool OverloadData::isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const +bool OverloadDataRootNode::isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const { - for (const OverloadData *pd : m_nextOverloadData) { + for (const auto &pd : m_children) { if (pd->overloads().contains(func)) return false; } return true; } -AbstractMetaFunctionCList OverloadData::overloadsWithoutRepetition() const +AbstractMetaFunctionCPtr OverloadDataRootNode::getFunctionWithDefaultValue() const { - AbstractMetaFunctionCList overloads = m_overloads; + const qsizetype argpos = argPos(); for (const auto &func : m_overloads) { - if (func->minimalSignature().endsWith(QLatin1String("const"))) - continue; - for (const auto &f : qAsConst(overloads)) { - if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) { - overloads.removeOne(f); - break; - } - } - } - return overloads; -} - -AbstractMetaFunctionCPtr OverloadData::getFunctionWithDefaultValue() const -{ - for (const auto &func : m_overloads) { - int removedArgs = 0; - for (int i = 0; i <= m_argPos + removedArgs; i++) { - if (func->argumentRemoved(i + 1)) + qsizetype removedArgs = 0; + for (qsizetype i = 0; i <= argpos + removedArgs; i++) { + if (func->arguments().at(i).isModifiedRemoved()) removedArgs++; } - if (func->arguments().at(m_argPos + removedArgs).hasDefaultValueExpression()) + if (func->arguments().at(argpos + removedArgs).hasDefaultValueExpression()) return func; } return {}; @@ -755,11 +668,11 @@ QList<int> OverloadData::invalidArgumentLengths() const { QSet<int> validArgLengths; - for (const auto &func : qAsConst(m_headOverloadData->m_overloads)) { + for (const auto &func : m_overloads) { const AbstractMetaArgumentList args = func->arguments(); int offset = 0; - for (int i = 0; i < args.size(); ++i) { - if (func->argumentRemoved(i+1)) { + for (qsizetype i = 0; i < args.size(); ++i) { + if (func->arguments().at(i).isModifiedRemoved()) { offset++; } else { if (args.at(i).hasDefaultValueExpression()) @@ -770,7 +683,7 @@ QList<int> OverloadData::invalidArgumentLengths() const } QList<int> invalidArgLengths; - for (int i = minArgs() + 1; i < maxArgs(); i++) { + for (int i = m_minArgs + 1; i < m_maxArgs; i++) { if (!validArgLengths.contains(i)) invalidArgLengths.append(i); } @@ -778,196 +691,204 @@ QList<int> OverloadData::invalidArgumentLengths() const return invalidArgLengths; } -int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos) +int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func) { - int removed = 0; - if (finalArgPos < 0) { - for (int i = 0; i < func->arguments().size(); i++) { - if (func->argumentRemoved(i + 1)) - removed++; - } - } else { - for (int i = 0; i < finalArgPos + removed; i++) { - if (func->argumentRemoved(i + 1)) - removed++; - } - } - return removed; + return std::count_if(func->arguments().cbegin(), func->arguments().cend(), + [](const AbstractMetaArgument &a) { return a.isModifiedRemoved(); }); } -bool OverloadData::isSingleArgument(const AbstractMetaFunctionCList &overloads) +int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos) { - bool singleArgument = true; - for (const auto &func : overloads) { - if (func->arguments().size() - numberOfRemovedArguments(func) != 1) { - singleArgument = false; - break; - } + Q_ASSERT(finalArgPos >= 0); + int removed = 0; + const auto size = func->arguments().size(); + for (qsizetype i = 0; i < qMin(size, qsizetype(finalArgPos + removed)); ++i) { + if (func->arguments().at(i).isModifiedRemoved()) + ++removed; } - return singleArgument; + return removed; } void OverloadData::dumpGraph(const QString &filename) const { QFile file(filename); if (file.open(QFile::WriteOnly)) { - TextStream s(&file); - s << m_headOverloadData->dumpGraph(); + QTextStream s(&file); + dumpRootGraph(s, m_minArgs, m_maxArgs); } } +QString OverloadData::dumpGraph() const +{ + QString result; + QTextStream s(&result); + dumpRootGraph(s, m_minArgs, m_maxArgs); + return result; +} + +bool OverloadData::showGraph() const +{ + return showDotGraph(referenceFunction()->name(), dumpGraph()); +} + static inline QString toHtml(QString s) { - s.replace(QLatin1Char('<'), QLatin1String("<")); - s.replace(QLatin1Char('>'), QLatin1String(">")); - s.replace(QLatin1Char('&'), QLatin1String("&")); + s.replace(u'<', u"<"_s); + s.replace(u'>', u">"_s); + s.replace(u'&', u"&"_s); return s; } -QString OverloadData::dumpGraph() const +void OverloadDataRootNode::dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const { - QString result; - QTextStream s(&result); - if (m_argPos == -1) { - const auto rfunc = referenceFunction(); - s << "digraph OverloadedFunction {\n"; - s << " graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];\n"; - - // Shows all function signatures - s << "legend [fontsize=9 fontname=freemono shape=rect label=\""; - for (const auto &func : m_overloads) { - s << "f" << functionNumber(func) << " : " - << toHtml(func->type().cppSignature()) - << ' ' << toHtml(func->minimalSignature()) << "\\l"; - } - s << "\"];\n"; - - // Function box title - s << " \"" << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 "; - s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; - s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">"; - if (rfunc->ownerClass()) - s << rfunc->ownerClass()->name() << "::"; - s << toHtml(rfunc->name()) << "</font>"; - if (rfunc->isVirtual()) { - s << "<br/><font color=\"white\" point-size=\"10\"><<"; - if (rfunc->isAbstract()) - s << "pure "; - s << "virtual>></font>"; - } - s << "</td></tr>"; + const auto rfunc = referenceFunction(); + s << "digraph OverloadedFunction {\n"; + s << " graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];\n"; - // Function return type - s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">" - << toHtml(rfunc->type().cppSignature()) - << "</td></tr>"; + // Shows all function signatures + s << "legend [fontsize=9 fontname=freemono shape=rect label=\""; + for (const auto &func : m_overloads) { + s << "f" << functionNumber(func) << " : " + << toHtml(func->type().cppSignature()) + << ' ' << toHtml(func->minimalSignature()) << "\\l"; + } + s << "\"];\n"; + + // Function box title + s << " \"" << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 "; + s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; + s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">"; + if (rfunc->ownerClass()) + s << rfunc->ownerClass()->name() << "::"; + s << toHtml(rfunc->name()) << "</font>"; + if (rfunc->isVirtual()) { + s << "<br/><font color=\"white\" point-size=\"10\"><<"; + if (rfunc->isAbstract()) + s << "pure "; + s << "virtual>></font>"; + } + s << "</td></tr>"; + + // Function return type + s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">" + << toHtml(rfunc->type().cppSignature()) + << "</td></tr>"; + + // Shows type changes for all function signatures + for (const auto &func : m_overloads) { + if (!func->isTypeModified()) + continue; + s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func); + s << "-type</td><td bgcolor=\"gray\" align=\"left\">"; + s << toHtml(func->modifiedTypeName()) << "</td></tr>"; + } - // Shows type changes for all function signatures - for (const auto &func : m_overloads) { - if (func->typeReplaced(0).isEmpty()) - continue; - s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func); - s << "-type</td><td bgcolor=\"gray\" align=\"left\">"; - s << toHtml(func->typeReplaced(0)) << "</td></tr>"; - } + // Minimum and maximum number of arguments + s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">"; + s << minArgs << "</td></tr>"; + s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">"; + s << maxArgs << "</td></tr>"; - // Minimum and maximum number of arguments - s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">"; - s << minArgs() << "</td></tr>"; - s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">"; - s << maxArgs() << "</td></tr>"; - - if (rfunc->ownerClass()) { - if (rfunc->implementingClass() != rfunc->ownerClass()) - s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>"; - if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass()) - s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>"; - } + if (rfunc->ownerClass()) { + if (rfunc->implementingClass() != rfunc->ownerClass()) + s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>"; + if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass()) + s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>"; + } - // Overloads for the signature to present point - s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">"; - for (const auto &func : m_overloads) - s << 'f' << functionNumber(func) << ' '; - s << "</td></tr>"; + // Overloads for the signature to present point + s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">"; + for (const auto &func : m_overloads) + s << 'f' << functionNumber(func) << ' '; + s << "</td></tr>"; - s << "</table>> ];\n"; + s << "</table>> ];\n"; - for (const OverloadData *pd : m_nextOverloadData) - s << " \"" << rfunc->name() << "\" -> " << pd->dumpGraph(); + for (const auto &pd : m_children) { + s << " \"" << rfunc->name() << "\" -> "; + pd->dumpNodeGraph(s); + } - s << "}\n"; - } else { - QString argId = QLatin1String("arg_") + QString::number(quintptr(this)); - s << argId << ";\n"; + s << "}\n"; +} - s << " \"" << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 "; - s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; +void OverloadDataNode::dumpNodeGraph(QTextStream &s) const +{ + QString argId = u"arg_"_s + QString::number(quintptr(this)); + s << argId << ";\n"; - // Argument box title - s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">"; - s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>"; + s << " \"" << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 "; + s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; - // Argument type information - QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType().cppSignature(); - s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">"; - s << toHtml(type) << "</td></tr>"; - if (hasArgumentTypeReplace()) { - s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">"; - s << toHtml(argType().cppSignature()) << "</td></tr>"; - } + // Argument box title + s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">"; + s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>"; - // Overloads for the signature to present point - s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">"; - for (const auto &func : m_overloads) - s << 'f' << functionNumber(func) << ' '; - s << "</td></tr>"; + // Argument type information + const QString type = modifiedArgType().cppSignature(); + s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">"; + s << toHtml(type) << "</td></tr>"; + if (isTypeModified()) { + s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">"; + s << toHtml(argType().cppSignature()) << "</td></tr>"; + } - // Show default values (original and modified) for various functions - for (const auto &func : m_overloads) { - const AbstractMetaArgument *arg = argument(func); - if (!arg) - continue; - QString argDefault = arg->defaultValueExpression(); - if (!argDefault.isEmpty() || - argDefault != arg->originalDefaultValueExpression()) { - s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func); - s << "-default</td><td bgcolor=\"gray\" align=\"left\">"; - s << argDefault << "</td></tr>"; - } - if (argDefault != arg->originalDefaultValueExpression()) { - s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func); - s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">"; - s << arg->originalDefaultValueExpression() << "</td></tr>"; - } - } + const OverloadDataRootNode *root = this; + while (!root->isRoot()) + root = root->parent(); - s << "</table>>];\n"; + // Overloads for the signature to present point + s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">"; + for (const auto &func : m_overloads) + s << 'f' << root->functionNumber(func) << ' '; + s << "</td></tr>"; - for (const OverloadData *pd : m_nextOverloadData) - s << " " << argId << " -> " << pd->dumpGraph(); + // Show default values (original and modified) for various functions + for (const auto &func : m_overloads) { + const AbstractMetaArgument *arg = overloadArgument(func); + if (!arg) + continue; + const int n = root->functionNumber(func); + QString argDefault = arg->defaultValueExpression(); + if (!argDefault.isEmpty() || + argDefault != arg->originalDefaultValueExpression()) { + s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n; + s << "-default</td><td bgcolor=\"gray\" align=\"left\">"; + s << argDefault << "</td></tr>"; + } + if (argDefault != arg->originalDefaultValueExpression()) { + s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n; + s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">"; + s << arg->originalDefaultValueExpression() << "</td></tr>"; + } } - return result; -} -int OverloadData::functionNumber(const AbstractMetaFunctionCPtr &func) const -{ - return m_headOverloadData->m_overloads.indexOf(func); -} + s << "</table>>];\n"; -OverloadData::~OverloadData() -{ - while (!m_nextOverloadData.isEmpty()) - delete m_nextOverloadData.takeLast(); + for (const auto &pd : m_children) { + s << " " << argId << " -> "; + pd->dumpNodeGraph(s); + } } -bool OverloadData::hasArgumentTypeReplace() const +int OverloadDataRootNode::functionNumber(const AbstractMetaFunctionCPtr &func) const { - return !m_argTypeReplaced.isEmpty(); + return m_overloads.indexOf(func); } -QString OverloadData::argumentTypeReplaced() const +bool OverloadData::pythonFunctionWrapperUsesListOfArguments() const { - return m_argTypeReplaced; + auto referenceFunction = m_overloads.constFirst(); + if (referenceFunction->isCallOperator()) + return true; + if (referenceFunction->isOperatorOverload()) + return false; + const int maxArgs = this->maxArgs(); + const int minArgs = this->minArgs(); + return (minArgs != maxArgs) + || (maxArgs > 1) + || referenceFunction->isConstructor() + || hasArgumentWithDefaultValue(); } bool OverloadData::hasArgumentWithDefaultValue() const @@ -985,9 +906,7 @@ bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionCPtr &f { const AbstractMetaArgumentList &arguments = func->arguments(); for (const AbstractMetaArgument &arg : arguments) { - if (func->argumentRemoved(arg.argumentIndex() + 1)) - continue; - if (arg.hasDefaultValueExpression()) + if (!arg.isModifiedRemoved() && arg.hasDefaultValueExpression()) return true; } return false; @@ -999,7 +918,7 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr const AbstractMetaArgumentList &arguments = func->arguments(); for (const AbstractMetaArgument &arg : arguments) { if (!arg.hasDefaultValueExpression() - || func->argumentRemoved(arg.argumentIndex() + 1)) + || arg.isModifiedRemoved()) continue; args << arg; } @@ -1007,9 +926,9 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr } #ifndef QT_NO_DEBUG_STREAM -void OverloadData::formatDebug(QDebug &d) const + +void OverloadDataRootNode::formatReferenceFunction(QDebug &d) const { - const qsizetype count = m_overloads.size(); auto refFunc = referenceFunction(); d << '"'; if (auto owner = refFunc->ownerClass()) @@ -1017,36 +936,76 @@ void OverloadData::formatDebug(QDebug &d) const d << refFunc->minimalSignature() << '"'; if (m_overloads.constFirst()->isReverseOperator()) d << " [reverseop]"; - d << ", argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs - << ", argPos=" << m_argPos; - if (!m_argTypeReplaced.isEmpty()) - d << ", argTypeReplaced=\"" << m_argTypeReplaced << '"'; +} +void OverloadDataRootNode::formatOverloads(QDebug &d) const +{ + const qsizetype count = m_overloads.size(); + d << ", overloads[" << count << ']'; if (count < 2) return; - d << "\", overloads[" << count << "]=("; - const int oldVerbosity = d.verbosity(); - d.setVerbosity(3); - for (int i = 0; i < count; ++i) { - if (i) - d << '\n'; - d << m_overloads.at(i).data(); - } - d.setVerbosity(oldVerbosity); - d << ')'; + d << "=("; + for (qsizetype i = 0; i < count; ++i) { + if (i) + d << '\n'; + d << m_overloads.at(i)->signature(); + } + d << ')'; } -QDebug operator<<(QDebug d, const OverloadData *od) +void OverloadDataRootNode::formatNextOverloadData(QDebug &d) const +{ + const qsizetype count = m_children.size(); + d << ", next[" << count << ']'; + if (d.verbosity() >= 3) { + d << "=("; + for (qsizetype i = 0; i < count; ++i) { + if (i) + d << '\n'; + m_children.at(i)->formatDebug(d); + } + d << ')'; + } +} + +void OverloadDataRootNode::formatDebug(QDebug &d) const +{ + formatReferenceFunction(d); + formatOverloads(d); + formatNextOverloadData(d); +} + +void OverloadDataNode::formatDebug(QDebug &d) const +{ + d << "OverloadDataNode("; + formatReferenceFunction(d); + d << ", argPos=" << m_argPos; + if (m_argument.argumentIndex() != m_argPos) + d << ", argIndex=" << m_argument.argumentIndex(); + d << ", argType=\"" << m_argument.type().cppSignature() << '"'; + if (isTypeModified()) + d << ", modifiedArgType=\"" << modifiedArgType().cppSignature() << '"'; + formatOverloads(d); + formatNextOverloadData(d); + d << ')'; +} + +void OverloadData::formatDebug(QDebug &d) const +{ + d << "OverloadData("; + formatReferenceFunction(d); + d << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs; + formatOverloads(d); + formatNextOverloadData(d); + d << ')'; +} + +QDebug operator<<(QDebug d, const OverloadData &od) { QDebugStateSaver saver(d); d.noquote(); d.nospace(); - d << "OverloadData("; - if (od) - od->formatDebug(d); - else - d << '0'; - d << ')'; + od.formatDebug(d); return d; } #endif // !QT_NO_DEBUG_STREAM |