aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertycache_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlpropertycache_p.h')
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h943
1 files changed, 213 insertions, 730 deletions
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index c3c818eb77..7ff499460d 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -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
#ifndef QQMLPROPERTYCACHE_P_H
#define QQMLPROPERTYCACHE_P_H
@@ -51,419 +15,193 @@
// We mean it.
//
+#include <private/qlinkedstringhash_p.h>
+#include <private/qqmlenumdata_p.h>
+#include <private/qqmlenumvalue_p.h>
+#include <private/qqmlpropertydata_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qflagpointer_p.h>
-#include "qqmlcleanup_p.h"
-#include "qqmlnotifier_p.h"
-#include <private/qqmlpropertyindex_p.h>
-#include <private/qhashedstring_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
-
-#include <private/qv4value_p.h>
+#include <QtCore/qversionnumber.h>
#include <limits>
QT_BEGIN_NAMESPACE
class QCryptographicHash;
-class QMetaProperty;
-class QQmlEngine;
class QJSEngine;
-class QQmlPropertyData;
class QMetaObjectBuilder;
+class QQmlContextData;
+class QQmlPropertyCache;
class QQmlPropertyCacheMethodArguments;
class QQmlVMEMetaObject;
-template <typename T> class QQmlPropertyCacheCreator;
-template <typename T> class QQmlPropertyCacheAliasCreator;
-
-// We have this somewhat awful split between RawData and Data so that RawData can be
-// used in unions. In normal code, you should always use Data which initializes RawData
-// to an invalid state on construction.
-// ### We should be able to remove this split nowadays
-class QQmlPropertyRawData
+
+class QQmlMetaObjectPointer
{
public:
- typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
-
- struct Flags {
- enum Types {
- OtherType = 0,
- FunctionType = 1, // Is an invokable
- QObjectDerivedType = 2, // Property type is a QObject* derived type
- EnumType = 3, // Property type is an enum
- QListType = 4, // Property type is a QML list
- QmlBindingType = 5, // Property type is a QQmlBinding*
- QJSValueType = 6, // Property type is a QScriptValue
- V4HandleType = 7, // Property type is a QQmlV4Handle
- VarPropertyType = 8, // Property type is a "var" property of VMEMO
- QVariantType = 9 // Property is a QVariant
- };
-
- // The _otherBits (which "pad" the Flags struct to align it nicely) are used
- // to store the relative property index. It will only get used when said index fits. See
- // trySetStaticMetaCallFunction for details.
- // (Note: this padding is done here, because certain compilers have surprising behavior
- // when an enum is declared in-between two bit fields.)
- enum { BitsLeftInFlags = 10 };
- unsigned _otherBits : BitsLeftInFlags; // align to 32 bits
-
- // Can apply to all properties, except IsFunction
- unsigned isConstant : 1; // Has CONST flag
- unsigned isWritable : 1; // Has WRITE function
- unsigned isResettable : 1; // Has RESET function
- unsigned isAlias : 1; // Is a QML alias to another property
- unsigned isFinal : 1; // Has FINAL flag
- unsigned isOverridden : 1; // Is overridden by a extension property
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
-
- unsigned type : 4; // stores an entry of Types
-
- // Apply only to IsFunctions
- unsigned isVMEFunction : 1; // Function was added by QML
- unsigned hasArguments : 1; // Function takes arguments
- unsigned isSignal : 1; // Function is a signal
- unsigned isVMESignal : 1; // Signal was added by QML
- unsigned isV4Function : 1; // Function takes QQmlV4Function* args
- unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
- unsigned isConstructor : 1; // The function was marked is a constructor
-
- // Internal QQmlPropertyCache flags
- unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
- unsigned overrideIndexIsProperty: 1;
-
- inline Flags();
- inline bool operator==(const Flags &other) const;
- inline void copyPropertyTypeFlags(Flags from);
- };
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer() = default;
- Flags flags() const { return _flags; }
- void setFlags(Flags f)
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QMetaObject *staticMetaObject)
+ : d(quintptr(staticMetaObject))
{
- unsigned otherBits = _flags._otherBits;
- _flags = f;
- _flags._otherBits = otherBits;
+ Q_ASSERT((d.loadRelaxed() & Shared) == 0);
}
- bool isValid() const { return coreIndex() != -1; }
-
- bool isConstant() const { return _flags.isConstant; }
- bool isWritable() const { return _flags.isWritable; }
- void setWritable(bool onoff) { _flags.isWritable = onoff; }
- bool isResettable() const { return _flags.isResettable; }
- bool isAlias() const { return _flags.isAlias; }
- bool isFinal() const { return _flags.isFinal; }
- bool isOverridden() const { return _flags.isOverridden; }
- bool isDirect() const { return _flags.isDirect; }
- bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
- bool isFunction() const { return _flags.type == Flags::FunctionType; }
- bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; }
- bool isEnum() const { return _flags.type == Flags::EnumType; }
- bool isQList() const { return _flags.type == Flags::QListType; }
- bool isQmlBinding() const { return _flags.type == Flags::QmlBindingType; }
- bool isQJSValue() const { return _flags.type == Flags::QJSValueType; }
- bool isV4Handle() const { return _flags.type == Flags::V4HandleType; }
- bool isVarProperty() const { return _flags.type == Flags::VarPropertyType; }
- bool isQVariant() const { return _flags.type == Flags::QVariantType; }
- bool isVMEFunction() const { return _flags.isVMEFunction; }
- bool hasArguments() const { return _flags.hasArguments; }
- bool isSignal() const { return _flags.isSignal; }
- bool isVMESignal() const { return _flags.isVMESignal; }
- bool isV4Function() const { return _flags.isV4Function; }
- bool isSignalHandler() const { return _flags.isSignalHandler; }
- bool isOverload() const { return _flags.isOverload; }
- void setOverload(bool onoff) { _flags.isOverload = onoff; }
- bool isCloned() const { return _flags.isCloned; }
- bool isConstructor() const { return _flags.isConstructor; }
-
- bool hasOverride() const { return overrideIndex() >= 0; }
- bool hasRevision() const { return revision() != 0; }
-
- bool isFullyResolved() const { return !_flags.notFullyResolved; }
-
- int propType() const { Q_ASSERT(isFullyResolved()); return _propType; }
- void setPropType(int pt)
+ ~QQmlMetaObjectPointer()
{
- Q_ASSERT(pt >= 0);
- Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
- _propType = quint16(pt);
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ reinterpret_cast<SharedHolder *>(dd ^ Shared)->release();
}
- int notifyIndex() const { return _notifyIndex; }
- void setNotifyIndex(int idx)
+private:
+ friend class QQmlPropertyCache;
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QQmlMetaObjectPointer &other)
+ : d(other.d.loadRelaxed())
{
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _notifyIndex = qint16(idx);
+ // other has to survive until this ctor is done. So d cannot disappear before.
+ const auto od = other.d.loadRelaxed();
+ if (od & Shared)
+ reinterpret_cast<SharedHolder *>(od ^ Shared)->addref();
}
- bool overrideIndexIsProperty() const { return _flags.overrideIndexIsProperty; }
- void setOverrideIndexIsProperty(bool onoff) { _flags.overrideIndexIsProperty = onoff; }
-
- int overrideIndex() const { return _overrideIndex; }
- void setOverrideIndex(int idx)
- {
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _overrideIndex = qint16(idx);
- }
+ QQmlMetaObjectPointer(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(const QQmlMetaObjectPointer &other) = delete;
- int coreIndex() const { return _coreIndex; }
- void setCoreIndex(int idx)
+public:
+ void setSharedOnce(QMetaObject *shared) const
{
- Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
- Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- _coreIndex = qint16(idx);
+ SharedHolder *holder = new SharedHolder(shared);
+ if (!d.testAndSetRelease(0, quintptr(holder) | Shared))
+ holder->release();
}
- quint8 revision() const { return _revision; }
- void setRevision(quint8 rev)
+ const QMetaObject *metaObject() const
{
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- _revision = quint8(rev);
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ return reinterpret_cast<SharedHolder *>(dd ^ Shared)->metaObject;
+ return reinterpret_cast<const QMetaObject *>(dd);
}
- /* If a property is a C++ type, then we store the minor
- * version of this type.
- * This is required to resolve property or signal revisions
- * if this property is used as a grouped property.
- *
- * Test.qml
- * property TextEdit someTextEdit: TextEdit {}
- *
- * Test {
- * someTextEdit.preeditText: "test" //revision 7
- * someTextEdit.onEditingFinished: console.log("test") //revision 6
- * }
- *
- * To determine if these properties with revisions are available we need
- * the minor version of TextEdit as imported in Test.qml.
- *
- */
-
- quint8 typeMinorVersion() const { return _typeMinorVersion; }
- void setTypeMinorVersion(quint8 rev)
+ bool isShared() const
{
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- _typeMinorVersion = quint8(rev);
+ // This works because static metaobjects need to be set in the ctor and once a shared
+ // metaobject has been set, it cannot be removed anymore.
+ const auto dd = d.loadRelaxed();
+ return !dd || (dd & Shared);
}
- QQmlPropertyCacheMethodArguments *arguments() const { return _arguments; }
- void setArguments(QQmlPropertyCacheMethodArguments *args) { _arguments = args; }
-
- int metaObjectOffset() const { return _metaObjectOffset; }
- void setMetaObjectOffset(int off)
+ bool isNull() const
{
- Q_ASSERT(off >= std::numeric_limits<qint16>::min());
- Q_ASSERT(off <= std::numeric_limits<qint16>::max());
- _metaObjectOffset = qint16(off);
+ return d.loadRelaxed() == 0;
}
- StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; }
- void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
- {
- if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
- _flags._otherBits = relativePropertyIndex;
- _staticMetaCallFunction = f;
- }
- }
- quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; }
-
private:
- Flags _flags;
- qint16 _coreIndex = 0;
- quint16 _propType = 0;
-
- // The notify index is in the range returned by QObjectPrivate::signalIndex().
- // This is different from QMetaMethod::methodIndex().
- qint16 _notifyIndex = 0;
- qint16 _overrideIndex = 0;
-
- quint8 _revision = 0;
- quint8 _typeMinorVersion = 0;
- qint16 _metaObjectOffset = 0;
+ enum Tag {
+ Static = 0,
+ Shared = 1
+ };
- QQmlPropertyCacheMethodArguments *_arguments = nullptr;
- StaticMetaCallFunction _staticMetaCallFunction = nullptr;
+ struct SharedHolder final : public QQmlRefCounted<SharedHolder>
+ {
+ Q_DISABLE_COPY_MOVE(SharedHolder)
+ SharedHolder(QMetaObject *shared) : metaObject(shared) {}
+ ~SharedHolder() { free(metaObject); }
+ QMetaObject *metaObject;
+ };
- friend class QQmlPropertyData;
- friend class QQmlPropertyCache;
+ mutable QBasicAtomicInteger<quintptr> d = 0;
};
-#if QT_POINTER_SIZE == 4
-Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 24);
-#else // QT_POINTER_SIZE == 8
-Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 32);
-#endif
-
-class QQmlPropertyData : public QQmlPropertyRawData
+class Q_QML_EXPORT QQmlPropertyCache final
+ : public QQmlRefCounted<QQmlPropertyCache>
{
public:
- enum WriteFlag {
- BypassInterceptor = 0x01,
- DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
- };
- Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
-
- inline QQmlPropertyData();
- inline QQmlPropertyData(const QQmlPropertyRawData &);
+ using Ptr = QQmlRefPointer<QQmlPropertyCache>;
- inline bool operator==(const QQmlPropertyRawData &);
-
- static Flags flagsForProperty(const QMetaProperty &);
- void load(const QMetaProperty &);
- void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
-
- void markAsOverrideOf(QQmlPropertyData *predecessor);
-
- inline void readProperty(QObject *target, void *property) const
- {
- void *args[] = { property, nullptr };
- readPropertyWithArgs(target, args);
- }
-
- inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ struct ConstPtr : public QQmlRefPointer<const QQmlPropertyCache>
{
- if (hasStaticMetaCallFunction())
- staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
- else if (isDirect())
- target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
- else
- QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
- }
-
- bool writeProperty(QObject *target, void *value, WriteFlags flags) const
- {
- int status = -1;
- void *argv[] = { value, nullptr, &status, &flags };
- if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
- staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
- else if (flags.testFlag(BypassInterceptor) && isDirect())
- target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
- else
- QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
- return true;
- }
+ using QQmlRefPointer<const QQmlPropertyCache>::QQmlRefPointer;
- static Flags defaultSignalFlags()
- {
- Flags f;
- f.isSignal = true;
- f.type = Flags::FunctionType;
- f.isVMESignal = true;
- return f;
- }
+ ConstPtr(const Ptr &ptr) : ConstPtr(ptr.data(), AddRef) {}
+ ConstPtr(Ptr &&ptr) : ConstPtr(ptr.take(), Adopt) {}
+ ConstPtr &operator=(const Ptr &ptr) { return operator=(ConstPtr(ptr)); }
+ ConstPtr &operator=(Ptr &&ptr) { return operator=(ConstPtr(std::move(ptr))); }
+ };
- static Flags defaultSlotFlags()
- {
- Flags f;
- f.type = Flags::FunctionType;
- f.isVMEFunction = true;
- return f;
- }
+ static Ptr createStandalone(
+ const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
-private:
- friend class QQmlPropertyCache;
- void lazyLoad(const QMetaProperty &);
- void lazyLoad(const QMetaMethod &);
- bool notFullyResolved() const { return _flags.notFullyResolved; }
-};
+ QQmlPropertyCache() = default;
+ ~QQmlPropertyCache();
-struct QQmlEnumValue
-{
- QQmlEnumValue() {}
- QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {}
- QString namedValue;
- int value = -1;
-};
+ void update(const QMetaObject *);
+ void invalidate(const QMetaObject *);
-struct QQmlEnumData
-{
- QString name;
- QVector<QQmlEnumValue> values;
-};
+ QQmlPropertyCache::Ptr copy() const;
-class QQmlPropertyCacheMethodArguments;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
-{
-public:
- QQmlPropertyCache();
- QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0);
- ~QQmlPropertyCache() override;
+ QQmlPropertyCache::Ptr copyAndAppend(
+ const QMetaObject *, QTypeRevision typeVersion,
+ QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()) const;
- void update(const QMetaObject *);
- void invalidate(const QMetaObject *);
- // Used by qmlpuppet. Remove as soon Creator requires Qt 5.5.
- void invalidate(void *, const QMetaObject *mo) { invalidate(mo); }
-
- QQmlPropertyCache *copy();
-
- QQmlPropertyCache *copyAndAppend(const QMetaObject *,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
- QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
-
- QQmlPropertyCache *copyAndReserve(int propertyCount,
- int methodCount, int signalCount, int enumCount);
- void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex,
- int propType, int revision, int notifyIndex);
- void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex,
- const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>());
- void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
+ QQmlPropertyCache::Ptr copyAndReserve(
+ int propertyCount, int methodCount, int signalCount, int enumCount) const;
+ void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
+ QMetaType propType, QTypeRevision revision, int notifyIndex);
+ void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex,
+ const QMetaType *types = nullptr,
const QList<QByteArray> &names = QList<QByteArray>());
+ void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
+ QMetaType returnType, const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes);
void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
- const QMetaObject *createMetaObject();
+ const QMetaObject *createMetaObject() const;
const QMetaObject *firstCppMetaObject() const;
template<typename K>
- QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const
+ const QQmlPropertyData *property(const K &key, QObject *object,
+ const QQmlRefPointer<QQmlContextData> &context) const
{
return findProperty(stringCache.find(key), object, context);
}
- QQmlPropertyData *property(int) const;
- QQmlPropertyData *method(int) const;
- QQmlPropertyData *signal(int index) const;
+ const QQmlPropertyData *property(int) const;
+ const QQmlPropertyData *maybeUnresolvedProperty(int) const;
+ const QQmlPropertyData *method(int) const;
+ const QQmlPropertyData *signal(int index) const;
QQmlEnumData *qmlEnum(int) const;
int methodIndexToSignalIndex(int) const;
QString defaultPropertyName() const;
- QQmlPropertyData *defaultProperty() const;
- QQmlPropertyCache *parent() const;
- // is used by the Qml Designer
- void setParent(QQmlPropertyCache *newParent);
+ const QQmlPropertyData *defaultProperty() const;
- inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
- inline bool isAllowedInRevision(QQmlPropertyData *) const;
+ // Return a reference here so that we don't have to addref/release all the time
+ inline const QQmlPropertyCache::ConstPtr &parent() const;
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QStringRef &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *,
- QQmlContextData *, QQmlPropertyData &);
+ // is used by the Qml Designer
+ void setParent(QQmlPropertyCache::ConstPtr newParent);
- static QQmlPropertyData *property(QJSEngine *engine, QObject *obj, const QString &name,
- QQmlContextData *context, QQmlPropertyData &local)
- {
- return property(engine, obj, QStringRef(&name), context, local);
- }
+ inline const QQmlPropertyData *overrideData(const QQmlPropertyData *) const;
+ inline bool isAllowedInRevision(const QQmlPropertyData *) const;
+
+ static const QQmlPropertyData *property(
+ QObject *, QStringView, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QLatin1String &, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QV4::String *, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
//see QMetaObjectPrivate::originalClone
- int originalClone(int index);
- static int originalClone(QObject *, int index);
+ int originalClone(int index) const;
+ static int originalClone(const QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString = nullptr);
@@ -478,45 +216,45 @@ public:
inline int signalOffset() const;
inline int qmlEnumCount() const;
- static bool isDynamicMetaObject(const QMetaObject *);
-
- void toMetaObjectBuilder(QMetaObjectBuilder &);
+ void toMetaObjectBuilder(QMetaObjectBuilder &) const;
inline bool callJSFactoryMethod(QObject *object, void **args) const;
static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
- QByteArray checksum(bool *ok);
+ QByteArray checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const;
+
+ QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; }
+ void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; }
+
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
template <typename T> friend class QQmlPropertyCacheCreator;
template <typename T> friend class QQmlPropertyCacheAliasCreator;
- friend class QQmlComponentAndAliasResolver;
+ template <typename T> friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
- friend struct QQmlMetaTypeData;
- inline QQmlPropertyCache *copy(int reserve);
+ QQmlPropertyCache(const QQmlMetaObjectPointer &metaObject) : _metaObject(metaObject) {}
+
+ inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const;
- void append(const QMetaObject *, int typeMinorVersion,
- QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(),
- QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
+ void append(const QMetaObject *, QTypeRevision typeVersion,
+ QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names);
typedef QVector<QQmlPropertyData> IndexCache;
- typedef QStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
- typedef QVector<int> AllowedRevisionCache;
+ typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
+ typedef QVector<QTypeRevision> AllowedRevisionCache;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const;
-
- QQmlPropertyData *ensureResolved(QQmlPropertyData*) const;
-
- Q_NEVER_INLINE void resolve(QQmlPropertyData *) const;
- void updateRecur(const QMetaObject *);
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
template<typename K>
QQmlPropertyData *findNamedProperty(const K &key) const
@@ -526,17 +264,36 @@ private:
}
template<typename K>
- void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride)
+ void setNamedProperty(const K &key, int index, QQmlPropertyData *data)
{
stringCache.insert(key, qMakePair(index, data));
- _hasPropertyOverrides |= isOverride;
}
private:
- QQmlPropertyCache *_parent;
- int propertyIndexCacheStart;
- int methodIndexCacheStart;
- int signalHandlerIndexCacheStart;
+ enum OverrideResult { NoOverride, InvalidOverride, ValidOverride };
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data, QQmlPropertyData *old)
+ {
+ if (!old)
+ return NoOverride;
+
+ if (data->markAsOverrideOf(old))
+ return ValidOverride;
+
+ qWarning("Final member %s is overridden in class %s. The override won't be used.",
+ qPrintable(name), className());
+ return InvalidOverride;
+ }
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data)
+ {
+ return handleOverride(name, data, findNamedProperty(name));
+ }
+
+ int propertyIndexCacheStart = 0; // placed here to avoid gap between QQmlRefCount and _parent
+ QQmlPropertyCache::ConstPtr _parent;
IndexCache propertyIndexCache;
IndexCache methodIndexCache;
@@ -545,250 +302,75 @@ private:
AllowedRevisionCache allowedRevisionCache;
QVector<QQmlEnumData> enumCache;
- bool _hasPropertyOverrides : 1;
- bool _ownMetaObject : 1;
- const QMetaObject *_metaObject;
+ QQmlMetaObjectPointer _metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
+ QByteArray _listPropertyAssignBehavior;
QString _defaultPropertyName;
- QQmlPropertyCacheMethodArguments *argumentsCache;
- int _jsFactoryMethodIndex;
- QByteArray _checksum;
-};
-
-typedef QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCachePtr;
-
-// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
-// This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
-// we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
-// QObject type used in assignment or when we don't have a QQmlEngine etc.
-//
-// This class does NOT reference the propertycache.
-class QQmlEnginePrivate;
-class Q_QML_EXPORT QQmlMetaObject
-{
-public:
- typedef QVarLengthArray<int, 9> ArgTypeStorage;
-
- inline QQmlMetaObject();
- inline QQmlMetaObject(QObject *);
- inline QQmlMetaObject(const QMetaObject *);
- inline QQmlMetaObject(QQmlPropertyCache *);
- inline QQmlMetaObject(const QQmlMetaObject &);
-
- inline QQmlMetaObject &operator=(const QQmlMetaObject &);
-
- inline bool isNull() const;
-
- inline const char *className() const;
- inline int propertyCount() const;
-
- inline bool hasMetaObject() const;
- inline const QMetaObject *metaObject() const;
-
- QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
-
- int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
-
- static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
-
- // static_metacall (on Gadgets) doesn't call the base implementation and therefore
- // we need a helper to find the correct meta object and property/method index.
- static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
-
-protected:
- QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
- int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
-
-};
-
-class QQmlObjectOrGadget: public QQmlMetaObject
-{
-public:
- QQmlObjectOrGadget(QObject *obj)
- : QQmlMetaObject(obj),
- ptr(obj)
- {}
- QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
- : QQmlMetaObject(propertyCache)
- , ptr(gadget)
- {}
-
- void metacall(QMetaObject::Call type, int index, void **argv) const;
-
-private:
- QBiPointer<QObject, void> ptr;
-
-protected:
- QQmlObjectOrGadget(const QMetaObject* metaObject)
- : QQmlMetaObject(metaObject)
- {}
-
+ QQmlPropertyCacheMethodArguments *argumentsCache = nullptr;
+ int methodIndexCacheStart = 0;
+ int signalHandlerIndexCacheStart = 0;
+ int _jsFactoryMethodIndex = -1;
};
-class QQmlStaticMetaObject : public QQmlObjectOrGadget {
-public:
- QQmlStaticMetaObject(const QMetaObject* metaObject)
- : QQmlObjectOrGadget(metaObject)
- {}
- int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
-};
-
-QQmlPropertyRawData::Flags::Flags()
- : _otherBits(0)
- , isConstant(false)
- , isWritable(false)
- , isResettable(false)
- , isAlias(false)
- , isFinal(false)
- , isOverridden(false)
- , isDirect(false)
- , type(OtherType)
- , isVMEFunction(false)
- , hasArguments(false)
- , isSignal(false)
- , isVMESignal(false)
- , isV4Function(false)
- , isSignalHandler(false)
- , isOverload(false)
- , isCloned(false)
- , isConstructor(false)
- , notFullyResolved(false)
- , overrideIndexIsProperty(false)
-{}
-
-bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const
-{
- return isConstant == other.isConstant &&
- isWritable == other.isWritable &&
- isResettable == other.isResettable &&
- isAlias == other.isAlias &&
- isFinal == other.isFinal &&
- isOverridden == other.isOverridden &&
- type == other.type &&
- isVMEFunction == other.isVMEFunction &&
- hasArguments == other.hasArguments &&
- isSignal == other.isSignal &&
- isVMESignal == other.isVMESignal &&
- isV4Function == other.isV4Function &&
- isSignalHandler == other.isSignalHandler &&
- isOverload == other.isOverload &&
- isCloned == other.isCloned &&
- isConstructor == other.isConstructor &&
- notFullyResolved == other.notFullyResolved &&
- overrideIndexIsProperty == other.overrideIndexIsProperty;
-}
-
-void QQmlPropertyRawData::Flags::copyPropertyTypeFlags(QQmlPropertyRawData::Flags from)
-{
- switch (from.type) {
- case QObjectDerivedType:
- case EnumType:
- case QListType:
- case QmlBindingType:
- case QJSValueType:
- case V4HandleType:
- case QVariantType:
- type = from.type;
- }
-}
-
-QQmlPropertyData::QQmlPropertyData()
-{
- setCoreIndex(-1);
- setPropType(0);
- setNotifyIndex(-1);
- setOverrideIndex(-1);
- setRevision(0);
- setMetaObjectOffset(-1);
- setArguments(nullptr);
- trySetStaticMetaCallFunction(nullptr, 0);
-}
-
-QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
-{
- *(static_cast<QQmlPropertyRawData *>(this)) = d;
-}
-
-bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
-{
- return flags() == other.flags() &&
- propType() == other.propType() &&
- coreIndex() == other.coreIndex() &&
- notifyIndex() == other.notifyIndex() &&
- revision() == other.revision();
-}
-
-inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
-{
- if (p && Q_UNLIKELY(p->notFullyResolved()))
- resolve(p);
-
- return p;
-}
-
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
inline const QMetaObject *QQmlPropertyCache::metaObject() const
{
- return _metaObject;
+ return _metaObject.metaObject();
}
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
// QML
inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
- while (_parent && (_metaObject == nullptr || _ownMetaObject))
- return _parent->firstCppMetaObject();
- return _metaObject;
+ const QQmlPropertyCache *p = this;
+ while (p->_metaObject.isShared())
+ p = p->parent().data();
+ return p->_metaObject.metaObject();
}
-inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
if (index < propertyIndexCacheStart)
return _parent->property(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- return ensureResolved(rv);
+ return &propertyIndexCache.at(index - propertyIndexCacheStart);
}
-inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::method(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return nullptr;
if (index < methodIndexCacheStart)
return _parent->method(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- return ensureResolved(rv);
+ return const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
}
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
-inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::signal(int index) const
{
- if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.size()))
return nullptr;
if (index < signalHandlerIndexCacheStart)
return _parent->signal(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ const QQmlPropertyData *rv = const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1);
- return ensureResolved(rv);
+ return rv;
}
inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
{
- if (index < 0 || index >= enumCache.count())
+ if (index < 0 || index >= enumCache.size())
return nullptr;
return const_cast<QQmlEnumData *>(&enumCache.at(index));
@@ -796,7 +378,7 @@ inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return index;
if (index < methodIndexCacheStart)
@@ -811,13 +393,13 @@ inline QString QQmlPropertyCache::defaultPropertyName() const
return _defaultPropertyName;
}
-inline QQmlPropertyCache *QQmlPropertyCache::parent() const
+inline const QQmlPropertyCache::ConstPtr &QQmlPropertyCache::parent() const
{
return _parent;
}
-QQmlPropertyData *
-QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
+const QQmlPropertyData *
+QQmlPropertyCache::overrideData(const QQmlPropertyData *data) const
{
if (!data->hasOverride())
return nullptr;
@@ -828,15 +410,30 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
return method(data->overrideIndex());
}
-bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
+bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const
{
- return (data->metaObjectOffset() == -1 && data->revision() == 0) ||
- (allowedRevisionCache[data->metaObjectOffset()] >= data->revision());
+ const QTypeRevision requested = data->revision();
+ const int offset = data->metaObjectOffset();
+ if (offset == -1 && requested == QTypeRevision::zero())
+ return true;
+
+ Q_ASSERT(offset >= 0);
+ Q_ASSERT(offset < allowedRevisionCache.size());
+ const QTypeRevision allowed = allowedRevisionCache[offset];
+
+ if (requested.hasMajorVersion()) {
+ if (requested.majorVersion() > allowed.majorVersion())
+ return false;
+ if (requested.majorVersion() < allowed.majorVersion())
+ return true;
+ }
+
+ return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion();
}
int QQmlPropertyCache::propertyCount() const
{
- return propertyIndexCacheStart + propertyIndexCache.count();
+ return propertyIndexCacheStart + int(propertyIndexCache.size());
}
int QQmlPropertyCache::propertyOffset() const
@@ -846,7 +443,7 @@ int QQmlPropertyCache::propertyOffset() const
int QQmlPropertyCache::methodCount() const
{
- return methodIndexCacheStart + methodIndexCache.count();
+ return methodIndexCacheStart + int(methodIndexCache.size());
}
int QQmlPropertyCache::methodOffset() const
@@ -856,7 +453,7 @@ int QQmlPropertyCache::methodOffset() const
int QQmlPropertyCache::signalCount() const
{
- return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
+ return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size());
}
int QQmlPropertyCache::signalOffset() const
@@ -866,138 +463,24 @@ int QQmlPropertyCache::signalOffset() const
int QQmlPropertyCache::qmlEnumCount() const
{
- return enumCache.count();
+ return int(enumCache.size());
}
bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
{
if (_jsFactoryMethodIndex != -1) {
- _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args);
- return true;
+ if (const QMetaObject *mo = _metaObject.metaObject()) {
+ mo->d.static_metacall(object, QMetaObject::InvokeMetaMethod,
+ _jsFactoryMethodIndex, args);
+ return true;
+ }
+ return false;
}
if (_parent)
return _parent->callJSFactoryMethod(object, args);
return false;
}
-QQmlMetaObject::QQmlMetaObject()
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(QObject *o)
-{
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
- else _m = o->metaObject();
- }
-}
-
-QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
-: _m(m)
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
-: _m(m)
-{
-}
-
-QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
-: _m(o._m)
-{
-}
-
-QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
-{
- _m = o._m;
- return *this;
-}
-
-bool QQmlMetaObject::isNull() const
-{
- return _m.isNull();
-}
-
-const char *QQmlMetaObject::className() const
-{
- if (_m.isNull()) {
- return nullptr;
- } else if (_m.isT1()) {
- return _m.asT1()->className();
- } else {
- return _m.asT2()->className();
- }
-}
-
-int QQmlMetaObject::propertyCount() const
-{
- if (_m.isNull()) {
- return 0;
- } else if (_m.isT1()) {
- return _m.asT1()->propertyCount();
- } else {
- return _m.asT2()->propertyCount();
- }
-}
-
-bool QQmlMetaObject::hasMetaObject() const
-{
- return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
-}
-
-const QMetaObject *QQmlMetaObject::metaObject() const
-{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1()->createMetaObject();
- else return _m.asT2();
-}
-
-class QQmlPropertyCacheVector
-{
-public:
- QQmlPropertyCacheVector() {}
- QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
- : data(std::move(other.data)) {}
- QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
- QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
- data.swap(moved);
- return *this;
- }
-
- ~QQmlPropertyCacheVector() { clear(); }
- void resize(int size) { return data.resize(size); }
- int count() const { return data.count(); }
- void clear()
- {
- for (int i = 0; i < data.count(); ++i) {
- if (QQmlPropertyCache *cache = data.at(i).data())
- cache->release();
- }
- data.clear();
- }
-
- void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
- QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
- void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
- if (QQmlPropertyCache *oldCache = data.at(index).data()) {
- if (replacement.data() == oldCache)
- return;
- oldCache->release();
- }
- data[index] = replacement.data();
- replacement->addref();
- }
-
- void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
- bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
-private:
- Q_DISABLE_COPY(QQmlPropertyCacheVector)
- QVector<QFlagPointer<QQmlPropertyCache>> data;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
-
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHE_P_H