diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/abstractmetafunction.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetafunction.cpp | 593 |
1 files changed, 418 insertions, 175 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp index 8aae6c19b..11a02f154 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp @@ -1,54 +1,42 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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) 2020 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 "abstractmetaargument.h" #include "abstractmetabuilder.h" #include "abstractmetalang.h" #include "abstractmetalang_helpers.h" #include "abstractmetatype.h" +#include "addedfunction.h" #include <codemodel.h> #include "documentation.h" +#include "exception.h" #include "messages.h" +#include "codesnip.h" #include "modifications.h" -#include "propertyspec.h" #include "reporthandler.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "complextypeentry.h" +#include "containertypeentry.h" +#include "functiontypeentry.h" +#include "primitivetypeentry.h" +#include "typesystemtypeentry.h" + +#include "qtcompat.h" #include <QtCore/QDebug> #include <QtCore/QRegularExpression> +#include <algorithm> + +using namespace Qt::StringLiterals; + // Cache FunctionModificationList in a flat list per class (0 for global // functions, or typically owner/implementing/declaring class. struct ModificationCacheEntry { - const AbstractMetaClass *klass; + AbstractMetaClassCPtr klass; FunctionModificationList modifications; }; @@ -60,7 +48,6 @@ public: AbstractMetaFunctionPrivate() : m_constant(false), m_reverse(false), - m_explicit(false), m_pointerOperator(false), m_isCallOperator(false) { @@ -73,7 +60,10 @@ public: int overloadNumber(const AbstractMetaFunction *q) const; const FunctionModificationList &modifications(const AbstractMetaFunction *q, - const AbstractMetaClass *implementor) const; + const AbstractMetaClassCPtr &implementor) const; + + bool applyTypeModification(const AbstractMetaFunction *q, + const QString &type, int number, QString *errorMessage); QString m_name; QString m_originalName; @@ -81,22 +71,25 @@ public: mutable QString m_cachedMinimalSignature; mutable QString m_cachedSignature; mutable QString m_cachedModifiedName; + QString m_unresolvedSignature; - FunctionTypeEntry* m_typeEntry = nullptr; + FunctionTypeEntryPtr m_typeEntry; AbstractMetaFunction::FunctionType m_functionType = AbstractMetaFunction::NormalFunction; AbstractMetaType m_type; - const AbstractMetaClass *m_class = nullptr; - const AbstractMetaClass *m_implementingClass = nullptr; - const AbstractMetaClass *m_declaringClass = nullptr; + QString m_modifiedTypeName; + AbstractMetaClassCPtr m_class; + AbstractMetaClassCPtr m_implementingClass; + AbstractMetaClassCPtr m_declaringClass; mutable ModificationCache m_modificationCache; int m_propertySpecIndex = -1; AbstractMetaArgumentList m_arguments; AddedFunctionPtr m_addedFunction; SourceLocation m_sourceLocation; AbstractMetaFunction::Attributes m_attributes; + FunctionAttributes m_cppAttributes; + AbstractMetaFunction::Flags m_flags; uint m_constant : 1; uint m_reverse : 1; - uint m_explicit : 1; uint m_pointerOperator : 1; uint m_isCallOperator : 1; mutable int m_cachedOverloadNumber = TypeSystem::OverloadNumberUnset; @@ -107,13 +100,17 @@ public: TypeSystem::ExceptionHandling m_exceptionHandlingModification = TypeSystem::ExceptionHandling::Unspecified; }; -AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : +AbstractMetaFunction::AbstractMetaFunction(const QString &name) : AbstractMetaFunction() { + d->m_originalName = d->m_name = name; +} + +AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : + AbstractMetaFunction(addedFunc->name()) +{ d->m_addedFunction = addedFunc; setConstant(addedFunc->isConstant()); - setName(addedFunc->name()); - setOriginalName(addedFunc->name()); switch (addedFunc->access()) { case AddedFunction::Protected: setAccess(Access::Protected); @@ -122,9 +119,9 @@ AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : setAccess(Access::Public); break; } - AbstractMetaFunction::Attributes atts = AbstractMetaFunction::FinalInTargetLang; + AbstractMetaFunction::Attributes atts; if (addedFunc->isStatic()) - atts |= AbstractMetaFunction::Static; + setCppAttribute(FunctionAttribute::Static); if (addedFunc->isClassMethod()) atts |= AbstractMetaFunction::ClassMethod; setAttributes(atts); @@ -217,23 +214,19 @@ void AbstractMetaFunction::setPointerOperator(bool value) bool AbstractMetaFunction::isExplicit() const { - return d->m_explicit; + return d->m_cppAttributes.testFlag(FunctionAttribute::Explicit); } void AbstractMetaFunction::setExplicit(bool isExplicit) { - d->m_explicit = isExplicit; + d->m_cppAttributes.setFlag(FunctionAttribute::Explicit, isExplicit); } bool AbstractMetaFunction::returnsBool() const { if (d->m_type.typeUsagePattern() != AbstractMetaType::PrimitivePattern) return false; - auto *pte = static_cast<const PrimitiveTypeEntry *>(d->m_type.typeEntry()); - // Walk along typedefs - while (auto *referencedPte = pte->referencedTypeEntry()) - pte =referencedPte; - return pte->name() == u"bool"; + return basicReferencedTypeEntry(d->m_type.typeEntry())->name() == u"bool"; } bool AbstractMetaFunction::isOperatorBool() const @@ -268,12 +261,37 @@ void AbstractMetaFunction::operator-=(AbstractMetaFunction::Attribute attribute) d->m_attributes.setFlag(attribute, false); } +FunctionAttributes AbstractMetaFunction::cppAttributes() const +{ + return d->m_cppAttributes; +} + +void AbstractMetaFunction::setCppAttributes(FunctionAttributes a) +{ + d->m_cppAttributes = a; +} + +void AbstractMetaFunction::setCppAttribute(FunctionAttribute a, bool on) +{ + d->m_cppAttributes.setFlag(a, on); +} + +AbstractMetaFunction::Flags AbstractMetaFunction::flags() const +{ + return d->m_flags; +} + +void AbstractMetaFunction::setFlags(Flags f) +{ + d->m_flags = f; +} + /******************************************************************************* * Indicates that this function has a modification that removes it */ -bool AbstractMetaFunction::isModifiedRemoved(const AbstractMetaClass *cls) const +bool AbstractMetaFunction::isModifiedRemoved(AbstractMetaClassCPtr cls) const { - if (!isInGlobalScope() && cls == nullptr) + if (!isInGlobalScope() && !cls) cls = d->m_implementingClass; for (const auto &mod : modifications(cls)) { if (mod.isRemoved()) @@ -283,6 +301,17 @@ bool AbstractMetaFunction::isModifiedRemoved(const AbstractMetaClass *cls) const return false; } +bool AbstractMetaFunction::isModifiedFinal(AbstractMetaClassCPtr cls) const +{ + if (!isInGlobalScope() && cls == nullptr) + cls = d->m_implementingClass; + for (const auto &mod : modifications(cls)) { + if (mod.modifiers().testFlag(FunctionModification::Final)) + return true; + } + return false; +} + bool AbstractMetaFunction::isVoid() const { return d->m_type.isVoid(); @@ -298,12 +327,12 @@ void AbstractMetaFunction::setType(const AbstractMetaType &type) d->m_type = type; } -const AbstractMetaClass *AbstractMetaFunction::ownerClass() const +AbstractMetaClassCPtr AbstractMetaFunction::ownerClass() const { return d->m_class; } -void AbstractMetaFunction::setOwnerClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setOwnerClass(const AbstractMetaClassCPtr &cls) { d->m_class = cls; } @@ -327,7 +356,7 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra result |= EqualImplementor; // Attributes - if (attributes() == other->attributes()) + if (attributes() == other->attributes() && cppAttributes() == other->cppAttributes()) result |= EqualAttributes; // Compare types @@ -358,10 +387,10 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra maxArguments = arguments(); } - int minCount = minArguments.size(); - int maxCount = maxArguments.size(); + const auto minCount = minArguments.size(); + const auto maxCount = maxArguments.size(); bool same = true; - for (int i = 0; i < maxCount; ++i) { + for (qsizetype i = 0; i < maxCount; ++i) { if (i < minCount) { const AbstractMetaArgument &min_arg = minArguments.at(i); const AbstractMetaArgument &max_arg = maxArguments.at(i); @@ -412,6 +441,11 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const { auto *cpy = new AbstractMetaFunction; cpy->setAttributes(attributes()); + auto ca = cppAttributes(); + // Historical bug: explicit was not copied! (causing nontypetemplate_test.py fail) + ca.setFlag(FunctionAttribute::Explicit, false); + cpy->setCppAttributes(ca); + cpy->setFlags(flags()); cpy->setAccess(access()); cpy->setName(name()); cpy->setOriginalName(originalName()); @@ -424,6 +458,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const cpy->setExceptionSpecification(d->m_exceptionSpecification); cpy->setAllowThreadModification(d->m_allowThreadModification); cpy->setExceptionHandlingModification(d->m_exceptionHandlingModification); + cpy->d->m_modifiedTypeName = d->m_modifiedTypeName; cpy->d->m_addedFunction = d->m_addedFunction; cpy->d->m_arguments = d->m_arguments; @@ -447,35 +482,50 @@ bool AbstractMetaFunction::generateBinding() const { switch (d->m_functionType) { case ConversionOperator: + if (d->m_name != u"operator int" && d->m_name != u"operator double") + return false; + break; case AssignmentOperatorFunction: case MoveAssignmentOperatorFunction: + case AbstractMetaFunction::MoveConstructorFunction: return false; default: + if (!isWhiteListed()) + return false; break; } + // Can we access the wrapper in case of a protected method? If not, + // disable for consistency regardless of avoidProtectedHack. + if (isProtected()) { + const auto typeFlags = ownerClass()->typeEntry()->typeFlags(); + if (typeFlags.testFlag(ComplexTypeEntry::DisableWrapper)) + return false; + } if (isPrivate() && d->m_functionType != EmptyFunction) return false; - return d->m_name != u"qt_metacall" && !usesRValueReferences() - && !isModifiedRemoved(); + // RValue references only for user-specified + // functions (<add-function>/<declare-function>/<function>) + return d->m_name != u"qt_metacall" && + (!usesRValueReferences() || d->m_addedFunction || d->m_typeEntry) + && !isModifiedRemoved(); } -QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const +bool AbstractMetaFunction::isWhiteListed() const { - AbstractMetaArgumentList arguments = this->arguments(); - if (arguments.size() == resolvedArguments.size()) { - QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')'); - return QStringList(TypeDatabase::normalizedSignature(signature)); - } - QStringList returned; - - const AbstractMetaArgument &argument = arguments.at(resolvedArguments.size()); - QStringList minimalTypeSignature = argument.type().minimalSignature().split(QLatin1String("::")); - for (int i = 0; i < minimalTypeSignature.size(); ++i) { - returned += introspectionCompatibleSignatures(QStringList(resolvedArguments) - << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::"))); + switch (d->m_functionType) { + case NormalFunction: + case SignalFunction: + case SlotFunction: + if (auto dc = declaringClass()) { + const QSet<QString> &whiteList = dc->typeEntry()->generateFunctions(); + return whiteList.isEmpty() || whiteList.contains(d->m_name) + || whiteList.contains(minimalSignature()); + } + break; + default: + break; } - - return returned; + return true; } QString AbstractMetaFunctionPrivate::signature() const @@ -483,22 +533,22 @@ QString AbstractMetaFunctionPrivate::signature() const if (m_cachedSignature.isEmpty()) { m_cachedSignature = m_originalName; - m_cachedSignature += QLatin1Char('('); + m_cachedSignature += u'('; - for (int i = 0; i < m_arguments.count(); ++i) { + for (qsizetype i = 0; i < m_arguments.size(); ++i) { const AbstractMetaArgument &a = m_arguments.at(i); const AbstractMetaType &t = a.type(); if (i > 0) - m_cachedSignature += QLatin1String(", "); + m_cachedSignature += u", "_s; m_cachedSignature += t.cppSignature(); // We need to have the argument names in the qdoc files - m_cachedSignature += QLatin1Char(' '); + m_cachedSignature += u' '; m_cachedSignature += a.name(); } - m_cachedSignature += QLatin1Char(')'); + m_cachedSignature += u')'; if (m_constant) - m_cachedSignature += QLatin1String(" const"); + m_cachedSignature += u" const"_s; } return m_cachedSignature; } @@ -508,6 +558,25 @@ QString AbstractMetaFunction::signature() const return d->signature(); } +QString AbstractMetaFunction::classQualifiedSignature() const +{ + QString result; + if (d->m_implementingClass) + result += d->m_implementingClass->qualifiedCppName() + u"::"_s; + result += signature(); + return result; +} + +QString AbstractMetaFunction::unresolvedSignature() const +{ + return d->m_unresolvedSignature; +} + +void AbstractMetaFunction::setUnresolvedSignature(const QString &s) +{ + d->m_unresolvedSignature = s; +} + bool AbstractMetaFunction::isConstant() const { return d->m_constant; @@ -520,31 +589,47 @@ void AbstractMetaFunction::setConstant(bool constant) bool AbstractMetaFunction::isUserAdded() const { - return !d->m_addedFunction.isNull() && !d->m_addedFunction->isDeclaration(); + return d->m_addedFunction && !d->m_addedFunction->isDeclaration(); +} + +bool AbstractMetaFunction::isUserAddedPythonOverride() const +{ + return d->m_addedFunction && d->m_addedFunction->isPythonOverride(); } bool AbstractMetaFunction::isUserDeclared() const { - return !d->m_addedFunction.isNull() && d->m_addedFunction->isDeclaration(); + return d->m_addedFunction && d->m_addedFunction->isDeclaration(); } int AbstractMetaFunction::actualMinimumArgumentCount() const { - AbstractMetaArgumentList arguments = this->arguments(); - int count = 0; - for (int i = 0; i < arguments.size(); ++i && ++count) { - if (argumentRemoved(i + 1)) + for (qsizetype i = 0, size = d->m_arguments.size(); i < size; ++i && ++count) { + const auto &arg = d->m_arguments.at(i); + if (arg.isModifiedRemoved()) --count; - else if (!arguments.at(i).defaultValueExpression().isEmpty()) + else if (!arg.defaultValueExpression().isEmpty()) break; } return count; } +int AbstractMetaFunction::actualArgumentIndex(int index) const +{ + if (index < 0 || index >= int(d->m_arguments.size())) + throw Exception(msgArgumentIndexOutOfRange(this, index)); + int result = 0; + for (int i = 0; i < index; ++i) { + if (!d->m_arguments.at(i).isModifiedRemoved()) + ++result; + } + return result; +} + // Returns reference counts for argument at idx, or all arguments if idx == -2 -QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const +QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClassCPtr &cls, int idx) const { QList<ReferenceCount> returned; @@ -559,7 +644,7 @@ QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaCl return returned; } -ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const +ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClassCPtr &cls, int idx) const { for (const auto &mod : modifications(cls)) { for (const ArgumentModification &argumentMod : mod.argument_mods()) { @@ -588,6 +673,11 @@ QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int return QString(); } +bool AbstractMetaFunction::hasConversionRule(TypeSystem::Language language, int idx) const +{ + return !conversionRule(language, idx).isEmpty(); +} + // FIXME If we remove a arg. in the method at the base class, it will not reflect here. bool AbstractMetaFunction::argumentRemoved(int key) const { @@ -603,28 +693,28 @@ bool AbstractMetaFunction::argumentRemoved(int key) const return false; } -const AbstractMetaClass *AbstractMetaFunction::targetLangOwner() const +AbstractMetaClassCPtr AbstractMetaFunction::targetLangOwner() const { return d->m_class && d->m_class->isInvisibleNamespace() ? d->m_class->targetLangEnclosingClass() : d->m_class; } -const AbstractMetaClass *AbstractMetaFunction::declaringClass() const +AbstractMetaClassCPtr AbstractMetaFunction::declaringClass() const { return d->m_declaringClass; } -void AbstractMetaFunction::setDeclaringClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setDeclaringClass(const AbstractMetaClassCPtr &cls) { d->m_declaringClass = cls; } -const AbstractMetaClass *AbstractMetaFunction::implementingClass() const +AbstractMetaClassCPtr AbstractMetaFunction::implementingClass() const { return d->m_implementingClass; } -void AbstractMetaFunction::setImplementingClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setImplementingClass(const AbstractMetaClassCPtr &cls) { d->m_implementingClass = cls; } @@ -649,13 +739,23 @@ void AbstractMetaFunction::addArgument(const AbstractMetaArgument &argument) d->m_arguments << argument; } +static bool modifiedDeprecated(const FunctionModification &mod) +{ + return mod.modifiers().testFlag(FunctionModification::Deprecated); +} + +static bool modifiedUndeprecated(const FunctionModification &mod) +{ + return mod.modifiers().testFlag(FunctionModification::Undeprecated); +} + bool AbstractMetaFunction::isDeprecated() const { - for (const auto &modification : modifications(declaringClass())) { - if (modification.isDeprecated()) - return true; - } - return false; + const auto &mods = modifications(declaringClass()); + + return d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated) + ? std::none_of(mods.cbegin(), mods.cend(), modifiedUndeprecated) + : std::any_of(mods.cbegin(), mods.cend(), modifiedDeprecated); } bool AbstractMetaFunction::isConstructor() const @@ -700,6 +800,24 @@ void AbstractMetaFunction::setFunctionType(AbstractMetaFunction::FunctionType ty d->m_functionType = type; } +std::optional<AbstractMetaFunction::ComparisonOperatorType> +AbstractMetaFunction::comparisonOperatorType() const +{ + if (d->m_functionType != ComparisonOperator) + return {}; + static const QHash<QString, ComparisonOperatorType> mapping = { + {u"operator=="_s, OperatorEqual}, + {u"operator!="_s, OperatorNotEqual}, + {u"operator<"_s, OperatorLess}, + {u"operator<="_s, OperatorLessEqual}, + {u"operator>"_s, OperatorGreater}, + {u"operator>="_s, OperatorGreaterEqual} + }; + const auto it = mapping.constFind(originalName()); + Q_ASSERT(it != mapping.constEnd()); + return it.value(); +} + // Auto-detect whether a function should be wrapped into // Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, that is, temporarily release // the GIL (global interpreter lock). Doing so is required for any thread-wait @@ -709,8 +827,13 @@ void AbstractMetaFunction::setFunctionType(AbstractMetaFunction::FunctionType ty bool AbstractMetaFunction::autoDetectAllowThread() const { // Disallow for simple getter functions. - const bool maybeGetter = d->m_constant != 0 && !isVoid() && d->m_arguments.isEmpty(); - return !maybeGetter; + return !maybeAccessor(); +} + +bool AbstractMetaFunction::maybeAccessor() const +{ + return d->m_functionType == NormalFunction && d->m_class != nullptr + && d->m_constant != 0 && !isVoid() && d->m_arguments.isEmpty(); } SourceLocation AbstractMetaFunction::sourceLocation() const @@ -723,12 +846,12 @@ void AbstractMetaFunction::setSourceLocation(const SourceLocation &sourceLocatio d->m_sourceLocation = sourceLocation; } -static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClass *klass) +static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClassCPtr &klass) { return klass->typeEntry()->allowThread(); } -static inline bool hasAllowThreadMod(const AbstractMetaClass *klass) +static inline bool hasAllowThreadMod(const AbstractMetaClassCPtr &klass) { return allowThreadMod(klass) != TypeSystem::AllowThread::Unspecified; } @@ -761,7 +884,7 @@ bool AbstractMetaFunction::allowThread() const return result; } -TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const AbstractMetaClass *cls, int idx) const +TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const AbstractMetaClassCPtr &cls, int idx) const { for (const auto &modification : modifications(cls)) { for (const ArgumentModification &argumentModification : modification.argument_mods()) { @@ -773,18 +896,22 @@ TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const Abstra return TypeSystem::UnspecifiedOwnership; } -QString AbstractMetaFunction::typeReplaced(int key) const +const QString &AbstractMetaFunction::modifiedTypeName() const { - for (const auto &modification : modifications(declaringClass())) { - for (const ArgumentModification &argumentModification : modification.argument_mods()) { - if (argumentModification.index() == key - && !argumentModification.modifiedType().isEmpty()) { - return argumentModification.modifiedType(); - } - } - } + return d->m_modifiedTypeName; +} - return QString(); +bool AbstractMetaFunction::generateOpaqueContainerReturn() const +{ + if (!isTypeModified() || d->m_type.typeUsagePattern() != AbstractMetaType::ContainerPattern) + return false; + // Needs to be a reference to a container, allow by value only for spans + if (d->m_type.referenceType() != LValueReference) { + auto cte = std::static_pointer_cast<const ContainerTypeEntry>(d->m_type.typeEntry()); + if (cte->containerKind() != ContainerTypeEntry::SpanContainer) + return false; + } + return d->m_type.generateOpaqueContainerForGetter(d->m_modifiedTypeName); } bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const @@ -798,6 +925,56 @@ bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const return false; } +// Note: The declaring class must be correctly set for this to work. +bool AbstractMetaFunctionPrivate::applyTypeModification(const AbstractMetaFunction *q, + const QString &type, + int number, QString *errorMessage) +{ + if (number < 0 || number > m_arguments.size()) { + *errorMessage = + msgTypeModificationFailed(type, number, q, + msgArgumentOutOfRange(number, 0, m_arguments.size())); + return false; + } + + // Modified return types may have unparseable types like Python tuples + if (number == 0) { + m_modifiedTypeName = type; + return true; + } + + auto typeOpt = AbstractMetaType::fromString(type, errorMessage); + if (!typeOpt.has_value()) { + *errorMessage = msgTypeModificationFailed(type, number, q, *errorMessage); + return false; + } + m_arguments[number - 1].setModifiedType(typeOpt.value()); + return true; +} + +void AbstractMetaFunction::applyTypeModifications() +{ + QString errorMessage; + for (const auto &modification : modifications(declaringClass())) { + for (const ArgumentModification &am : modification.argument_mods()) { + const int n = am.index(); + if (am.isTypeModified() + && !d->applyTypeModification(this, am.modifiedType(), + n, &errorMessage)) { + throw Exception(errorMessage); + } else if (am.isRemoved() && n != 0) { + if (n < 1 || n > d->m_arguments.size()) { + errorMessage = + msgArgumentRemovalFailed(this, n, + msgArgumentOutOfRange(n, 1, d->m_arguments.size())); + throw Exception(errorMessage); + } + d->m_arguments[n - 1].setModifiedRemoved(true); + } + } + } +} + QString AbstractMetaFunction::pyiTypeReplaced(int argumentIndex) const { for (const auto &modification : modifications(declaringClass())) { @@ -820,28 +997,26 @@ QString AbstractMetaFunction::pyiTypeReplaced(int argumentIndex) const QString AbstractMetaFunctionPrivate::formatMinimalSignature(const AbstractMetaFunction *q, bool comment) const { - QString result = m_originalName + QLatin1Char('('); - for (int i = 0; i < m_arguments.count(); ++i) { + QString result = m_originalName + u'('; + for (qsizetype i = 0; i < m_arguments.size(); ++i) { + const auto &argument = m_arguments.at(i); if (i > 0) - result += QLatin1Char(','); - - QString typeName; - if (comment) - typeName = q->typeReplaced(i + 1); - if (typeName.isEmpty()) - typeName = m_arguments.at(i).type().minimalSignature(); - result += typeName; + result += u','; + + const auto &type = comment ? argument.modifiedType() : argument.type(); + result += type.minimalSignature(); + if (comment && argument.hasDefaultValueExpression()) + result += u'='; } - result += QLatin1Char(')'); + result += u')'; if (m_constant) - result += QLatin1String("const"); + result += u"const"_s; result = TypeDatabase::normalizedSignature(result); if (comment && !q->isVoid()) { - QString typeName = q->typeReplaced(0); - if (typeName.isEmpty()) - typeName = q->type().minimalSignature(); - result += QStringLiteral("->") + typeName; + result += u"->"_s; + result += q->isTypeModified() + ? q->modifiedTypeName() : q->type().minimalSignature(); } return result; } @@ -853,6 +1028,14 @@ QString AbstractMetaFunction::minimalSignature() const return d->m_cachedMinimalSignature; } +QStringList AbstractMetaFunction::modificationSignatures() const +{ + QStringList result{minimalSignature()}; + if (d->m_unresolvedSignature != result.constFirst()) + result.append(d->m_unresolvedSignature); + return result; +} + QString AbstractMetaFunction::signatureComment() const { return d->formatMinimalSignature(this, true); @@ -861,25 +1044,28 @@ QString AbstractMetaFunction::signatureComment() const QString AbstractMetaFunction::debugSignature() const { QString result; - const bool isOverride = attributes() & AbstractMetaFunction::OverriddenCppMethod; - const bool isFinal = attributes() & AbstractMetaFunction::FinalCppMethod; - if (!isOverride && !isFinal && (attributes() & AbstractMetaFunction::VirtualCppMethod)) - result += QLatin1String("virtual "); + const auto attributes = cppAttributes(); + const bool isOverride = attributes.testFlag(FunctionAttribute::Override); + const bool isFinal = attributes.testFlag(FunctionAttribute::Final); + if (!isOverride && !isFinal && (attributes.testFlag(FunctionAttribute::Virtual))) + result += u"virtual "_s; + if (d->m_implementingClass) + result += d->m_implementingClass->qualifiedCppName() + u"::"_s; result += minimalSignature(); if (isOverride) - result += QLatin1String(" override"); + result += u" override"_s; if (isFinal) - result += QLatin1String(" final"); + result += u" final"_s; return result; } FunctionModificationList AbstractMetaFunction::findClassModifications(const AbstractMetaFunction *f, - const AbstractMetaClass *implementor) + AbstractMetaClassCPtr implementor) { - const QString signature = f->minimalSignature(); + const auto signatures = f->modificationSignatures(); FunctionModificationList mods; while (implementor) { - mods += implementor->typeEntry()->functionModifications(signature); + mods += implementor->typeEntry()->functionModifications(signatures); if ((implementor == implementor->baseClass()) || (implementor == f->implementingClass() && !mods.isEmpty())) { break; @@ -891,15 +1077,16 @@ FunctionModificationList AbstractMetaFunction::findClassModifications(const Abst FunctionModificationList AbstractMetaFunction::findGlobalModifications(const AbstractMetaFunction *f) { - return TypeDatabase::instance()->functionModifications(f->minimalSignature()); + auto *td = TypeDatabase::instance(); + return td->globalFunctionModifications(f->modificationSignatures()); } const FunctionModificationList & AbstractMetaFunctionPrivate::modifications(const AbstractMetaFunction *q, - const AbstractMetaClass *implementor) const + const AbstractMetaClassCPtr &implementor) const { - if (!m_addedFunction.isNull()) - return m_addedFunction->modifications; + if (m_addedFunction) + return m_addedFunction->modifications(); for (const auto &ce : m_modificationCache) { if (ce.klass == implementor) return ce.modifications; @@ -913,9 +1100,9 @@ const FunctionModificationList & } const FunctionModificationList & - AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const + AbstractMetaFunction::modifications(AbstractMetaClassCPtr implementor) const { - if (implementor == nullptr) + if (!implementor) implementor = d->m_class; return d->modifications(this, implementor); } @@ -925,9 +1112,15 @@ void AbstractMetaFunction::clearModificationsCache() d->m_modificationCache.clear(); } +const DocModificationList AbstractMetaFunction::addedFunctionDocModifications() const +{ + return d->m_addedFunction + ? d->m_addedFunction->docModifications() : DocModificationList{}; +} + QString AbstractMetaFunction::argumentName(int index, bool /* create */, - const AbstractMetaClass * /* implementor */) const + AbstractMetaClassCPtr /* implementor */) const { return d->m_arguments[--index].name(); } @@ -942,19 +1135,30 @@ void AbstractMetaFunction::setPropertySpecIndex(int i) d->m_propertySpecIndex = i; } -FunctionTypeEntry *AbstractMetaFunction::typeEntry() const +FunctionTypeEntryPtr AbstractMetaFunction::typeEntry() const { return d->m_typeEntry; } -void AbstractMetaFunction::setTypeEntry(FunctionTypeEntry *typeEntry) +void AbstractMetaFunction::setTypeEntry(const FunctionTypeEntryPtr &typeEntry) { d->m_typeEntry = typeEntry; } +QString AbstractMetaFunction::targetLangPackage() const +{ + if (d->m_addedFunction != nullptr) + return d->m_addedFunction->targetLangPackage(); + if (d->m_class != nullptr) + return d->m_class->typeEntry()->targetLangPackage(); + if (d->m_typeEntry != nullptr) + return d->m_typeEntry->targetLangPackage(); + return {}; +} + bool AbstractMetaFunction::isCallOperator() const { - return d->m_name == QLatin1String("operator()"); + return d->m_name == u"operator()"; } bool AbstractMetaFunction::hasInjectedCode() const @@ -1035,7 +1239,7 @@ bool AbstractMetaFunction::hasSignatureModifications() const bool AbstractMetaFunction::isConversionOperator(const QString &funcName) { - return funcName.startsWith(QLatin1String("operator ")); + return funcName.startsWith(u"operator "); } ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const @@ -1048,12 +1252,12 @@ void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e) d->m_exceptionSpecification = e; } -static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClass *klass) +static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClassCPtr &klass) { return klass->typeEntry()->exceptionHandling(); } -static inline bool hasExceptionMod(const AbstractMetaClass *klass) +static inline bool hasExceptionMod(const AbstractMetaClassCPtr &klass) { return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified; } @@ -1106,11 +1310,11 @@ bool AbstractMetaFunction::isOperatorOverload(const QString &funcName) if (isConversionOperator(funcName)) return true; - static const QRegularExpression opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" + static const QRegularExpression opRegEx(u"^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~" "|\\[\\]|\\s+delete\\[?\\]?" "|\\(\\)" - "|\\s+new\\[?\\]?)$")); + "|\\s+new\\[?\\]?)$"_s); Q_ASSERT(opRegEx.isValid()); return opRegEx.match(funcName).hasMatch(); } @@ -1137,22 +1341,27 @@ bool AbstractMetaFunction::isComparisonOperator() const return d->m_functionType == ComparisonOperator; } +bool AbstractMetaFunction::isSymmetricalComparisonOperator() const +{ + if (d->m_functionType != ComparisonOperator || d->m_class == nullptr) + return false; + AbstractMetaType classType(d->m_class->typeEntry()); + classType.decideUsagePattern(); + return std::all_of(d->m_arguments.constBegin(), d->m_arguments.constEnd(), + [classType](const AbstractMetaArgument &a) { + return a.type().isEquivalent(classType);}); +} + bool AbstractMetaFunction::isIncDecrementOperator() const { return d->m_functionType == IncrementOperator || d->m_functionType == DecrementOperator; } - bool AbstractMetaFunction::isLogicalOperator() const { return d->m_functionType == LogicalOperator; } -bool AbstractMetaFunction::isSubscriptOperator() const -{ - return d->m_functionType == SubscriptOperator; -} - bool AbstractMetaFunction::isAssignmentOperator() const { return d->m_functionType == AssignmentOperatorFunction @@ -1202,7 +1411,7 @@ bool AbstractMetaFunction::isInplaceOperator() const bool AbstractMetaFunction::isVirtual() const { - return d->m_attributes.testFlag(AbstractMetaFunction::VirtualCppMethod); + return d->m_cppAttributes.testFlag(FunctionAttribute::Virtual); } QString AbstractMetaFunctionPrivate::modifiedName(const AbstractMetaFunction *q) const @@ -1227,7 +1436,7 @@ QString AbstractMetaFunction::modifiedName() const AbstractMetaFunctionCPtr AbstractMetaFunction::find(const AbstractMetaFunctionCList &haystack, - const QString &needle) + QAnyStringView needle) { for (const auto &f : haystack) { if (f->name() == needle) @@ -1265,6 +1474,8 @@ bool AbstractMetaFunction::matches(OperatorQueryOptions query) const break; case AbstractMetaFunction::ComparisonOperator: result = query.testFlag(OperatorQueryOption::ComparisonOp); + if (!result && query.testFlag(OperatorQueryOption::SymmetricalComparisonOp)) + result = isSymmetricalComparisonOperator(); break; default: break; @@ -1323,17 +1534,14 @@ TypeSystem::SnakeCase AbstractMetaFunction::snakeCase() const return mod.snakeCase(); } - if (d->m_typeEntry) { // Global function - const auto snakeCase = d->m_typeEntry->snakeCase(); - return snakeCase != TypeSystem::SnakeCase::Unspecified - ? snakeCase : d->m_typeEntry->typeSystemTypeEntry()->snakeCase(); - } + if (d->m_typeEntry) // Global function + return typeSystemTypeEntry(d->m_typeEntry)->snakeCase(); if (d->m_class) { auto typeEntry = d->m_class->typeEntry(); const auto snakeCase = typeEntry->snakeCase(); return snakeCase != TypeSystem::SnakeCase::Unspecified - ? snakeCase : typeEntry->typeSystemTypeEntry()->snakeCase(); + ? snakeCase : typeSystemTypeEntry(typeEntry)->snakeCase(); } return TypeSystem::SnakeCase::Disabled; } @@ -1347,7 +1555,7 @@ bool AbstractMetaFunction::injectedCodeUsesPySelf() const bool AbstractMetaFunction::injectedCodeCallsPythonOverride() const { static const QRegularExpression - overrideCallRegexCheck(QStringLiteral(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)")); + overrideCallRegexCheck(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)"_L1); Q_ASSERT(overrideCallRegexCheck.isValid()); return injectedCodeContains(overrideCallRegexCheck, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode); @@ -1357,13 +1565,13 @@ bool AbstractMetaFunction::injectedCodeHasReturnValueAttribution(TypeSystem::Lan { if (language == TypeSystem::TargetLangCode) { static const QRegularExpression - retValAttributionRegexCheck_target(QStringLiteral(R"(%PYARG_0\s*=[^=]\s*.+)")); + retValAttributionRegexCheck_target(R"(%PYARG_0\s*=[^=]\s*.+)"_L1); Q_ASSERT(retValAttributionRegexCheck_target.isValid()); return injectedCodeContains(retValAttributionRegexCheck_target, TypeSystem::CodeSnipPositionAny, language); } static const QRegularExpression - retValAttributionRegexCheck_native(QStringLiteral(R"(%0\s*=[^=]\s*.+)")); + retValAttributionRegexCheck_native(R"(%0\s*=[^=]\s*.+)"_L1); Q_ASSERT(retValAttributionRegexCheck_native.isValid()); return injectedCodeContains(retValAttributionRegexCheck_native, TypeSystem::CodeSnipPositionAny, language); } @@ -1387,6 +1595,38 @@ bool AbstractMetaFunction::isVisibilityModifiedToPrivate() const return false; } +struct ComparisonOperator +{ + const char *cppOperator; + const char *pythonOpCode; +}; + +using ComparisonOperatorMapping = + QHash<AbstractMetaFunction::ComparisonOperatorType, ComparisonOperator>; + +static const ComparisonOperatorMapping &comparisonOperatorMapping() +{ + static const ComparisonOperatorMapping result = { + {AbstractMetaFunction::OperatorEqual, {"==", "Py_EQ"}}, + {AbstractMetaFunction::OperatorNotEqual, {"!=", "Py_NE"}}, + {AbstractMetaFunction::OperatorLess, {"<", "Py_LT"}}, + {AbstractMetaFunction::OperatorLessEqual, {"<=", "Py_LE"}}, + {AbstractMetaFunction::OperatorGreater, {">", "Py_GT"}}, + {AbstractMetaFunction::OperatorGreaterEqual, {">=", "Py_GE"}} + }; + return result; +} + +const char * AbstractMetaFunction::pythonRichCompareOpCode(ComparisonOperatorType ct) +{ + return comparisonOperatorMapping().value(ct).pythonOpCode; +} + +const char * AbstractMetaFunction::cppComparisonOperator(ComparisonOperatorType ct) +{ + return comparisonOperatorMapping().value(ct).cppOperator; +} + #ifndef QT_NO_DEBUG_STREAM void AbstractMetaFunction::formatDebugBrief(QDebug &debug) const { @@ -1412,12 +1652,15 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const if (d->m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified) debug << " exeption-mod " << int(d->m_exceptionHandlingModification); debug << '('; - for (int i = 0, count = d->m_arguments.size(); i < count; ++i) { + for (qsizetype i = 0, count = d->m_arguments.size(); i < count; ++i) { if (i) debug << ", "; debug << d->m_arguments.at(i); } - debug << "), signature=\"" << minimalSignature() << '"'; + const QString signature = minimalSignature(); + debug << "), signature=\"" << signature << '"'; + if (signature != d->m_unresolvedSignature) + debug << ", unresolvedSignature=\"" << d->m_unresolvedSignature << '"'; if (d->m_constant) debug << " [const]"; if (d->m_reverse) @@ -1426,9 +1669,9 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const debug << " [userAdded]"; if (isUserDeclared()) debug << " [userDeclared]"; - if (d->m_explicit) + if (d->m_cppAttributes.testFlag(FunctionAttribute::Explicit)) debug << " [explicit]"; - if (attributes().testFlag(AbstractMetaFunction::Deprecated)) + if (d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated)) debug << " [deprecated]"; if (d->m_pointerOperator) debug << " [operator->]"; |