aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertycache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlpropertycache.cpp')
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp583
1 files changed, 272 insertions, 311 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 8ffdc42d82..a225f94a3f 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>
@@ -89,19 +54,13 @@ QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
const QMetaType metaType = p.metaType();
int propType = metaType.id();
if (p.isEnumType()) {
- flags.type = QQmlPropertyData::Flags::EnumType;
+ flags.setType(QQmlPropertyData::Flags::EnumType);
} else if (metaType.flags() & QMetaType::PointerToQObject) {
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
+ flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
} else if (propType == QMetaType::QVariant) {
- flags.type = QQmlPropertyData::Flags::QVariantType;
- } else if (propType < static_cast<int>(QMetaType::User)) {
- // nothing to do
- } else if (propType == qMetaTypeId<QQmlBinding *>()) {
- flags.type = QQmlPropertyData::Flags::QmlBindingType;
- } else if (propType == qMetaTypeId<QJSValue>()) {
- flags.type = QQmlPropertyData::Flags::QJSValueType;
+ flags.setType(QQmlPropertyData::Flags::QVariantType);
} else if (metaType.flags() & QMetaType::IsQmlList) {
- flags.type = QQmlPropertyData::Flags::QListType;
+ flags.setType(QQmlPropertyData::Flags::QListType);
}
return flags;
@@ -121,51 +80,67 @@ void QQmlPropertyData::load(const QMetaProperty &p)
void QQmlPropertyData::load(const QMetaMethod &m)
{
setCoreIndex(m.methodIndex());
- setArguments(nullptr);
+ m_flags.setType(Flags::FunctionType);
- setPropType(m.returnMetaType());
+ // 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.
- m_flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal) {
+ switch (m.methodType()) {
+ case QMetaMethod::Signal:
m_flags.setIsSignal(true);
- } else if (m.methodType() == QMetaMethod::Constructor) {
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
+ case QMetaMethod::Constructor:
+ m_flags.setIsSignal(false);
m_flags.setIsConstructor(true);
setPropType(QMetaType::fromType<QObject *>());
+ 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.setHasArguments(true);
- if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
- m_flags.setIsV4Function(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.setIsCloned(true);
+ m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
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()
- : propertyIndexCacheStart(0), _parent(nullptr),
- argumentsCache(nullptr), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0),
- _jsFactoryMethodIndex(-1), _hasPropertyOverrides(false)
-{
-}
-
-/*!
-Creates a new QQmlPropertyCache of \a metaObject.
-*/
-QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevision 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.isValid() && metaObjectRevision != QTypeRevision::zero()) {
// Set the revision of the meta object that this cache describes to be
@@ -173,9 +148,13 @@ QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevisio
// 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()
@@ -191,42 +170,38 @@ QQmlPropertyCache::~QQmlPropertyCache()
// We must clear this prior to releasing the parent incase it is a
// linked hash
stringCache.clear();
- if (_parent) _parent->release();
-
- _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 = RefCountedMetaObject();
-
return rv;
}
@@ -246,18 +221,18 @@ void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Fl
data.setFlags(flags);
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;
@@ -270,56 +245,55 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
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> &parameterTypes)
+ int coreIndex, QMetaType returnType,
+ const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes)
{
- int argumentCount = names.count();
+ int argumentCount = names.size();
QQmlPropertyData data;
- data.setPropType(QMetaType(returnType));
+ 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)
@@ -331,77 +305,83 @@ 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) {
+ if (_metaObject.isNull()) {
QMetaObjectBuilder builder;
toMetaObjectBuilder(builder);
builder.setSuperClass(_parent->createMetaObject());
- _metaObject = RefCountedMetaObject(builder.toMetaObject(), RefCountedMetaObject::SharedMetaObject);
+ _metaObject.setSharedOnce(builder.toMetaObject());
}
- return _metaObject;
+ return _metaObject.metaObject();
}
-QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
+const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
- QQmlPropertyData *rv = nullptr;
+ const QQmlPropertyData *rv = nullptr;
if (index < propertyIndexCacheStart)
return _parent->maybeUnresolvedProperty(index);
else
- rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
return rv;
}
-QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
return property(defaultPropertyName(), nullptr, nullptr);
}
-void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
+void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
{
- if (_parent == newParent)
- return;
- if (_parent)
- _parent->release();
- _parent = newParent;
- _parent->addref();
+ if (_parent != newParent)
+ _parent = std::move(newParent);
}
-QQmlPropertyCache *
+QQmlPropertyCache::Ptr
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
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, 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,
QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
QQmlPropertyData::Flags signalFlags)
{
- _metaObject = RefCountedMetaObject(metaObject, RefCountedMetaObject::StaticMetaObject);
-
- bool dynamicMetaObject = isDynamicMetaObject(metaObject);
-
allowedRevisionCache.append(QTypeRevision::zero());
int methodCount = metaObject->methodCount();
@@ -422,6 +402,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();
}
}
}
@@ -470,10 +452,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->setFlags(methodFlags);
data->load(m);
- data->m_flags.setIsDirect(!dynamicMetaObject);
- 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];
@@ -483,47 +464,29 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
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() % QStringView{methodName}.mid(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.setIsOverload(true);
+ };
- data->markAsOverrideOf(old);
- }
+ if (utf8)
+ doSetNamedProperty(QHashedString(QString::fromUtf8(rawName, cptr - rawName)));
+ else
+ doSetNamedProperty(QHashedCStringRef(rawName, cptr - rawName));
}
int propCount = metaObject->propertyCount();
@@ -551,23 +514,25 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->load(p);
data->setTypeVersion(typeVersion);
- data->m_flags.setIsDirect(!dynamicMetaObject);
-
- 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;
@@ -576,25 +541,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.setIsDirect(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::updateRecur(const QMetaObject *metaObject)
-{
- if (!metaObject)
- return;
-
- updateRecur(metaObject->superClass());
-
- append(metaObject, QTypeRevision());
-}
-
void QQmlPropertyCache::update(const QMetaObject *metaObject)
{
Q_ASSERT(metaObject);
@@ -614,7 +566,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
@@ -627,7 +580,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
methodIndexCache.clear();
signalHandlerIndexCache.clear();
- _hasPropertyOverrides = false;
argumentsCache = nullptr;
int pc = metaObject->propertyCount();
@@ -636,9 +588,9 @@ 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, QTypeRevision());
} else {
@@ -649,7 +601,7 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
StringCache::ConstIterator it, QObject *object,
const QQmlRefPointer<QQmlContextData> &context) const
{
@@ -668,10 +620,11 @@ inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &contex
{
// 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
@@ -680,14 +633,14 @@ inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(
+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
@@ -757,21 +710,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.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->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;
@@ -784,13 +740,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 &param = 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();
@@ -805,7 +765,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
return parameters;
}
-int QQmlPropertyCache::originalClone(int index)
+int QQmlPropertyCache::originalClone(int index) const
{
while (signal(index)->isCloned())
--index;
@@ -814,10 +774,10 @@ int QQmlPropertyCache::originalClone(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);
@@ -904,27 +864,23 @@ static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string)
}
template<typename T>
-QQmlPropertyData *
-qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
- const QQmlRefPointer<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);
@@ -937,31 +893,28 @@ qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
return rv;
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QV4::String *name,
- const QQmlRefPointer<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, QStringView name,
- const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData *local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QStringView &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name,
- const QQmlRefPointer<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)
{
uint offset = mo->d.stringdata[2*index];
@@ -970,30 +923,25 @@ static inline const QByteArray stringData(const QMetaObject *mo, int index)
return QByteArray::fromRawData(string, length);
}
-bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
-{
- return priv(mo->d.data)->flags & DynamicMetaObject;
-}
-
const char *QQmlPropertyCache::className() const
{
- if (_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;
@@ -1001,7 +949,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);
@@ -1011,7 +959,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);
@@ -1023,20 +971,20 @@ 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)
@@ -1051,10 +999,11 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
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().isValid())
@@ -1066,11 +1015,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(arguments->arguments[1 + ii]).name());
+ 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());
}
}
@@ -1091,23 +1041,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 {
@@ -1237,11 +1190,13 @@ 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 != 9)
+ if (priv->revision != QMetaObjectPrivate::OutputRevision)
return false;
uint highestStringIndex = 0;
@@ -1263,7 +1218,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));
}
@@ -1271,35 +1226,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 || _metaObject.isShared()) {
+ 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
@@ -1308,7 +1269,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)