aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/shiboken2/overloaddata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator/shiboken2/overloaddata.cpp')
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp1091
1 files changed, 0 insertions, 1091 deletions
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
deleted file mode 100644
index bd39e9444..000000000
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ /dev/null
@@ -1,1091 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include <abstractmetalang.h>
-#include <reporthandler.h>
-#include <graph.h>
-#include "overloaddata.h"
-#include "indentor.h"
-#include "shibokengenerator.h"
-
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QTemporaryFile>
-
-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;
-}
-
-static QString getTypeName(const AbstractMetaType *type)
-{
- const TypeEntry *typeEntry = getReferencedTypeEntry(type->typeEntry());
- QString typeName = typeEntry->name();
- if (typeEntry->isContainer()) {
- QStringList types;
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *cType : instantiations) {
- const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry());
- types << typeEntry->name();
- }
- typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >");
- }
- 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()) {
- if (typeA->isContainer() || typeA->isSmartPointer()) {
- if (typeA->instantiations().size() != typeB->instantiations().size())
- return false;
-
- for (int i = 0; i < typeA->instantiations().size(); ++i) {
- if (!typesAreEqual(typeA->instantiations().at(i), typeB->instantiations().at(i)))
- return false;
- }
- return true;
- }
-
- return !(ShibokenGenerator::isCString(typeA) ^ ShibokenGenerator::isCString(typeB));
- }
- return false;
-}
-
-
-/**
- * OverloadSortData just helps writing clearer code in the
- * OverloadData::sortNextOverloads method.
- */
-struct OverloadSortData
-{
- /**
- * Adds a typeName into the type map without associating it with
- * a OverloadData. This is done to express type dependencies that could
- * or could not appear in overloaded signatures not processed yet.
- */
- void mapType(const QString &typeName)
- {
- if (map.contains(typeName))
- return;
- map[typeName] = counter;
- if (!reverseMap.contains(counter))
- reverseMap[counter] = nullptr;
- counter++;
- }
-
- void mapType(OverloadData *overloadData)
- {
- QString typeName = getTypeName(overloadData);
- map[typeName] = counter;
- reverseMap[counter] = overloadData;
- counter++;
- }
-
- int lastProcessedItemId() { return counter - 1; }
-
- int counter = 0;
- QHash<QString, int> map; // typeName -> id
- QHash<int, OverloadData *> reverseMap; // id -> OverloadData;
-};
-
-/**
- * Helper function that returns the name of a container get from containerType argument and
- * an instantiation taken either from an implicit conversion expressed by the function argument,
- * or from the string argument implicitConvTypeName.
- */
-static QString getImplicitConversionTypeName(const AbstractMetaType *containerType,
- const AbstractMetaType *instantiation,
- const AbstractMetaFunction *function,
- const QString &implicitConvTypeName = QString())
-{
- QString impConv;
- if (!implicitConvTypeName.isEmpty())
- impConv = implicitConvTypeName;
- else if (function->isConversionOperator())
- impConv = function->ownerClass()->typeEntry()->name();
- else
- impConv = getTypeName(function->arguments().constFirst()->type());
-
- QStringList types;
- const AbstractMetaTypeList &instantiations = containerType->instantiations();
- for (const AbstractMetaType *otherType : 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 OverloadData::MetaFunctionList &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)
- << "\".";
- 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;
-}
-
-/**
- * Topologically sort the overloads by implicit convertion order
- *
- * This avoids using an implicit conversion if there's an explicit
- * overload for the convertible type. So, if there's an implicit convert
- * like TargetType(ConvertibleType foo) and both are in the overload list,
- * ConvertibleType is checked before TargetType.
- *
- * Side effects: Modifies m_nextOverloadData
- */
-void OverloadData::sortNextOverloads()
-{
- OverloadSortData sortData;
- bool checkPyObject = false;
- int pyobjectIndex = 0;
- bool checkPySequence = false;
- int pySeqIndex = 0;
- bool checkQString = false;
- int qstringIndex = 0;
- bool checkQVariant = false;
- int qvariantIndex = 0;
- bool checkPyBuffer = false;
- int pyBufferIndex = 0;
-
- // Primitive types that are not int, long, short,
- // char and their respective unsigned counterparts.
- QStringList nonIntegerPrimitives;
- nonIntegerPrimitives << QLatin1String("float") << QLatin1String("double")
- << QLatin1String("bool");
-
- // Signed integer primitive types.
- QStringList signedIntegerPrimitives;
- signedIntegerPrimitives << QLatin1String("int") << QLatin1String("short")
- << QLatin1String("long");
-
- // sort the children overloads
- for (OverloadData *ov : qAsConst(m_nextOverloadData))
- ov->sortNextOverloads();
-
- if (m_nextOverloadData.size() <= 1)
- return;
-
- // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids,
- // these ids will be used by the topological sort algorithm, because is easier and faster to work
- // with graph sorting using integers.
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- sortData.mapType(ov);
-
- const QString typeName(getTypeName(ov));
-
- if (!checkPyObject && typeName.contains(QLatin1String("PyObject"))) {
- checkPyObject = true;
- pyobjectIndex = sortData.lastProcessedItemId();
- } else if (!checkPySequence && typeName == QLatin1String("PySequence")) {
- checkPySequence = true;
- pySeqIndex = sortData.lastProcessedItemId();
- } else if (!checkPyBuffer && typeName == QLatin1String("PyBuffer")) {
- checkPyBuffer = true;
- pyBufferIndex = sortData.lastProcessedItemId();
- } else if (!checkQVariant && typeName == QLatin1String("QVariant")) {
- checkQVariant = true;
- qvariantIndex = sortData.lastProcessedItemId();
- } else if (!checkQString && typeName == QLatin1String("QString")) {
- checkQString = true;
- qstringIndex = sortData.lastProcessedItemId();
- }
-
- const AbstractMetaTypeList &instantiations = ov->argType()->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
- // Add dependencies for type instantiation of container.
- QString typeName = getTypeName(instantiation);
- sortData.mapType(typeName);
-
- // Build dependency for implicit conversion types instantiations for base container.
- // For example, considering signatures "method(list<PointF>)" and "method(list<Point>)",
- // and being PointF implicitly convertible from Point, an list<T> instantiation with T
- // 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))
- sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive));
- } else {
- const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
- for (const AbstractMetaFunction *function : funcs)
- sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, function));
- }
- }
- }
-
-
- // Create the graph of type dependencies based on implicit conversions.
- Graph graph(sortData.reverseMap.count());
- // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
- const char *primitiveTypes[] = {"int",
- "unsigned int",
- "long",
- "unsigned long",
- "short",
- "unsigned short",
- "bool",
- "unsigned char",
- "char",
- "float",
- "double",
- "const char*"
- };
- const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char *);
- bool hasPrimitive[numPrimitives];
- for (int i = 0; i < numPrimitives; ++i)
- hasPrimitive[i] = sortData.map.contains(QLatin1String(primitiveTypes[i]));
-
- if (checkPySequence && checkPyObject)
- graph.addEdge(pySeqIndex, pyobjectIndex);
-
- QStringList classesWithIntegerImplicitConversion;
-
- MetaFunctionList involvedConversions;
-
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- const AbstractMetaType *targetType = ov->argType();
- const QString targetTypeEntryName(getTypeName(ov));
- int targetTypeId = sortData.map[targetTypeEntryName];
-
- // Process implicit conversions
- const AbstractMetaFunctionList &functions = m_generator->implicitConversions(targetType);
- for (AbstractMetaFunction *function : functions) {
- QString convertibleType;
- if (function->isConversionOperator())
- convertibleType = function->ownerClass()->typeEntry()->name();
- else
- convertibleType = getTypeName(function->arguments().constFirst()->type());
-
- if (convertibleType == QLatin1String("int") || convertibleType == QLatin1String("unsigned int"))
- classesWithIntegerImplicitConversion << targetTypeEntryName;
-
- if (!sortData.map.contains(convertibleType))
- continue;
-
- int convertibleTypeId = sortData.map[convertibleType];
-
- // If a reverse pair already exists, remove it. Probably due to the
- // container check (This happened to QVariant and QHash)
- graph.removeEdge(targetTypeId, convertibleTypeId);
- graph.addEdge(convertibleTypeId, targetTypeId);
- involvedConversions.append(function);
- }
-
- // Process inheritance relationships
- if (targetType->isValue() || targetType->isObject()) {
- const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_generator->classes(), targetType->typeEntry());
- const AbstractMetaClassList &ancestors = m_generator->getAllAncestors(metaClass);
- for (const AbstractMetaClass *ancestor : ancestors) {
- QString ancestorTypeName = ancestor->typeEntry()->name();
- if (!sortData.map.contains(ancestorTypeName))
- continue;
- int ancestorTypeId = sortData.map[ancestorTypeName];
- graph.removeEdge(ancestorTypeId, targetTypeId);
- graph.addEdge(targetTypeId, ancestorTypeId);
- }
- }
-
- // Process template instantiations
- const AbstractMetaTypeList &instantiations = targetType->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
- if (sortData.map.contains(getTypeName(instantiation))) {
- int convertible = sortData.map[getTypeName(instantiation)];
-
- if (!graph.containsEdge(targetTypeId, convertible)) // Avoid cyclic dependency.
- graph.addEdge(convertible, targetTypeId);
-
- if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) {
- for (const QString &primitive : qAsConst(nonIntegerPrimitives)) {
- QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive);
- if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) // Avoid cyclic dependency.
- graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
- }
-
- } else {
- const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
- for (const AbstractMetaFunction *function : funcs) {
- QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function);
- if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) { // Avoid cyclic dependency.
- graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
- involvedConversions.append(function);
- }
- }
- }
- }
- }
-
-
- if ((checkPySequence || checkPyObject || checkPyBuffer)
- && !targetTypeEntryName.contains(QLatin1String("PyObject"))
- && !targetTypeEntryName.contains(QLatin1String("PyBuffer"))
- && !targetTypeEntryName.contains(QLatin1String("PySequence"))) {
- if (checkPySequence) {
- // PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeId, pySeqIndex);
- } else if (checkPyBuffer) {
- // PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeId, pyBufferIndex);
- } else {
- // Add dependency on PyObject, so its check is the last one (too generic).
- graph.addEdge(targetTypeId, pyobjectIndex);
- }
- } else if (checkQVariant && targetTypeEntryName != QLatin1String("QVariant")) {
- if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeId, qvariantIndex);
- } else if (checkQString && ShibokenGenerator::isPointer(ov->argType())
- && targetTypeEntryName != QLatin1String("QString")
- && targetTypeEntryName != QLatin1String("QByteArray")
- && (!checkPyObject || targetTypeId != pyobjectIndex)) {
- if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeId, qstringIndex);
- }
-
- if (targetType->isEnum()) {
- // Enum values must precede primitive types.
- for (int i = 0; i < numPrimitives; ++i) {
- if (hasPrimitive[i])
- graph.addEdge(targetTypeId, sortData.map[QLatin1String(primitiveTypes[i])]);
- }
- }
- }
-
- // QByteArray args need to be checked after QString args
- if (sortData.map.contains(QLatin1String("QString")) && sortData.map.contains(QLatin1String("QByteArray")))
- graph.addEdge(sortData.map[QLatin1String("QString")], sortData.map[QLatin1String("QByteArray")]);
-
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- 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))
- graph.addEdge(sortData.map[targetTypeEntryName], sortData.map[implicitFromInt]);
- }
-
-
- // Special case for double(int i) (not tracked by m_generator->implicitConversions
- for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) {
- if (sortData.map.contains(signedIntegerName)) {
- for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) {
- if (sortData.map.contains(nonIntegerName))
- graph.addEdge(sortData.map[nonIntegerName], sortData.map[signedIntegerName]);
- }
- }
- }
-
- // sort the overloads topologically based on the dependency graph.
- const auto unmappedResult = graph.topologicalSort();
- if (unmappedResult.isEmpty()) {
- QString funcName = referenceFunction()->name();
- if (referenceFunction()->ownerClass())
- funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.'));
-
- // Dump overload graph
- QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot");
- QHash<int, QString> nodeNames;
- for (auto it = sortData.map.cbegin(), end = sortData.map.cend(); it != end; ++it)
- nodeNames.insert(it.value(), it.key());
- graph.dumpDot(nodeNames, graphName);
- qCWarning(lcShiboken).noquote() << qPrintable(msgCyclicDependency(funcName, graphName, involvedConversions));
- }
-
- m_nextOverloadData.clear();
- for (int i : unmappedResult) {
- if (!sortData.reverseMap[i])
- continue;
- m_nextOverloadData << sortData.reverseMap[i];
- }
-}
-
-/**
- * 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
- * combination.
- *
- * Example:
- * addStuff(double, PyObject *)
- * addStuff(double, int)
- *
- * Given these two overloads, there will be the following graph:
- *
- * addStuff - double - PyObject *
- * \- int
- *
- */
-OverloadData::OverloadData(const AbstractMetaFunctionList &overloads, const ShibokenGenerator *generator)
- : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(nullptr),
- m_headOverloadData(this), m_previousOverloadData(nullptr), m_generator(generator)
-{
- for (const AbstractMetaFunction *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 AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- currentOverloadData = currentOverloadData->addOverloadData(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();
-}
-
-OverloadData::OverloadData(OverloadData *headOverloadData, const AbstractMetaFunction *func,
- const AbstractMetaType *argType, int argPos)
- : m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
- m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr),
- m_generator(nullptr)
-{
- if (func)
- this->addOverload(func);
-}
-
-void OverloadData::addOverload(const AbstractMetaFunction *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 AbstractMetaFunction *func,
- const AbstractMetaArgument *arg)
-{
- const AbstractMetaType *argType = arg->type();
- OverloadData *overloadData = nullptr;
- if (!func->isOperatorOverload()) {
- for (OverloadData *tmp : qAsConst(m_nextOverloadData)) {
- // 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())) {
- tmp->addOverload(func);
- overloadData = tmp;
- }
- }
- }
-
- if (!overloadData) {
- overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1);
- overloadData->m_previousOverloadData = this;
- overloadData->m_generator = this->m_generator;
- QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
-
- if (!typeReplaced.isEmpty())
- overloadData->m_argTypeReplaced = typeReplaced;
- m_nextOverloadData.append(overloadData);
- }
-
- return overloadData;
-}
-
-QStringList OverloadData::returnTypes() const
-{
- QSet<QString> retTypes;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (!func->typeReplaced(0).isEmpty())
- retTypes << func->typeReplaced(0);
- else if (func->type() && !func->argumentRemoved(0))
- retTypes << func->type()->cppSignature();
- else
- retTypes << QLatin1String("void");
- }
- return retTypes.values();
-}
-
-bool OverloadData::hasNonVoidReturnType() const
-{
- QStringList retTypes = returnTypes();
- return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1;
-}
-
-bool OverloadData::hasVarargs() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- AbstractMetaArgumentList args = func->arguments();
- if (args.size() > 1 && args.constLast()->type()->isVarargs())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasAllowThread() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->allowThread())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList &overloads)
-{
- for (const AbstractMetaFunction *func : qAsConst(overloads)) {
- if (func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasStaticFunction() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList &overloads)
-{
- for (const AbstractMetaFunction *func : qAsConst(overloads)) {
- if (!func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasInstanceFunction() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- if (!func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionList &overloads)
-{
- return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads);
-}
-
-bool OverloadData::hasStaticAndInstanceFunctions() const
-{
- return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
-}
-
-const AbstractMetaFunction *OverloadData::referenceFunction() const
-{
- return m_overloads.constFirst();
-}
-
-const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunction *func) const
-{
- if (isHeadOverloadData() || !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))
- removed++;
- else
- argPos++;
- }
-
- 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
-{
- OverloadDataList overloadDataList;
- overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos);
- return overloadDataList;
-}
-
-bool OverloadData::nextArgumentHasDefaultValue() const
-{
- for (OverloadData *overloadData : m_nextOverloadData) {
- if (overloadData->getFunctionWithDefaultValue())
- return true;
- }
- return false;
-}
-
-static OverloadData *_findNextArgWithDefault(OverloadData *overloadData)
-{
- if (overloadData->getFunctionWithDefaultValue())
- return overloadData;
-
- OverloadData *result = nullptr;
- const OverloadDataList &data = overloadData->nextOverloadData();
- for (OverloadData *odata : data) {
- OverloadData *tmp = _findNextArgWithDefault(odata);
- if (!result || (tmp && result->argPos() > tmp->argPos()))
- result = tmp;
- }
- return result;
-}
-
-OverloadData *OverloadData::findNextArgWithDefault()
-{
- return _findNextArgWithDefault(this);
-}
-
-bool OverloadData::isFinalOccurrence(const AbstractMetaFunction *func) const
-{
- for (const OverloadData *pd : m_nextOverloadData) {
- if (pd->overloads().contains(func))
- return false;
- }
- return true;
-}
-
-OverloadData::MetaFunctionList OverloadData::overloadsWithoutRepetition() const
-{
- MetaFunctionList overloads = m_overloads;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->minimalSignature().endsWith(QLatin1String("const")))
- continue;
- for (const AbstractMetaFunction *f : qAsConst(overloads)) {
- if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) {
- overloads.removeOne(f);
- break;
- }
- }
- }
- return overloads;
-}
-
-const AbstractMetaFunction *OverloadData::getFunctionWithDefaultValue() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- int removedArgs = 0;
- for (int i = 0; i <= m_argPos + removedArgs; i++) {
- if (func->argumentRemoved(i + 1))
- removedArgs++;
- }
- if (func->arguments().at(m_argPos + removedArgs)->hasDefaultValueExpression())
- return func;
- }
- return nullptr;
-}
-
-QVector<int> OverloadData::invalidArgumentLengths() const
-{
- QSet<int> validArgLengths;
-
- for (const AbstractMetaFunction *func : qAsConst(m_headOverloadData->m_overloads)) {
- const AbstractMetaArgumentList args = func->arguments();
- int offset = 0;
- for (int i = 0; i < args.size(); ++i) {
- if (func->argumentRemoved(i+1)) {
- offset++;
- } else {
- if (args.at(i)->hasDefaultValueExpression())
- validArgLengths << i-offset;
- }
- }
- validArgLengths << args.size() - offset;
- }
-
- QVector<int> invalidArgLengths;
- for (int i = minArgs() + 1; i < maxArgs(); i++) {
- if (!validArgLengths.contains(i))
- invalidArgLengths.append(i);
- }
-
- return invalidArgLengths;
-}
-
-int OverloadData::numberOfRemovedArguments(const AbstractMetaFunction *func, int finalArgPos)
-{
- 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;
-}
-
-QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList &overloads)
-{
- int minArgs = 10000;
- int maxArgs = 0;
- for (const AbstractMetaFunction *func : overloads) {
- int origNumArgs = func->arguments().size();
- int removed = numberOfRemovedArguments(func);
- int numArgs = origNumArgs - removed;
- if (maxArgs < numArgs)
- maxArgs = numArgs;
- if (minArgs > numArgs)
- minArgs = numArgs;
- for (int j = 0; j < origNumArgs; j++) {
- if (func->argumentRemoved(j + 1))
- continue;
- int fixedArgIndex = j - removed;
- if (fixedArgIndex < minArgs && func->arguments().at(j)->hasDefaultValueExpression())
- minArgs = fixedArgIndex;
- }
- }
- return {minArgs, maxArgs};
-}
-
-bool OverloadData::isSingleArgument(const AbstractMetaFunctionList &overloads)
-{
- bool singleArgument = true;
- for (const AbstractMetaFunction *func : overloads) {
- if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
- singleArgument = false;
- break;
- }
- }
- return singleArgument;
-}
-
-void OverloadData::dumpGraph(const QString &filename) const
-{
- QFile file(filename);
- if (file.open(QFile::WriteOnly)) {
- QTextStream s(&file);
- s << m_headOverloadData->dumpGraph();
- }
-}
-
-static inline QString toHtml(QString s)
-{
- s.replace(QLatin1Char('<'), QLatin1String("&lt;"));
- s.replace(QLatin1Char('>'), QLatin1String("&gt;"));
- s.replace(QLatin1Char('&'), QLatin1String("&amp;"));
- return s;
-}
-
-QString OverloadData::dumpGraph() const
-{
- Indentor INDENT;
- Indentation indent(INDENT);
- QString result;
- QTextStream s(&result);
- if (m_argPos == -1) {
- const AbstractMetaFunction *rfunc = referenceFunction();
- s << "digraph OverloadedFunction {\n";
- s << INDENT << "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 AbstractMetaFunction *func : m_overloads) {
- s << "f" << functionNumber(func) << " : ";
- if (func->type())
- s << toHtml(func->type()->cppSignature());
- else
- s << "void";
- s << ' ' << toHtml(func->minimalSignature()) << "\\l";
- }
- s << "\"];\n";
-
- // Function box title
- s << INDENT << '"' << 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\">&lt;&lt;";
- if (rfunc->isAbstract())
- s << "pure ";
- s << "virtual&gt;&gt;</font>";
- }
- s << "</td></tr>";
-
- // Function return type
- s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
- if (rfunc->type())
- s << toHtml(rfunc->type()->cppSignature());
- else
- s << "void";
- s << "</td></tr>";
-
- // Shows type changes for all function signatures
- for (const AbstractMetaFunction *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>";
-
- 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 AbstractMetaFunction *func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</td></tr>";
-
- s << "</table>> ];\n";
-
- for (const OverloadData *pd : m_nextOverloadData)
- s << INDENT << '"' << rfunc->name() << "\" -> " << pd->dumpGraph();
-
- s << "}\n";
- } else {
- QString argId = QLatin1String("arg_") + QString::number(quintptr(this));
- s << argId << ";\n";
-
- s << INDENT << '"' << 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 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>";
-
- // 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>";
- }
-
- // Overloads for the signature to present point
- s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
- for (const AbstractMetaFunction *func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</td></tr>";
-
- // Show default values (original and modified) for various functions
- for (const AbstractMetaFunction *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>";
- }
- }
-
- s << "</table>>];\n";
-
- for (const OverloadData *pd : m_nextOverloadData)
- s << INDENT << argId << " -> " << pd->dumpGraph();
- }
- return result;
-}
-
-int OverloadData::functionNumber(const AbstractMetaFunction *func) const
-{
- return m_headOverloadData->m_overloads.indexOf(func);
-}
-
-OverloadData::~OverloadData()
-{
- while (!m_nextOverloadData.isEmpty())
- delete m_nextOverloadData.takeLast();
-}
-
-bool OverloadData::hasArgumentTypeReplace() const
-{
- return !m_argTypeReplaced.isEmpty();
-}
-
-QString OverloadData::argumentTypeReplaced() const
-{
- return m_argTypeReplaced;
-}
-
-bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionList &overloads)
-{
- if (OverloadData::getMinMaxArguments(overloads).second == 0)
- return false;
- for (const AbstractMetaFunction *func : overloads) {
- if (hasArgumentWithDefaultValue(func))
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasArgumentWithDefaultValue() const
-{
- if (maxArgs() == 0)
- return false;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (hasArgumentWithDefaultValue(func))
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction *func)
-{
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- if (arg->hasDefaultValueExpression())
- return true;
- }
- return false;
-}
-
-AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction *func)
-{
- AbstractMetaArgumentList args;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (AbstractMetaArgument *arg : arguments) {
- if (!arg->hasDefaultValueExpression()
- || func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- args << arg;
- }
- return args;
-}
-
-#ifndef QT_NO_DEBUG_STREAM
-void OverloadData::formatDebug(QDebug &d) const
-{
- const int count = m_overloads.size();
- d << "argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs
- << ", argPos=" << m_argPos << ", argTypeReplaced=\"" << m_argTypeReplaced
- << "\", 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);
- }
- d << ')';
- d.setVerbosity(oldVerbosity);
-}
-
-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 << ')';
- return d;
-}
-#endif // !QT_NO_DEBUG_STREAM