aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-21 16:32:01 +0100
committerUlf Hermann <ulf.hermann@qt.io>2023-02-15 09:13:45 +0100
commit4501cda657a989adb550a2a92ff4387e2274d7b7 (patch)
tree6856c48ea30e84460f0be24e5e1b682d473e554b
parent291d3ed0da263103ca2d612eb2f470ee160e8fb6 (diff)
Repair QQmlGadgetPtrWrapper's metaObject
We need two metaobjects: One with the PropertyAccessInStaticMetaCall flagg and one without. The one without needs to be used with QQmlGadgetPtrWrapper, since the wrapper wants to intercept metacalls. The other one needs to be used when calling readOnGadget(). We can accommodate this by just retaining the original metaobject. As it's retrieved from a gadget type you should definitely be able to readOnGadget() with it. The dynamic meta object, on the other hand, can be lazily created when we actually metacall() through QQmlGadgetPtrWrapper. This relieves us of all the special casing around QQmlGadgetPtrWrapper and makes it safe to use for anyone. Fixes: QTBUG-108704 Fixes: QTBUG-111136 Fixes: QTBUG-111019 Change-Id: Icc01c81babaa9d1eca8d5ddfaf44d724a404db38 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit c4f0d07bda41ea3ea083d17c56e67a3b05a532bb) Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp5
-rw-r--r--src/qml/qml/qqmlbinding.cpp2
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp34
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h38
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp36
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp2
7 files changed, 60 insertions, 65 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 578b07cb22..1fcc1e7772 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -147,8 +147,7 @@ QQmlEngineDebugServiceImpl::propertyData(QObject *obj, int propIdx)
{
QQmlObjectProperty rv;
- const QMetaObject *metaObject = obj->metaObject();
- QMetaProperty prop = metaObject->property(propIdx);
+ QMetaProperty prop = obj->metaObject()->property(propIdx);
rv.type = QQmlObjectProperty::Unknown;
rv.valueTypeName = QString::fromUtf8(prop.typeName());
@@ -159,10 +158,7 @@ QQmlEngineDebugServiceImpl::propertyData(QObject *obj, int propIdx)
if (binding)
rv.binding = binding->expression();
- if (metaObject->metaType().flags().testFlag(QMetaType::IsGadget))
- rv.value = valueContents(static_cast<QQmlGadgetPtrWrapper *>(obj)->readOnGadget(prop));
- else
- rv.value = valueContents(prop.read(obj));
+ rv.value = valueContents(prop.read(obj));
if (prop.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
rv.type = QQmlObjectProperty::Object;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
index 7a7d2f37b4..d72c11d439 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
@@ -40,7 +40,6 @@ private:
int m_id;
QQmlWatcher *m_watch;
QObject *m_object;
- bool m_isGadget;
int m_debugId;
QMetaProperty m_property;
@@ -52,7 +51,6 @@ QQmlWatchProxy::QQmlWatchProxy(int id, QQmlExpression *exp, int debugId, QQmlWat
m_id(id),
m_watch(parent),
m_object(nullptr),
- m_isGadget(false),
m_debugId(debugId),
m_expr(exp)
{
@@ -66,7 +64,6 @@ QQmlWatchProxy::QQmlWatchProxy(int id, QObject *object, int debugId, const QMeta
m_id(id),
m_watch(parent),
m_object(object),
- m_isGadget(typeid(*m_object) == typeid(QQmlGadgetPtrWrapper)),
m_debugId(debugId),
m_property(prop),
m_expr(nullptr)
@@ -84,8 +81,6 @@ void QQmlWatchProxy::notifyValueChanged()
QVariant v;
if (m_expr)
v = m_expr->evaluate();
- else if (m_isGadget)
- v = static_cast<QQmlGadgetPtrWrapper *>(m_object)->readOnGadget(m_property);
else
v = m_property.read(m_object);
emit m_watch->propertyChanged(m_id, m_debugId, m_property, v);
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 49a72c17e9..10a9e60819 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -339,7 +339,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType()->metaType == pd->propType()) {
+ if (vtw->d()->valueType()->metaType() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 7365255935..8cb18104b6 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -11,20 +11,9 @@
QT_BEGIN_NAMESPACE
-QQmlValueType::QQmlValueType(QMetaType type, const QMetaObject *gadgetMetaObject)
- : metaType(type)
-{
- QMetaObjectBuilder builder(gadgetMetaObject);
-
- // This is required for calling readOnGadget() on properties from this metaObject.
- builder.setFlags(PropertyAccessInStaticMetaCall);
-
- dynamicMetaObject = builder.toMetaObject();
-}
-
QQmlValueType::~QQmlValueType()
{
- ::free(dynamicMetaObject);
+ ::free(m_dynamicMetaObject);
}
QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, QMetaType type)
@@ -54,7 +43,7 @@ void QQmlGadgetPtrWrapper::read(QObject *obj, int idx)
QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
+void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) const
{
Q_ASSERT(m_gadgetPtr);
int status = -1;
@@ -62,16 +51,16 @@ void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteF
QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
}
-QVariant QQmlGadgetPtrWrapper::value()
+QVariant QQmlGadgetPtrWrapper::value() const
{
Q_ASSERT(m_gadgetPtr);
- return QVariant(QMetaType(metaTypeId()), m_gadgetPtr);
+ return QVariant(metaType(), m_gadgetPtr);
}
void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
{
Q_ASSERT(m_gadgetPtr);
- Q_ASSERT(metaTypeId() == value.userType());
+ Q_ASSERT(metaType() == value.metaType());
const QQmlValueType *type = valueType();
type->destruct(m_gadgetPtr);
type->construct(m_gadgetPtr, value.constData());
@@ -80,7 +69,7 @@ void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv)
{
Q_ASSERT(m_gadgetPtr);
- const QMetaObject *metaObject = valueType()->metaObject();
+ const QMetaObject *metaObject = valueType()->staticMetaObject();
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id);
metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv);
return id;
@@ -94,7 +83,16 @@ const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const
QMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
{
- return dynamicMetaObject;
+ if (!m_dynamicMetaObject) {
+ QMetaObjectBuilder builder(m_staticMetaObject);
+
+ // Do not set PropertyAccessInStaticMetaCall here. QQmlGadgetPtrWrapper likes to
+ // to intercept the metacalls since it needs to use its gadgetPtr.
+ // For QQmlValueType::metaObject() we use the base type that has the flag.
+
+ m_dynamicMetaObject = builder.toMetaObject();
+ }
+ return m_dynamicMetaObject;
}
void QQmlValueType::objectDestroyed(QObject *)
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 6b7df3f1b9..5376130b0f 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -34,18 +34,20 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlValueType : public QDynamicMetaObjectData
{
public:
- QQmlValueType() : metaType(QMetaType::UnknownType) {}
- QQmlValueType(QMetaType type, const QMetaObject *metaObject);
+ QQmlValueType() = default;
+ QQmlValueType(QMetaType type, const QMetaObject *staticMetaObject)
+ : m_metaType(type), m_staticMetaObject(staticMetaObject)
+ {}
~QQmlValueType();
- void *create() const { return metaType.create(); }
- void destroy(void *gadgetPtr) const { metaType.destroy(gadgetPtr); }
+ void *create() const { return m_metaType.create(); }
+ void destroy(void *gadgetPtr) const { m_metaType.destroy(gadgetPtr); }
- void construct(void *gadgetPtr, const void *copy) const { metaType.construct(gadgetPtr, copy); }
- void destruct(void *gadgetPtr) const { metaType.destruct(gadgetPtr); }
+ void construct(void *gadgetPtr, const void *copy) const { m_metaType.construct(gadgetPtr, copy); }
+ void destruct(void *gadgetPtr) const { m_metaType.destruct(gadgetPtr); }
- int metaTypeId() const { return metaType.id(); }
- const QMetaObject *metaObject() const { return dynamicMetaObject; }
+ QMetaType metaType() const { return m_metaType; }
+ const QMetaObject *staticMetaObject() const { return m_staticMetaObject; }
// ---- dynamic meta object data interface
QMetaObject *toDynamicMetaObject(QObject *) override;
@@ -53,9 +55,10 @@ public:
int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override;
// ----
-public:
- QMetaType metaType;
- QMetaObject *dynamicMetaObject = nullptr;
+private:
+ QMetaType m_metaType;
+ const QMetaObject *m_staticMetaObject = nullptr;
+ QMetaObject *m_dynamicMetaObject = nullptr;
};
class Q_QML_PRIVATE_EXPORT QQmlGadgetPtrWrapper : public QObject
@@ -68,14 +71,18 @@ public:
~QQmlGadgetPtrWrapper();
void read(QObject *obj, int idx);
- void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags);
- QVariant value();
+ void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) const;
+ QVariant value() const;
void setValue(const QVariant &value);
- int metaTypeId() const { return valueType()->metaTypeId(); }
+ QMetaType metaType() const { return valueType()->metaType(); }
int metaCall(QMetaObject::Call type, int id, void **argv);
- QMetaProperty property(int index) { return valueType()->metaObject()->property(index); }
+ QMetaProperty property(int index) const
+ {
+ return valueType()->staticMetaObject()->property(index);
+ }
+
QVariant readOnGadget(const QMetaProperty &property) const
{
return property.readOnGadget(m_gadgetPtr);
@@ -88,7 +95,6 @@ public:
private:
const QQmlValueType *valueType() const;
-
void *m_gadgetPtr = nullptr;
};
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 34de9faef9..d088d5e411 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -35,7 +35,7 @@ using namespace QV4;
void Heap::QQmlValueTypeWrapper::destroy()
{
if (m_gadgetPtr) {
- m_valueType->metaType.destruct(m_gadgetPtr);
+ m_valueType->metaType().destruct(m_gadgetPtr);
::operator delete(m_gadgetPtr);
}
Object::destroy();
@@ -44,22 +44,22 @@ void Heap::QQmlValueTypeWrapper::destroy()
void Heap::QQmlValueTypeWrapper::setData(const void *data) const
{
if (auto *gadget = gadgetPtr())
- valueType()->metaType.destruct(gadget);
+ valueType()->metaType().destruct(gadget);
if (!gadgetPtr())
- setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
- valueType()->metaType.construct(gadgetPtr(), data);
+ setGadgetPtr(::operator new(valueType()->metaType().sizeOf()));
+ valueType()->metaType().construct(gadgetPtr(), data);
}
void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
{
- Q_ASSERT(valueType()->metaType.id() == value.userType());
+ Q_ASSERT(valueType()->metaType().id() == value.userType());
setData(value.constData());
}
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
Q_ASSERT(gadgetPtr());
- return QVariant(valueType()->metaType, gadgetPtr());
+ return QVariant(valueType()->metaType(), gadgetPtr());
}
@@ -86,7 +86,7 @@ bool QQmlValueTypeReference::readReferenceValue() const
if (QQmlMetaType::isValueType(variantReferenceType)) {
const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(variantReferenceType);
if (d()->gadgetPtr()) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->valueType()->metaType().destruct(d()->gadgetPtr());
::operator delete(d()->gadgetPtr());
}
d()->setGadgetPtr(nullptr);
@@ -101,8 +101,8 @@ bool QQmlValueTypeReference::readReferenceValue() const
d()->setValue(variantReferenceValue);
} else {
if (!d()->gadgetPtr()) {
- d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
+ d()->setGadgetPtr(::operator new(d()->valueType()->metaType().sizeOf()));
+ d()->valueType()->metaType().construct(d()->gadgetPtr(), nullptr);
}
// value-type reference
void *args[] = { d()->gadgetPtr(), nullptr };
@@ -145,7 +145,7 @@ ReturnedValue QQmlValueTypeWrapper::create(
ExecutionEngine *engine, const QVariant &value, const QMetaObject *metaObject,
QMetaType type)
{
- Q_ASSERT(value.metaType() == QQmlMetaType::valueType(type)->metaType);
+ Q_ASSERT(value.metaType() == QQmlMetaType::valueType(type)->metaType());
return create(engine, value.constData(), metaObject, type);
}
@@ -181,7 +181,7 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
if (!ref->readReferenceValue())
return false;
- const QMetaType type = d()->valueType()->metaType;
+ const QMetaType type = d()->valueType()->metaType();
type.destruct(data);
type.construct(data, d()->gadgetPtr());
return true;
@@ -367,12 +367,12 @@ bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType()->metaType.id();
+ return d()->valueType()->metaType().id();
}
QMetaType QQmlValueTypeWrapper::type() const
{
- return d()->valueType()->metaType;
+ return d()->valueType()->metaType();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
@@ -381,9 +381,9 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
Q_ALLOCA_DECLARE(void, gadget);
if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
if (!d()->gadgetPtr()) {
- Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
+ Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType().sizeOf());
d()->setGadgetPtr(gadget);
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
+ d()->valueType()->metaType().construct(d()->gadgetPtr(), nullptr);
destructGadgetOnExit = true;
}
if (!ref->readReferenceValue())
@@ -396,7 +396,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
if (destructGadgetOnExit) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->valueType()->metaType().destruct(d()->gadgetPtr());
d()->setGadgetPtr(nullptr);
}
return true;
@@ -434,9 +434,9 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
RETURN_UNDEFINED();
QString result;
- if (!QMetaType::convert(w->d()->valueType()->metaType, w->d()->gadgetPtr(),
+ if (!QMetaType::convert(w->d()->valueType()->metaType(), w->d()->gadgetPtr(),
QMetaType(QMetaType::QString), &result)) {
- result = QString::fromUtf8(w->d()->valueType()->metaType.name()) + QLatin1Char('(');
+ result = QString::fromUtf8(w->d()->valueType()->metaType().name()) + QLatin1Char('(');
const QMetaObject *mo = w->d()->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index 1687adb284..1f275ded5a 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -656,7 +656,7 @@ public:
// NB: This acquires the lock on QQmlMetaTypeData. If we had a QQmlEngine here,
// we could use QQmlGadgetPtrWrapper::instance() to avoid this.
if (const QQmlValueType *valueType = QQmlMetaType::valueType(type))
- metaObject = valueType->metaObject();
+ metaObject = valueType->staticMetaObject();
else
return QVariant();
}