diff options
Diffstat (limited to 'src/qml/qml/qqmlpropertycache.cpp')
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 871 |
1 files changed, 359 insertions, 512 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 69957ab282..34b4643c99 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** 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-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qqmlpropertycache_p.h" @@ -46,13 +10,14 @@ #include <private/qmetaobject_p.h> #include <private/qmetaobjectbuilder_p.h> #include <private/qqmlpropertycachemethodarguments_p.h> +#include <private/qqmlsignalnames_p.h> #include <private/qv4value_p.h> #include <QtCore/qdebug.h> #include <QtCore/QCryptographicHash> +#include <QtCore/private/qtools_p.h> -#include <ctype.h> // for toupper #include <limits.h> #include <algorithm> @@ -65,49 +30,6 @@ QT_BEGIN_NAMESPACE #define Q_INT16_MAX 32767 -// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick -// to load -static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) -{ - QQmlPropertyData::Flags flags; - - flags.isConstant = p.isConstant(); - flags.isWritable = p.isWritable(); - flags.isResettable = p.isResettable(); - flags.isFinal = p.isFinal(); - - if (p.isEnumType()) - flags.type = QQmlPropertyData::Flags::EnumType; - - return flags; -} - -// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to -// load -static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags) -{ - Q_ASSERT(propType != -1); - - if (propType == QMetaType::QObjectStar) { - flags.type = QQmlPropertyData::Flags::QObjectDerivedType; - } else if (propType == QMetaType::QVariant) { - flags.type = QQmlPropertyData::Flags::QVariantType; - } else if (propType < static_cast<int>(QVariant::UserType)) { - // nothing to do - } else if (propType == qMetaTypeId<QQmlBinding *>()) { - flags.type = QQmlPropertyData::Flags::QmlBindingType; - } else if (propType == qMetaTypeId<QJSValue>()) { - flags.type = QQmlPropertyData::Flags::QJSValueType; - } else { - QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType); - - if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) - flags.type = QQmlPropertyData::Flags::QObjectDerivedType; - else if (cat == QQmlMetaType::List) - flags.type = QQmlPropertyData::Flags::QListType; - } -} - static int metaObjectSignalCount(const QMetaObject *metaObject) { int signalCount = 0; @@ -119,114 +41,119 @@ static int metaObjectSignalCount(const QMetaObject *metaObject) QQmlPropertyData::Flags QQmlPropertyData::flagsForProperty(const QMetaProperty &p) { - auto flags = fastFlagsForProperty(p); - flagsForPropertyType(p.userType(), flags); - return flags; -} + QQmlPropertyData::Flags flags; -static void populate(QQmlPropertyData *data, const QMetaProperty &p) -{ - Q_ASSERT(p.revision() <= Q_INT16_MAX); - data->setCoreIndex(p.propertyIndex()); - data->setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); - data->setFlags(fastFlagsForProperty(p)); - data->setRevision(p.revision()); -} + flags.setIsConstant(p.isConstant()); + flags.setIsWritable(p.isWritable()); + flags.setIsResettable(p.isResettable()); + flags.setIsFinal(p.isFinal()); + flags.setIsRequired(p.isRequired()); + flags.setIsBindable(p.isBindable()); -void QQmlPropertyData::lazyLoad(const QMetaProperty &p) -{ - populate(this, p); - int type = static_cast<int>(p.type()); - if (type == QMetaType::QObjectStar) { - setPropType(type); - m_flags.type = Flags::QObjectDerivedType; - } else if (type == QMetaType::QVariant) { - setPropType(type); - m_flags.type = Flags::QVariantType; - } else if (type == QVariant::UserType || type == -1) { - m_flags.notFullyResolved = true; - } else { - setPropType(type); + + const QMetaType metaType = p.metaType(); + int propType = metaType.id(); + if (p.isEnumType()) { + flags.setType(QQmlPropertyData::Flags::EnumType); + } else if (metaType.flags() & QMetaType::PointerToQObject) { + flags.setType(QQmlPropertyData::Flags::QObjectDerivedType); + } else if (propType == QMetaType::QVariant) { + flags.setType(QQmlPropertyData::Flags::QVariantType); + } else if (metaType.flags() & QMetaType::IsQmlList) { + flags.setType(QQmlPropertyData::Flags::QListType); } + + return flags; } void QQmlPropertyData::load(const QMetaProperty &p) { - populate(this, p); - setPropType(p.userType()); - flagsForPropertyType(propType(), m_flags); + Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max()); + setCoreIndex(p.propertyIndex()); + setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); + setFlags(flagsForProperty(p)); + setRevision(QTypeRevision::fromEncodedVersion(p.revision())); + QMetaType type = p.metaType(); + setPropType(type); } void QQmlPropertyData::load(const QMetaMethod &m) { setCoreIndex(m.methodIndex()); - setArguments(nullptr); - - setPropType(m.returnType()); - - m_flags.type = Flags::FunctionType; - if (m.methodType() == QMetaMethod::Signal) { - m_flags.isSignal = true; - } else if (m.methodType() == QMetaMethod::Constructor) { - m_flags.isConstructor = true; - setPropType(QMetaType::QObjectStar); + m_flags.setType(Flags::FunctionType); + + // We need to set the constructor, signal, constant, arguments, V4Function, cloned flags. + // These are specific to methods and change with each method. + // The same QQmlPropertyData may be loaded with multiple methods in sequence. + + switch (m.methodType()) { + case QMetaMethod::Signal: + m_flags.setIsSignal(true); + m_flags.setIsConstructor(false); + setPropType(m.returnMetaType()); + break; + case QMetaMethod::Constructor: + m_flags.setIsSignal(false); + m_flags.setIsConstructor(true); + break; + default: + m_flags.setIsSignal(false); + m_flags.setIsConstructor(false); + setPropType(m.returnMetaType()); + break; } + m_flags.setIsConstant(m.isConst()); + const int paramCount = m.parameterCount(); if (paramCount) { - m_flags.hasArguments = true; - if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*")) - m_flags.isV4Function = true; + m_flags.setHasArguments(true); + m_flags.setIsV4Function( + paramCount == 1 && + m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>()); + } else { + m_flags.setHasArguments(false); + m_flags.setIsV4Function(false); } - if (m.attributes() & QMetaMethod::Cloned) - m_flags.isCloned = true; + m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned); - Q_ASSERT(m.revision() <= Q_INT16_MAX); - setRevision(m.revision()); -} - -void QQmlPropertyData::lazyLoad(const QMetaMethod &m) -{ - load(m); - - const char *returnType = m.typeName(); - if (!returnType) - returnType = "\0"; - if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) { - m_flags.notFullyResolved = true; - } + Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max()); + setRevision(QTypeRevision::fromEncodedVersion(m.revision())); } /*! -Creates a new empty QQmlPropertyCache. + Creates a standalone QQmlPropertyCache of \a metaObject. It is separate from the usual + QQmlPropertyCache hierarchy. It's parent is not equal to any other QQmlPropertyCache + created from QObject::staticMetaObject, for example. */ -QQmlPropertyCache::QQmlPropertyCache() - : _parent(nullptr), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(nullptr), argumentsCache(nullptr), _jsFactoryMethodIndex(-1) -{ -} - -/*! -Creates a new QQmlPropertyCache of \a metaObject. -*/ -QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, int metaObjectRevision) - : QQmlPropertyCache() +QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone( + const QMetaObject *metaObject, QTypeRevision metaObjectRevision) { Q_ASSERT(metaObject); - update(metaObject); + Ptr result; + if (const QMetaObject *super = metaObject->superClass()) { + result = createStandalone( + super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision); + } else { + result.adopt(new QQmlPropertyCache(metaObject)); + result->update(metaObject); + } - if (metaObjectRevision > 0) { + if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) { // Set the revision of the meta object that this cache describes to be // 'metaObjectRevision'. This is useful when constructing a property cache // from a type that was created directly in C++, and not through QML. For such // types, the revision for each recorded QMetaObject would normally be zero, which // would exclude any revisioned properties. - for (int metaObjectOffset = 0; metaObjectOffset < allowedRevisionCache.size(); ++metaObjectOffset) - allowedRevisionCache[metaObjectOffset] = metaObjectRevision; + for (int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size(); + ++metaObjectOffset) { + result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision; + } } + + return result; } QQmlPropertyCache::~QQmlPropertyCache() @@ -234,7 +161,6 @@ QQmlPropertyCache::~QQmlPropertyCache() QQmlPropertyCacheMethodArguments *args = argumentsCache; while (args) { QQmlPropertyCacheMethodArguments *next = args->next; - delete args->signalParameterStringForJS; delete args->names; free(args); args = next; @@ -243,44 +169,38 @@ QQmlPropertyCache::~QQmlPropertyCache() // We must clear this prior to releasing the parent incase it is a // linked hash stringCache.clear(); - if (_parent) _parent->release(); - - if (_ownMetaObject) free(const_cast<QMetaObject *>(_metaObject)); - _metaObject = nullptr; - _parent = nullptr; } -QQmlPropertyCache *QQmlPropertyCache::copy(int reserve) +QQmlPropertyCache::Ptr QQmlPropertyCache::copy(const QQmlMetaObjectPointer &mo, int reserve) const { - QQmlPropertyCache *cache = new QQmlPropertyCache(); - cache->_parent = this; - cache->_parent->addref(); - cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; - cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; - cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart; + QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr( + new QQmlPropertyCache(mo), QQmlPropertyCache::Ptr::Adopt); + cache->_parent.reset(this); + cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart; + cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart; + cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart; cache->stringCache.linkAndReserve(stringCache, reserve); cache->allowedRevisionCache = allowedRevisionCache; - cache->_metaObject = _metaObject; cache->_defaultPropertyName = _defaultPropertyName; + cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior; return cache; } -QQmlPropertyCache *QQmlPropertyCache::copy() +QQmlPropertyCache::Ptr QQmlPropertyCache::copy() const { - return copy(0); + return copy(_metaObject, 0); } -QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount, - int signalCount, int enumCount) +QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve( + int propertyCount, int methodCount, int signalCount, int enumCount) const { - QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount); + QQmlPropertyCache::Ptr rv = copy( + QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount); rv->propertyIndexCache.reserve(propertyCount); rv->methodIndexCache.reserve(methodCount); rv->signalHandlerIndexCache.reserve(signalCount); rv->enumCache.reserve(enumCount); - rv->_metaObject = nullptr; - return rv; } @@ -290,89 +210,89 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth This is different from QMetaMethod::methodIndex(). */ void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags, - int coreIndex, int propType, int minorVersion, int notifyIndex) + int coreIndex, QMetaType propType, QTypeRevision version, + int notifyIndex) { QQmlPropertyData data; data.setPropType(propType); data.setCoreIndex(coreIndex); data.setNotifyIndex(notifyIndex); data.setFlags(flags); - data.setTypeMinorVersion(minorVersion); + data.setTypeVersion(version); - QQmlPropertyData *old = findNamedProperty(name); - if (old) - data.markAsOverrideOf(old); + const OverrideResult overrideResult = handleOverride(name, &data); + if (overrideResult == InvalidOverride) + return; - int index = propertyIndexCache.count(); + int index = propertyIndexCache.size(); propertyIndexCache.append(data); - setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != nullptr)); + setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index); } void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags, - int coreIndex, const int *types, + int coreIndex, const QMetaType *types, const QList<QByteArray> &names) { QQmlPropertyData data; - data.setPropType(QVariant::Invalid); + data.setPropType(QMetaType()); data.setCoreIndex(coreIndex); data.setFlags(flags); data.setArguments(nullptr); QQmlPropertyData handler = data; - handler.m_flags.isSignalHandler = true; + handler.m_flags.setIsSignalHandler(true); if (types) { - int argumentCount = *types; + const auto argumentCount = names.size(); QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); - ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); - args->argumentsValid = true; + new (args->types) QMetaType; // Invalid return type + ::memcpy(args->types + 1, types, argumentCount * sizeof(QMetaType)); data.setArguments(args); } - QQmlPropertyData *old = findNamedProperty(name); - if (old) - data.markAsOverrideOf(old); + const OverrideResult overrideResult = handleOverride(name, &data); + if (overrideResult == InvalidOverride) + return; - int methodIndex = methodIndexCache.count(); + int methodIndex = methodIndexCache.size(); methodIndexCache.append(data); - int signalHandlerIndex = signalHandlerIndexCache.count(); + int signalHandlerIndex = signalHandlerIndexCache.size(); signalHandlerIndexCache.append(handler); - QString handlerName = QLatin1String("on") + name; - handlerName[2] = handlerName.at(2).toUpper(); + const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name); - setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr)); - setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != nullptr)); + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex); + setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), + signalHandlerIndexCache.data() + signalHandlerIndex); } void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags, - int coreIndex, int returnType, const QList<QByteArray> &names, - const QVector<int> ¶meterTypes) + int coreIndex, QMetaType returnType, + const QList<QByteArray> &names, + const QVector<QMetaType> ¶meterTypes) { - int argumentCount = names.count(); + int argumentCount = names.size(); QQmlPropertyData data; data.setPropType(returnType); data.setCoreIndex(coreIndex); + data.setFlags(flags); + const OverrideResult overrideResult = handleOverride(name, &data); + if (overrideResult == InvalidOverride) + return; QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); + new (args->types) QMetaType(returnType); for (int ii = 0; ii < argumentCount; ++ii) - args->arguments[ii + 1] = parameterTypes.at(ii); - args->argumentsValid = true; + new (args->types + ii + 1) QMetaType(parameterTypes.at(ii)); data.setArguments(args); - data.setFlags(flags); - - QQmlPropertyData *old = findNamedProperty(name); - if (old) - data.markAsOverrideOf(old); - - int methodIndex = methodIndexCache.count(); + int methodIndex = methodIndexCache.size(); methodIndexCache.append(data); - setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr)); + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex); } void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values) @@ -384,76 +304,84 @@ void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumVa } // Returns this property cache's metaObject, creating it if necessary. -const QMetaObject *QQmlPropertyCache::createMetaObject() +const QMetaObject *QQmlPropertyCache::createMetaObject() const { - if (!_metaObject) { - _ownMetaObject = true; - + if (_metaObject.isNull()) { QMetaObjectBuilder builder; toMetaObjectBuilder(builder); builder.setSuperClass(_parent->createMetaObject()); - _metaObject = builder.toMetaObject(); + _metaObject.setSharedOnce(builder.toMetaObject()); } - return _metaObject; + return _metaObject.metaObject(); } -QQmlPropertyData *QQmlPropertyCache::defaultProperty() const +const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const { - return property(defaultPropertyName(), nullptr, nullptr); + if (index < 0 || index >= propertyCount()) + return nullptr; + + const QQmlPropertyData *rv = nullptr; + if (index < propertyIndexCacheStart) + return _parent->maybeUnresolvedProperty(index); + else + rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); + return rv; } -void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent) +const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const { - if (_parent == newParent) - return; - if (_parent) - _parent->release(); - _parent = newParent; - _parent->addref(); + return property(defaultPropertyName(), nullptr, nullptr); } -QQmlPropertyCache * -QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - QQmlPropertyData::Flags propertyFlags, - QQmlPropertyData::Flags methodFlags, - QQmlPropertyData::Flags signalFlags) +void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent) { - return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags); + if (_parent != newParent) + _parent = std::move(newParent); } -QQmlPropertyCache * +QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - int typeMinorVersion, + QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, - QQmlPropertyData::Flags signalFlags) + QQmlPropertyData::Flags signalFlags) const { Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); // Reserve enough space in the name hash for all the methods (including signals), all the // signal handlers and all the properties. This assumes no name clashes, but this is the // common case. - QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount + - QMetaObjectPrivate::get(metaObject)->signalCount + - QMetaObjectPrivate::get(metaObject)->propertyCount); + QQmlPropertyCache::Ptr rv = copy( + metaObject, + QMetaObjectPrivate::get(metaObject)->methodCount + + QMetaObjectPrivate::get(metaObject)->signalCount + + QMetaObjectPrivate::get(metaObject)->propertyCount); - rv->append(metaObject, typeMinorVersion, propertyFlags, methodFlags, signalFlags); + rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags); return rv; } +static QHashedString signalNameToHandlerName(const QHashedString &methodName) +{ + return QQmlSignalNames::signalNameToHandlerName(methodName); +} + +static QHashedString signalNameToHandlerName(const QHashedCStringRef &methodName) +{ + return QQmlSignalNames::signalNameToHandlerName( + QLatin1StringView{ methodName.constData(), methodName.length() }); +} + + void QQmlPropertyCache::append(const QMetaObject *metaObject, - int typeMinorVersion, + QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) { - _metaObject = metaObject; - - bool dynamicMetaObject = isDynamicMetaObject(metaObject); - - allowedRevisionCache.append(0); + allowedRevisionCache.append(QTypeRevision::zero()); int methodCount = metaObject->methodCount(); Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); @@ -473,6 +401,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod); if (_jsFactoryMethodIndex != -1) _jsFactoryMethodIndex -= metaObject->methodOffset(); + } else if (0 == qstrcmp(name, "QML.ListPropertyAssignBehavior")) { + _listPropertyAssignBehavior = mci.value(); } } } @@ -482,7 +412,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); // These indices don't apply to gadgets, so don't block them. - const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject; + // It is enough to check for QObject::staticMetaObject here because the loop below excludes + // methods of parent classes: It starts at metaObject->methodOffset() + const bool preventDestruction = (metaObject == &QObject::staticMetaObject); int methodOffset = metaObject->methodOffset(); int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount; @@ -518,61 +450,42 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, else data->setFlags(methodFlags); - data->lazyLoad(m); - data->m_flags.isDirect = !dynamicMetaObject; + data->load(m); - Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->setMetaObjectOffset(allowedRevisionCache.count() - 1); + Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX); + data->setMetaObjectOffset(allowedRevisionCache.size() - 1); if (data->isSignal()) { sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart]; *sigdata = *data; - sigdata->m_flags.isSignalHandler = true; + sigdata->m_flags.setIsSignalHandler(true); } QQmlPropertyData *old = nullptr; - if (utf8) { - QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName)); - if (StringCache::mapped_type *it = stringCache.value(methodName)) - old = it->second; - setNamedProperty(methodName, ii, data, (old != nullptr)); - - if (data->isSignal()) { - QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1)); - setNamedProperty(on, ii, sigdata, (old != nullptr)); - ++signalHandlerIndex; + const auto doSetNamedProperty = [&](const auto &methodName) { + if (StringCache::mapped_type *it = stringCache.value(methodName)) { + if (handleOverride(methodName, data, (old = it->second)) == InvalidOverride) + return; } - } else { - QHashedCStringRef methodName(rawName, cptr - rawName); - if (StringCache::mapped_type *it = stringCache.value(methodName)) - old = it->second; - setNamedProperty(methodName, ii, data, (old != nullptr)); + + setNamedProperty(methodName, ii, data); if (data->isSignal()) { - int length = methodName.length(); - - QVarLengthArray<char, 128> str(length+3); - str[0] = 'o'; - str[1] = 'n'; - str[2] = toupper(rawName[0]); - if (length > 1) - memcpy(&str[3], &rawName[1], length - 1); - str[length + 2] = '\0'; - - QHashedString on(QString::fromLatin1(str.data())); - setNamedProperty(on, ii, data, (old != nullptr)); + + // TODO: Remove this once we can. Signals should not be overridable. + if (!utf8) + data->m_flags.setIsOverridableSignal(true); + + setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata); ++signalHandlerIndex; } - } - - if (old) { - // We only overload methods in the same class, exactly like C++ - if (old->isFunction() && old->coreIndex() >= methodOffset) - data->m_flags.isOverload = true; + }; - data->markAsOverrideOf(old); - } + if (utf8) + doSetNamedProperty(QHashedString(QString::fromUtf8(rawName, cptr - rawName))); + else + doSetNamedProperty(QHashedCStringRef(rawName, cptr - rawName)); } int propCount = metaObject->propertyCount(); @@ -597,26 +510,28 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; data->setFlags(propertyFlags); - data->lazyLoad(p); - data->setTypeMinorVersion(typeMinorVersion); - - data->m_flags.isDirect = !dynamicMetaObject; + data->load(p); + data->setTypeVersion(typeVersion); - Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->setMetaObjectOffset(allowedRevisionCache.count() - 1); + Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX); + data->setMetaObjectOffset(allowedRevisionCache.size() - 1); QQmlPropertyData *old = nullptr; if (utf8) { QHashedString propName(QString::fromUtf8(str, cptr - str)); - if (StringCache::mapped_type *it = stringCache.value(propName)) - old = it->second; - setNamedProperty(propName, ii, data, (old != nullptr)); + if (StringCache::mapped_type *it = stringCache.value(propName)) { + if (handleOverride(propName, data, (old = it->second)) == InvalidOverride) + continue; + } + setNamedProperty(propName, ii, data); } else { QHashedCStringRef propName(str, cptr - str); - if (StringCache::mapped_type *it = stringCache.value(propName)) - old = it->second; - setNamedProperty(propName, ii, data, (old != nullptr)); + if (StringCache::mapped_type *it = stringCache.value(propName)) { + if (handleOverride(propName, data, (old = it->second)) == InvalidOverride) + continue; + } + setNamedProperty(propName, ii, data); } bool isGadget = true; @@ -625,67 +540,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, isGadget = false; } - if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept - data->m_flags.isDirect = false; - else + // otherwise always dispatch over a 'normal' meta-call so the QQmlValueType can intercept + if (!isGadget) data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset); - if (old) - data->markAsOverrideOf(old); } } -void QQmlPropertyCache::resolve(QQmlPropertyData *data) const -{ - Q_ASSERT(data->notFullyResolved()); - data->m_flags.notFullyResolved = false; - - const QMetaObject *mo = firstCppMetaObject(); - if (data->isFunction()) { - auto metaMethod = mo->method(data->coreIndex()); - const char *retTy = metaMethod.typeName(); - if (!retTy) - retTy = "\0"; - data->setPropType(QMetaType::type(retTy)); - } else { - auto metaProperty = mo->property(data->coreIndex()); - data->setPropType(QMetaType::type(metaProperty.typeName())); - } - - if (!data->isFunction()) { - if (data->propType() == QMetaType::UnknownType) { - QQmlPropertyCache *p = _parent; - while (p && (!mo || _ownMetaObject)) { - mo = p->_metaObject; - p = p->_parent; - } - - int propOffset = mo->propertyOffset(); - if (mo && data->coreIndex() < propOffset + mo->propertyCount()) { - while (data->coreIndex() < propOffset) { - mo = mo->superClass(); - propOffset = mo->propertyOffset(); - } - - int registerResult = -1; - void *argv[] = { ®isterResult }; - mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv); - data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); - } - } - flagsForPropertyType(data->propType(), data->m_flags); - } -} - -void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) -{ - if (!metaObject) - return; - - updateRecur(metaObject->superClass()); - - append(metaObject, -1); -} - void QQmlPropertyCache::update(const QMetaObject *metaObject) { Q_ASSERT(metaObject); @@ -705,7 +565,8 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject) // cached in a parent cache. stringCache.reserve(pc + mc + sc); - updateRecur(metaObject); + if (metaObject) + append(metaObject, QTypeRevision()); } /*! \internal @@ -718,7 +579,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) methodIndexCache.clear(); signalHandlerIndexCache.clear(); - _hasPropertyOverrides = false; argumentsCache = nullptr; int pc = metaObject->propertyCount(); @@ -727,11 +587,11 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) int reserve = pc + mc + sc; if (parent()) { - propertyIndexCacheStart = parent()->propertyIndexCache.count() + parent()->propertyIndexCacheStart; - methodIndexCacheStart = parent()->methodIndexCache.count() + parent()->methodIndexCacheStart; - signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.count() + parent()->signalHandlerIndexCacheStart; + propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart; + methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart; + signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart; stringCache.linkAndReserve(parent()->stringCache, reserve); - append(metaObject, -1); + append(metaObject, QTypeRevision()); } else { propertyIndexCacheStart = 0; methodIndexCacheStart = 0; @@ -740,7 +600,9 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) } } -QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const +const QQmlPropertyData *QQmlPropertyCache::findProperty( + StringCache::ConstIterator it, QObject *object, + const QQmlRefPointer<QQmlContextData> &context) const { QQmlData *data = (object ? QQmlData::get(object) : nullptr); const QQmlVMEMetaObject *vmemo = nullptr; @@ -753,14 +615,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, namespace { -inline bool contextHasNoExtensions(QQmlContextData *context) +inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &context) { // This context has no extension if its parent is the engine's rootContext, // which has children but no imports - return (!context->parent || !context->parent->imports); + const QQmlRefPointer<QQmlContextData> parent = context->parent(); + return (!parent || !parent->imports()); } -inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount) +inline int maximumIndexForProperty(const QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount) { return prop->isFunction() ? methodCount : prop->isSignalHandler() ? signalCount @@ -769,12 +632,14 @@ inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount } -QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const +const QQmlPropertyData *QQmlPropertyCache::findProperty( + StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, + const QQmlRefPointer<QQmlContextData> &context) const { StringCache::ConstIterator end = stringCache.end(); if (it != end) { - QQmlPropertyData *result = it.value().second; + const QQmlPropertyData *result = it.value().second; // If there exists a typed property (not a function or signal handler), of the // right name available to the specified context, we need to return that @@ -783,7 +648,7 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, if (vmemo && context && !contextHasNoExtensions(context)) { // Find the meta-object that corresponds to the supplied context do { - if (vmemo->ctxt == context) + if (vmemo->ctxt.contextData().data() == context.data()) break; vmemo = vmemo->parentVMEMetaObject(); @@ -815,7 +680,7 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, } while (it != end); } - return ensureResolved(result); + return result; } return nullptr; @@ -844,22 +709,24 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject) const } } -void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor) +bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor) { + Q_ASSERT(predecessor != this); + if (predecessor->isFinal()) + return false; + setOverrideIndexIsProperty(!predecessor->isFunction()); setOverrideIndex(predecessor->coreIndex()); - - predecessor->m_flags.isOverridden = true; + predecessor->m_flags.setIsOverridden(true); + Q_ASSERT(predecessor->isOverridden()); + return true; } -QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names) +QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject( + int argc, const QList<QByteArray> &names) { typedef QQmlPropertyCacheMethodArguments A; - A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int))); - args->arguments[0] = argc; - args->argumentsValid = false; - args->signalParameterStringForJS = nullptr; - args->parameterError = false; + A *args = static_cast<A *>(malloc(sizeof(A) + argc * sizeof(QMetaType))); args->names = argc ? new QList<QByteArray>(names) : nullptr; args->next = argumentsCache; argumentsCache = args; @@ -872,13 +739,17 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi const QSet<QString> &illegalNames = engine->illegalNames(); QString parameters; - for (int i = 0; i < parameterNameList.count(); ++i) { + const qsizetype count = parameterNameList.size(); + if (count > std::numeric_limits<quint16>::max()) + *errorString = QCoreApplication::translate("QQmlRewrite", "Signal has an excessive number of parameters: %1").arg(count); + + for (qsizetype i = 0; i < count; ++i) { if (i > 0) parameters += QLatin1Char(','); const QByteArray ¶m = parameterNameList.at(i); - if (param.isEmpty()) + if (param.isEmpty()) { unnamedParameter = true; - else if (unnamedParameter) { + } else if (unnamedParameter) { if (errorString) *errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter."); return QString(); @@ -893,19 +764,19 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi return parameters; } -int QQmlPropertyCache::originalClone(int index) +int QQmlPropertyCache::originalClone(int index) const { while (signal(index)->isCloned()) --index; return index; } -int QQmlPropertyCache::originalClone(QObject *object, int index) +int QQmlPropertyCache::originalClone(const QObject *object, int index) { - QQmlData *data = QQmlData::get(object, false); + QQmlData *data = QQmlData::get(object); if (data && data->propertyCache) { - QQmlPropertyCache *cache = data->propertyCache; - QQmlPropertyData *sig = cache->signal(index); + const QQmlPropertyCache *cache = data->propertyCache.data(); + const QQmlPropertyData *sig = cache->signal(index); while (sig && sig->isCloned()) { --index; sig = cache->signal(index); @@ -981,7 +852,7 @@ static inline const char *qQmlPropertyCacheToString(QLatin1String string) return string.data(); } -static inline QByteArray qQmlPropertyCacheToString(const QStringRef &string) +static inline QByteArray qQmlPropertyCacheToString(QStringView string) { return string.toUtf8(); } @@ -992,99 +863,84 @@ static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string) } template<typename T> -QQmlPropertyData * -qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name, - QQmlContextData *context, QQmlPropertyData &local) +const QQmlPropertyData * +qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer<QQmlContextData> &context, + QQmlPropertyData *local) { - QQmlPropertyCache *cache = nullptr; + const QQmlPropertyCache *cache = nullptr; QQmlData *ddata = QQmlData::get(obj, false); if (ddata && ddata->propertyCache) { - cache = ddata->propertyCache; - } else if (engine) { - QJSEnginePrivate *ep = QJSEnginePrivate::get(engine); - cache = ep->cache(obj); - if (cache) { - ddata = QQmlData::get(obj, true); - cache->addref(); - ddata->propertyCache = cache; - } + cache = ddata->propertyCache.data(); + } else if (auto newCache = QQmlMetaType::propertyCache(obj)) { + cache = newCache.data(); + ddata = QQmlData::get(obj, true); + ddata->propertyCache = std::move(newCache); } - QQmlPropertyData *rv = nullptr; + const QQmlPropertyData *rv = nullptr; if (cache) { rv = cache->property(name, obj, context); - } else { - local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name)); - if (local.isValid()) - rv = &local; + } else if (local) { + *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name)); + if (local->isValid()) + rv = local; } return rv; } -QQmlPropertyData * -QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QV4::String *name, - QQmlContextData *context, QQmlPropertyData &local) +const QQmlPropertyData *QQmlPropertyCache::property( + QObject *obj, const QV4::String *name, const QQmlRefPointer<QQmlContextData> &context, + QQmlPropertyData *local) { - return qQmlPropertyCacheProperty<const QV4::String *>(engine, obj, name, context, local); + return qQmlPropertyCacheProperty<const QV4::String *>(obj, name, context, local); } -QQmlPropertyData * -QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QStringRef &name, - QQmlContextData *context, QQmlPropertyData &local) +const QQmlPropertyData *QQmlPropertyCache::property( + QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context, + QQmlPropertyData *local) { - return qQmlPropertyCacheProperty<const QStringRef &>(engine, obj, name, context, local); + return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local); } -QQmlPropertyData * -QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name, - QQmlContextData *context, QQmlPropertyData &local) +const QQmlPropertyData *QQmlPropertyCache::property( + QObject *obj, const QLatin1String &name, const QQmlRefPointer<QQmlContextData> &context, + QQmlPropertyData *local) { - return qQmlPropertyCacheProperty<const QLatin1String &>(engine, obj, name, context, local); + return qQmlPropertyCacheProperty<const QLatin1String &>(obj, name, context, local); } -// these two functions are copied from qmetaobject.cpp -static inline const QMetaObjectPrivate *priv(const uint* data) -{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } - +// this function is copied from qmetaobject.cpp static inline const QByteArray stringData(const QMetaObject *mo, int index) { - Q_ASSERT(priv(mo->d.data)->revision >= 7); - const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) }; - Q_ASSERT(data.ptr->ref.isStatic()); - Q_ASSERT(data.ptr->alloc == 0); - Q_ASSERT(data.ptr->capacityReserved == 0); - Q_ASSERT(data.ptr->size >= 0); - return data; -} - -bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo) -{ - return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject; + uint offset = mo->d.stringdata[2*index]; + uint length = mo->d.stringdata[2*index + 1]; + const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset; + return QByteArray::fromRawData(string, length); } const char *QQmlPropertyCache::className() const { - if (!_ownMetaObject && _metaObject) - return _metaObject->className(); + if (const QMetaObject *mo = _metaObject.metaObject()) + return mo->className(); else return _dynamicClassName.constData(); } -void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) +void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) const { - struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs, - const QPair<QString, QQmlPropertyData *> &rhs) { + struct Sort { static bool lt(const QPair<QString, const QQmlPropertyData *> &lhs, + const QPair<QString, const QQmlPropertyData *> &rhs) { return lhs.second->coreIndex() < rhs.second->coreIndex(); } }; - struct Insert { static void in(QQmlPropertyCache *This, - QList<QPair<QString, QQmlPropertyData *> > &properties, - QList<QPair<QString, QQmlPropertyData *> > &methods, - StringCache::ConstIterator iter, QQmlPropertyData *data) { + struct Insert { static void in(const QQmlPropertyCache *This, + QList<QPair<QString, const QQmlPropertyData *> > &properties, + QList<QPair<QString, const QQmlPropertyData *> > &methods, + StringCache::ConstIterator iter, const QQmlPropertyData *data) { if (data->isSignalHandler()) return; @@ -1092,7 +948,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) if (data->coreIndex() < This->methodIndexCacheStart) return; - QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); + QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); // Overrides can cause the entry to already exist if (!methods.contains(entry)) methods.append(entry); @@ -1102,7 +958,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) if (data->coreIndex() < This->propertyIndexCacheStart) return; - QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); + QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); // Overrides can cause the entry to already exist if (!properties.contains(entry)) properties.append(entry); @@ -1114,40 +970,43 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) builder.setClassName(_dynamicClassName); - QList<QPair<QString, QQmlPropertyData *> > properties; - QList<QPair<QString, QQmlPropertyData *> > methods; + QList<QPair<QString, const QQmlPropertyData *> > properties; + QList<QPair<QString, const QQmlPropertyData *> > methods; for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter) Insert::in(this, properties, methods, iter, iter.value().second); - Q_ASSERT(properties.count() == propertyIndexCache.count()); - Q_ASSERT(methods.count() == methodIndexCache.count()); + Q_ASSERT(properties.size() == propertyIndexCache.size()); + Q_ASSERT(methods.size() == methodIndexCache.size()); std::sort(properties.begin(), properties.end(), Sort::lt); std::sort(methods.begin(), methods.end(), Sort::lt); - for (int ii = 0; ii < properties.count(); ++ii) { - QQmlPropertyData *data = properties.at(ii).second; + for (int ii = 0; ii < properties.size(); ++ii) { + const QQmlPropertyData *data = properties.at(ii).second; int notifierId = -1; if (data->notifyIndex() != -1) notifierId = data->notifyIndex() - signalHandlerIndexCacheStart; QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(), - QMetaType::typeName(data->propType()), + data->propType().name(), + data->propType(), notifierId); property.setReadable(true); property.setWritable(data->isWritable()); property.setResettable(data->isResettable()); + property.setBindable(data->isBindable()); + property.setAlias(data->isAlias()); } - for (int ii = 0; ii < methods.count(); ++ii) { - QQmlPropertyData *data = methods.at(ii).second; + for (int ii = 0; ii < methods.size(); ++ii) { + const QQmlPropertyData *data = methods.at(ii).second; QByteArray returnType; - if (data->propType() != 0) - returnType = QMetaType::typeName(data->propType()); + if (data->propType().isValid()) + returnType = data->propType().name(); QByteArray signature; // '+=' reserves extra capacity. Follow-up appending will be probably free. @@ -1155,11 +1014,12 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) QQmlPropertyCacheMethodArguments *arguments = nullptr; if (data->hasArguments()) { - arguments = (QQmlPropertyCacheMethodArguments *)data->arguments(); - Q_ASSERT(arguments->argumentsValid); - for (int ii = 0; ii < arguments->arguments[0]; ++ii) { - if (ii != 0) signature.append(','); - signature.append(QMetaType::typeName(arguments->arguments[1 + ii])); + arguments = data->arguments(); + for (int ii = 0, end = arguments->names ? arguments->names->size() : 0; + ii < end; ++ii) { + if (ii != 0) + signature.append(','); + signature.append(arguments->types[1 + ii].name()); } } @@ -1180,23 +1040,26 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) method.setReturnType(returnType); } - for (int ii = 0; ii < enumCache.count(); ++ii) { + for (int ii = 0; ii < enumCache.size(); ++ii) { const QQmlEnumData &enumData = enumCache.at(ii); QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8()); enumeration.setIsScoped(true); - for (int jj = 0; jj < enumData.values.count(); ++jj) { + for (int jj = 0; jj < enumData.values.size(); ++jj) { const QQmlEnumValue &value = enumData.values.at(jj); enumeration.addKey(value.namedValue.toUtf8(), value.value); } } if (!_defaultPropertyName.isEmpty()) { - QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr); + const QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr); if (dp && dp->coreIndex() >= propertyIndexCacheStart) { Q_ASSERT(!dp->isFunction()); builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8()); } } + + if (!_listPropertyAssignBehavior.isEmpty()) + builder.addClassInfo("QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior); } namespace { @@ -1204,14 +1067,12 @@ template <typename StringVisitor, typename TypeInfoVisitor> int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount, StringVisitor visitString, TypeInfoVisitor visitTypeInfo) { - const int intsPerMethod = 5; - int fieldsForParameterData = 0; bool hasRevisionedMethods = false; for (int i = 0; i < methodCount; ++i) { - const int handle = methodOffset + i * intsPerMethod; + const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod; const uint flags = mo.d.data[handle + 4]; if (flags & MethodRevisioned) @@ -1241,42 +1102,23 @@ int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount, if (hasRevisionedMethods) fieldsForRevisions = methodCount; - return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData; + return methodCount * QMetaObjectPrivate::IntsPerMethod + + fieldsForRevisions + fieldsForParameterData; } template <typename StringVisitor, typename TypeInfoVisitor> int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo) { const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); - const int intsPerProperty = 3; - - bool hasRevisionedProperties = false; - bool hasNotifySignals = false; for (int i = 0; i < priv->propertyCount; ++i) { - const int handle = priv->propertyData + i * intsPerProperty; - - const auto flags = mo.d.data[handle + 2]; - if (flags & Revisioned) { - hasRevisionedProperties = true; - } - if (flags & Notify) - hasNotifySignals = true; + const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty; visitString(mo.d.data[handle]); // name visitTypeInfo(mo.d.data[handle + 1]); } - int fieldsForPropertyRevisions = 0; - if (hasRevisionedProperties) - fieldsForPropertyRevisions = priv->propertyCount; - - int fieldsForNotifySignals = 0; - if (hasNotifySignals) - fieldsForNotifySignals = priv->propertyCount; - - return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions - + fieldsForNotifySignals; + return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty; } template <typename StringVisitor> @@ -1299,21 +1141,19 @@ template <typename StringVisitor> int visitEnumerations(const QMetaObject &mo, StringVisitor visitString) { const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); - const int intsPerEnumerator = priv->revision >= 8 ? 5 : 4; - int fieldCount = priv->enumeratorCount * intsPerEnumerator; + int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum; for (int i = 0; i < priv->enumeratorCount; ++i) { - const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator; + const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum; - const uint keyCount = enumeratorData[intsPerEnumerator == 5 ? 3 : 2]; + const uint keyCount = enumeratorData[3]; fieldCount += keyCount * 2; visitString(enumeratorData[0]); // name - if (intsPerEnumerator == 5) - visitString(enumeratorData[1]); // enum name + visitString(enumeratorData[1]); // enum name - const uint keyOffset = enumeratorData[intsPerEnumerator == 5 ? 4 : 3]; + const uint keyOffset = enumeratorData[4]; for (uint j = 0; j < keyCount; ++j) { visitString(mo.d.data[keyOffset + 2 * j]); @@ -1349,13 +1189,14 @@ int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor) } // anonymous namespace +static_assert(QMetaObjectPrivate::OutputRevision == 12, "Check and adjust determineMetaObjectSizes"); + bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount) { const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); - if (priv->revision < 7 || priv->revision > 8) { + if (priv->revision != QMetaObjectPrivate::OutputRevision) return false; - } uint highestStringIndex = 0; const auto stringIndexVisitor = [&highestStringIndex](uint index) { @@ -1376,7 +1217,7 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m return false; } - hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint)); + hash.addData({reinterpret_cast<const char *>(mo.d.data), qsizetype(fieldCount * sizeof(uint))}); for (int i = 0; i < stringCount; ++i) { hash.addData(stringData(&mo, i)); } @@ -1384,35 +1225,41 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m return true; } -QByteArray QQmlPropertyCache::checksum(bool *ok) +QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const { - if (!_checksum.isEmpty()) { + auto it = checksums->constFind(quintptr(this)); + if (it != checksums->constEnd()) { *ok = true; - return _checksum; + return *it; } // Generate a checksum on the meta-object data only on C++ types. - if (!_metaObject || _ownMetaObject) { + if (_metaObject.isShared()) { *ok = false; - return _checksum; + return QByteArray(); } QCryptographicHash hash(QCryptographicHash::Md5); if (_parent) { - hash.addData(_parent->checksum(ok)); + hash.addData(_parent->checksum(checksums, ok)); if (!*ok) return QByteArray(); } - if (!addToHash(hash, *createMetaObject())) { + if (!addToHash(hash, *_metaObject.metaObject())) { *ok = false; return QByteArray(); } - _checksum = hash.result(); - *ok = !_checksum.isEmpty(); - return _checksum; + const QByteArray result = hash.result(); + if (result.isEmpty()) { + *ok = false; + } else { + *ok = true; + checksums->insert(quintptr(this), result); + } + return result; } /*! \internal @@ -1421,7 +1268,7 @@ QByteArray QQmlPropertyCache::checksum(bool *ok) */ QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const { - QQmlPropertyData *signalData = signal(index); + const QQmlPropertyData *signalData = signal(index); if (signalData && signalData->hasArguments()) { QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments(); if (args && args->names) |