aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/ApiExtractor/abstractmetafunction.cpp')
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetafunction.cpp593
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->]";