aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4engine.cpp10
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp8
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp22
-rw-r--r--src/qml/qml/qqmlglobal.cpp280
-rw-r--r--src/qml/qml/qqmlglobal_p.h10
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp19
-rw-r--r--src/qml/qml/qqmlproperty.cpp15
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp6
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp4
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp4
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/testtypes.h130
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp67
12 files changed, 416 insertions, 159 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 56cc4efb48..41c7a90906 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1569,9 +1569,9 @@ static QVariant toVariant(
QV4::ScopedValue arrayValue(scope);
for (qint64 i = 0; i < length; ++i) {
arrayValue = a->get(i);
- QVariant asVariant(valueMetaType);
- if (QQmlValueTypeProvider::createValueType(
- arrayValue, valueMetaType, asVariant.data())) {
+ QVariant asVariant = QQmlValueTypeProvider::createValueType(
+ arrayValue, valueMetaType);
+ if (asVariant.isValid()) {
retnAsIterable.metaContainer().addValue(retn.data(), asVariant.constData());
continue;
}
@@ -1662,8 +1662,8 @@ static QVariant toVariant(
#endif
if (metaType.isValid() && !(metaType.flags() & QMetaType::PointerToQObject)) {
- QVariant result(metaType);
- if (QQmlValueTypeProvider::createValueType(value, metaType, result.data()))
+ const QVariant result = QQmlValueTypeProvider::createValueType(value, metaType);
+ if (result.isValid())
return result;
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 132084705c..d33466a7fa 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -714,9 +714,9 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
} else {
const QMetaType originalType = variant.metaType();
if (originalType != valueMetaType) {
- QVariant converted(valueMetaType);
- if (QQmlValueTypeProvider::createValueType(
- variant, valueMetaType, converted.data())) {
+ const QVariant converted = QQmlValueTypeProvider::createValueType(
+ variant, valueMetaType);
+ if (converted.isValid()) {
variant = converted;
} else if (!variant.convert(valueMetaType)) {
qWarning().noquote()
@@ -725,7 +725,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
.arg(QString::number(i),
QString::fromUtf8(originalType.name()),
QString::fromUtf8(valueMetaType.name()));
- variant = converted;
+ variant = QVariant(valueMetaType);
}
}
meta->addValueAtEnd(result.data(), variant.constData());
diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index 36111f32a6..9d75073e84 100644
--- a/src/qml/qml/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -475,8 +475,9 @@ QVariant QtObject::font(const QJSValue &fontSpecifier) const
}
{
- QVariant v((QMetaType(QMetaType::QFont)));
- if (QQmlValueTypeProvider::constructFromJSValue(fontSpecifier, v.metaType(), v.data()))
+ const QVariant v = QQmlValueTypeProvider::createValueType(
+ fontSpecifier, QMetaType(QMetaType::QFont));
+ if (v.isValid())
return v;
}
@@ -511,9 +512,8 @@ static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... paramete
return QVariant();
QJSValue params = e->newArray(sizeof...(parameters));
addParameters(e, params, 0, parameters...);
- QVariant variant(type);
- QQmlValueTypeProvider::constructFromJSValue(params, type, variant.data());
- return variant;
+ const QVariant variant = QQmlValueTypeProvider::createValueType(params, type);
+ return variant.isValid() ? variant : QVariant(type);
}
/*!
@@ -563,10 +563,9 @@ QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
*/
QVariant QtObject::matrix4x4() const
{
- QVariant variant((QMetaType(QMetaType::QMatrix4x4)));
- QQmlValueTypeProvider::constructFromJSValue(
- QJSValue(), variant.metaType(), variant.data());
- return variant;
+ const QMetaType metaType(QMetaType::QMatrix4x4);
+ const QVariant variant = QQmlValueTypeProvider::createValueType(QJSValue(), metaType);
+ return variant.isValid() ? variant : QVariant(metaType);
}
/*!
@@ -587,8 +586,9 @@ QVariant QtObject::matrix4x4() const
QVariant QtObject::matrix4x4(const QJSValue &value) const
{
if (value.isObject()) {
- QVariant v((QMetaType(QMetaType::QMatrix4x4)));
- if (QQmlValueTypeProvider::constructFromJSValue(value, v.metaType(), v.data()))
+ QVariant v = QQmlValueTypeProvider::createValueType(
+ value, QMetaType(QMetaType::QMatrix4x4));
+ if (v.isValid())
return v;
}
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 265b26b1e0..90889c2ea4 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -1,15 +1,15 @@
// 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 <private/qqmlglobal_p.h>
-#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/private/qjsvalue_p.h>
-
+#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/qqmlengine.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qstringlist.h>
+
+#include <QtCore/private/qvariant_p.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
-#include <QtCore/QCoreApplication>
+#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
@@ -70,21 +70,32 @@ static bool isConstructibleMetaType(const QMetaType metaType)
return true;
}
+static void *createVariantData(QMetaType type, QVariant *variant)
+{
+ const QtPrivate::QMetaTypeInterface *iface = type.iface();
+ QVariant::Private *d = &variant->data_ptr();
+ Q_ASSERT(d->is_null && !d->is_shared);
+ *d = QVariant::Private(iface);
+ if (QVariant::Private::canUseInternalSpace(iface))
+ return d->data.data;
+
+ // This is not exception safe.
+ // If your value type throws an exception from its ctor bad things will happen anyway.
+ d->data.shared = QVariant::PrivateShared::create(iface->size, iface->alignment);
+ d->is_shared = true;
+ return d->data.shared->data();
+}
+
static void callConstructor(
- const QMetaObject *mo, int i, void *parameter, QMetaType metaType, void *data)
+ const QMetaObject *mo, int i, void *parameter, void *data)
{
- // Unfortunately CreateInstance unconditionally creates the instance on the heap.
- void *gadget = nullptr;
- void *p[] = { &gadget, parameter };
- mo->static_metacall(QMetaObject::CreateInstance, i, p);
- Q_ASSERT(gadget);
- metaType.destruct(data);
- metaType.construct(data, gadget);
- metaType.destroy(gadget);
+ void *p[] = { data, parameter };
+ mo->static_metacall(QMetaObject::ConstructInPlace, i, p);
}
+template<typename Allocate>
static bool fromMatchingType(
- const QMetaObject *mo, const QV4::Value &s, const QMetaType metaType, void *data)
+ const QMetaObject *mo, const QV4::Value &s, Allocate &&allocate)
{
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
const QMetaMethod ctor = mo->constructor(i);
@@ -94,19 +105,19 @@ static bool fromMatchingType(
const QMetaType parameterType = ctor.parameterMetaType(0);
QVariant parameter = QV4::ExecutionEngine::toVariant(s, parameterType);
if (parameter.metaType() == parameterType) {
- callConstructor(mo, i, parameter.data(), metaType, data);
+ callConstructor(mo, i, parameter.data(), allocate());
return true;
}
- QVariant converted(parameterType);
- if (QQmlValueTypeProvider::createValueType(s, parameterType, converted.data())) {
- callConstructor(mo, i, converted.data(), metaType, data);
+ QVariant converted = QQmlValueTypeProvider::createValueType(s, parameterType);
+ if (converted.isValid()) {
+ callConstructor(mo, i, converted.data(), allocate());
return true;
}
if (QMetaType::convert(parameter.metaType(), parameter.constData(),
parameterType, converted.data())) {
- callConstructor(mo, i, converted.data(), metaType, data);
+ callConstructor(mo, i, converted.data(), allocate());
return true;
}
}
@@ -114,14 +125,14 @@ static bool fromMatchingType(
return false;
}
-static bool fromMatchingType(
- const QMetaObject *mo, QVariant s, const QMetaType metaType, void *data)
+template<typename Allocate>
+static bool fromMatchingType(const QMetaObject *mo, QVariant s, Allocate &&allocate)
{
const QMetaType sourceMetaType = s.metaType();
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
QJSValue val = s.value<QJSValue>();
- return fromMatchingType(
- mo, QV4::Value(QJSValuePrivate::asReturnedValue(&val)), metaType, data);
+ return fromMatchingType(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&val)),
+ std::forward<Allocate>(allocate));
}
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
@@ -131,20 +142,20 @@ static bool fromMatchingType(
const QMetaType parameterType = ctor.parameterMetaType(0);
if (sourceMetaType == parameterType) {
- callConstructor(mo, i, s.data(), metaType, data);
+ callConstructor(mo, i, s.data(), allocate());
return true;
}
- QVariant parameter(parameterType);
- if (QQmlValueTypeProvider::createValueType(s, parameterType, parameter.data())) {
- callConstructor(mo, i, parameter.data(), metaType, data);
+ QVariant parameter = QQmlValueTypeProvider::createValueType(s, parameterType);
+ if (parameter.isValid()) {
+ callConstructor(mo, i, parameter.data(), allocate());
return true;
}
// At this point, s should be a builtin type. For builtin types
// the QMetaType converters are good enough.
if (QMetaType::convert(sourceMetaType, s.constData(), parameterType, parameter.data())) {
- callConstructor(mo, i, parameter.data(), metaType, data);
+ callConstructor(mo, i, parameter.data(), allocate());
return true;
}
}
@@ -152,8 +163,8 @@ static bool fromMatchingType(
return false;
}
-static bool fromString(
- const QMetaObject *mo, QString s, const QMetaType metaType, void *data)
+template<typename Allocate>
+static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
{
for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
const QMetaMethod ctor = mo->constructor(i);
@@ -161,24 +172,16 @@ static bool fromString(
continue;
if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
- callConstructor(mo, i, &s, metaType, data);
+ callConstructor(mo, i, &s, allocate());
return true;
}
}
-
return false;
}
-static bool byProperties(
- const QMetaObject *mo, const QV4::Value &s, void *data)
+static void doWriteProperties(const QMetaObject *mo, const QV4::Value &s, void *target)
{
- if (!s.isObject())
- return false;
-
- if (!mo)
- return false;
-
const QV4::Object *o = static_cast<const QV4::Object *>(&s);
QV4::Scope scope(o->engine());
QV4::ScopedObject object(scope, o);
@@ -198,19 +201,20 @@ static bool byProperties(
const QMetaType propertyType = metaProperty.metaType();
QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
if (property.metaType() == propertyType) {
- metaProperty.writeOnGadget(data, property);
+ metaProperty.writeOnGadget(target, property);
continue;
}
- QVariant converted(propertyType);
- if (QQmlValueTypeProvider::createValueType(v4PropValue, propertyType, converted.data())) {
- metaProperty.writeOnGadget(data, converted);
+ QVariant converted = QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, converted);
continue;
}
+ converted = QVariant(propertyType);
if (QMetaType::convert(property.metaType(), property.constData(),
propertyType, converted.data())) {
- metaProperty.writeOnGadget(data, converted);
+ metaProperty.writeOnGadget(target, converted);
continue;
}
@@ -219,31 +223,75 @@ static bool byProperties(
.arg(v4PropValue->toQStringNoThrow(), QString::fromUtf8(propertyType.name()),
propertyName);
}
- return true;
}
-static bool byProperties(
- const QMetaObject *mo, const QVariant &s, void *data)
+static QVariant byProperties(const QMetaObject *mo, QMetaType metaType, const QV4::Value &s)
{
- if (!mo)
- return false;
+ if (!s.isObject() || !mo)
+ return QVariant();
- if (s.metaType() == QMetaType::fromType<QJSValue>()) {
- QJSValue val = s.value<QJSValue>();
- return byProperties(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&val)), data);
- }
+ QVariant result(metaType);
+ doWriteProperties(mo, s, result.data());
+ return result;
+}
- return false;
+static QVariant byProperties(const QMetaObject *mo, QMetaType metaType, const QVariant &s)
+{
+ if (!mo || s.metaType() != QMetaType::fromType<QJSValue>())
+ return QVariant();
+
+ QJSValue val = s.value<QJSValue>();
+ return byProperties(mo, metaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
}
-static bool fromJSValue(
- const QQmlType &type, const QJSValue &s, QMetaType metaType, void *data)
+/*!
+ * \internal
+ * Specialization that creates the value type in place at \a target, which is expected to be
+ * already initialized. This is more efficient if we can do byProperties() since it can use a
+ * pre-constructed object. It also avoids the creation of a QVariant in most cases. It is less
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType, void *target)
{
+ if (!isConstructibleMetaType(metaType))
+ return false;
+
+ auto destruct = [metaType, target]() {
+ metaType.destruct(target);
+ return target;
+ };
+
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
+ const auto warn = [&]() {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << mo->className() << "to call with value" << s.toQStringNoThrow();
+ };
+
+ if (type.canPopulateValueType()) {
+ if (s.isObject() && mo) {
+ doWriteProperties(mo, s, target);
+ return true;
+ }
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, destruct))
+ return true;
+ warn();
+
+ }
+ } else if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, destruct))
+ return true;
+ warn();
+ }
+ }
+
if (const auto valueTypeFunction = type.createValueTypeFunction()) {
- QVariant result = valueTypeFunction(s);
+ const QVariant result
+ = valueTypeFunction(QJSValuePrivate::fromReturnedValue(s.asReturnedValue()));
if (result.metaType() == metaType) {
- metaType.destruct(data);
- metaType.construct(data, result.constData());
+ metaType.construct(destruct(), result.constData());
return true;
}
}
@@ -251,70 +299,69 @@ static bool fromJSValue(
return false;
}
-bool QQmlValueTypeProvider::constructFromJSValue(
- const QJSValue &s, QMetaType metaType, void *data)
+static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
{
- return isConstructibleMetaType(metaType)
- && fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType, data);
+ if (const auto valueTypeFunction = type.createValueTypeFunction()) {
+ const QVariant result = valueTypeFunction(s);
+ if (result.metaType() == metaType)
+ return result;
+ }
+
+ return QVariant();
}
-bool QQmlValueTypeProvider::createValueType(
- const QString &s, QMetaType metaType, void *data)
+QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
{
if (!isConstructibleMetaType(metaType))
- return false;
- const QQmlType type = QQmlMetaType::qmlType(metaType);
- const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type);
- if (mo && type.canConstructValueType()) {
- if (fromString(mo, s, metaType, data))
- return true;
- }
-
- return fromJSValue(type, s, metaType, data);
+ return QVariant();
+ return fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType);
}
-bool QQmlValueTypeProvider::createValueType(
- const QJSValue &s, QMetaType metaType, void *data)
+QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType)
{
if (!isConstructibleMetaType(metaType))
- return false;
+ return QVariant();
const QQmlType type = QQmlMetaType::qmlType(metaType);
- if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
- if (type.canPopulateValueType()
- && byProperties(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&s)), data)) {
- return true;
- }
-
- if (type.canConstructValueType()
- && fromMatchingType(mo, QV4::Value(QJSValuePrivate::asReturnedValue(&s)),
- metaType, data)) {
- return true;
- }
+ const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type);
+ if (mo && type.canConstructValueType()) {
+ QVariant result;
+ if (fromString(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
}
- return fromJSValue(type, s, metaType, data);
+ return fromJSValue(type, s, metaType);
}
-bool QQmlValueTypeProvider::createValueType(
- const QV4::Value &s, QMetaType metaType, void *data)
+QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType)
{
if (!isConstructibleMetaType(metaType))
- return false;
+ return QVariant();
const QQmlType type = QQmlMetaType::qmlType(metaType);
if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
- if (type.canPopulateValueType() && byProperties(mo, s, data))
- return true;
- if (type.canConstructValueType()) {
- if (fromMatchingType(mo, s, metaType, data))
- return true;
+ const auto warn = [&]() {
qWarning().noquote()
<< "Could not find any constructor for value type"
<< mo->className() << "to call with value" << s.toQStringNoThrow();
+ };
+
+ if (type.canPopulateValueType()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn();
+ }
+ } else if (type.canConstructValueType()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn();
}
}
- return fromJSValue(
- type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType, data);
+ return fromJSValue(type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType);
}
@@ -322,25 +369,36 @@ bool QQmlValueTypeProvider::createValueType(
* \internal
* This should only be called with either builtin types or wrapped QJSValues as source.
*/
-bool QQmlValueTypeProvider::createValueType(
- const QVariant &s, QMetaType metaType, void *data)
+QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType metaType)
{
if (!isConstructibleMetaType(metaType))
- return false;
+ return QVariant();
const QQmlType type = QQmlMetaType::qmlType(metaType);
if (const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(type)) {
- if (type.canPopulateValueType() && byProperties(mo, s, data))
- return true;
- if (type.canConstructValueType()) {
- if (fromMatchingType(mo, s, metaType, data))
- return true;
+ const auto warn = [&]() {
qWarning().noquote()
<< "Could not find any constructor for value type"
<< mo->className() << "to call with value" << s;
+ };
+
+ if (type.canPopulateValueType()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn();
+ }
+ } else if (type.canConstructValueType()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn();
}
}
- return false;
+ return QVariant();
}
QQmlColorProvider::~QQmlColorProvider() {}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 918f95993f..e56ae73edc 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -189,12 +189,12 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
class QQmlValueTypeProvider
{
public:
- static bool constructFromJSValue(const QJSValue &, QMetaType, void *);
-
- static bool createValueType(const QString &, QMetaType, void *);
- static bool createValueType(const QJSValue &, QMetaType, void *);
static bool createValueType(const QV4::Value &, QMetaType, void *);
- static bool createValueType(const QVariant &, QMetaType, void *);
+
+ static QVariant createValueType(const QJSValue &, QMetaType);
+ static QVariant createValueType(const QString &, QMetaType);
+ static QVariant createValueType(const QV4::Value &, QMetaType);
+ static QVariant createValueType(const QVariant &, QMetaType);
};
class Q_QML_PRIVATE_EXPORT QQmlColorProvider
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index c014c24d43..46fe25b1ba 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -426,9 +426,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
break;
case QMetaType::QColor: {
- QVariant data(propertyType);
- if (QQmlValueTypeProvider::createValueType(
- compilationUnit->bindingValueAsString(binding), propertyType, data.data())) {
+ QVariant data = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ if (data.isValid()) {
property->writeProperty(_qobject, data.data(), propertyWriteFlags);
}
}
@@ -509,12 +509,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QMetaType::QVector3D:
case QMetaType::QVector4D:
case QMetaType::QQuaternion: {
- QVariant result(propertyType);
- bool ok = QQmlValueTypeProvider::createValueType(
- compilationUnit->bindingValueAsString(binding),
- result.metaType(), result.data());
- assertOrNull(ok);
- Q_UNUSED(ok);
+ QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ assertOrNull(result.isValid());
property->writeProperty(_qobject, result.data(), propertyWriteFlags);
break;
}
@@ -602,8 +599,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
- QVariant target(propertyType);
- if (QQmlValueTypeProvider::createValueType(source, propertyType, target.data())) {
+ QVariant target = QQmlValueTypeProvider::createValueType(source, propertyType);
+ if (target.isValid()) {
property->writeProperty(_qobject, target.data(), propertyWriteFlags);
break;
}
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 306f733e21..3c039ba55d 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1423,14 +1423,15 @@ static ConvertAndAssignResult tryConvertAndAssign(
}
}
- QVariant converted(propertyMetaType);
- if (QQmlValueTypeProvider::createValueType(value, propertyMetaType, converted.data())
- || QMetaType::convert(value.metaType(), value.constData(),
- propertyMetaType, converted.data())) {
- return {true, property.writeProperty(object, converted.data(), flags)};
+ QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
+ if (!converted.isValid()) {
+ converted = QVariant(propertyMetaType);
+ if (!QMetaType::convert(value.metaType(), value.constData(),
+ propertyMetaType, converted.data())) {
+ return {false, false};
+ }
}
-
- return {false, false};
+ return {true, property.writeProperty(object, converted.data(), flags)};
};
template<typename Op>
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index c6783842dc..308b66e2d9 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -568,10 +568,10 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(
default: return QString();
}
};
- QVariant result(property->propType());
- if (!QQmlValueTypeProvider::createValueType(
+ const QVariant result = QQmlValueTypeProvider::createValueType(
compilationUnit->bindingValueAsString(binding),
- result.metaType(), result.data())) {
+ property->propType());
+ if (!result.isValid()) {
return warnOrError(tr("Invalid property assignment: %1 expected")
.arg(typeName()));
}
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
index c1625b6667..d2222dc338 100644
--- a/src/qml/qml/qqmlstringconverters.cpp
+++ b/src/qml/qml/qqmlstringconverters.cpp
@@ -40,8 +40,8 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, QMetaType pre
case QMetaType::QRect:
return QVariant::fromValue(rectFFromString(s, ok).toRect());
default: {
- QVariant ret(preferredType);
- if (QQmlValueTypeProvider::createValueType(s, preferredType, ret.data())) {
+ const QVariant ret = QQmlValueTypeProvider::createValueType(s, preferredType);
+ if (ret.isValid()) {
if (ok)
*ok = true;
return ret;
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp
index 1746957872..7569556121 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.cpp
@@ -2,10 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "testtypes.h"
+QList<Padding::LogEntry> Padding::log;
+
void registerTypes()
{
qmlRegisterType<MyTypeObject>("Test", 1, 0, "MyTypeObject");
qmlRegisterTypesAndRevisions<ConstructibleValueType>("Test", 1);
qmlRegisterTypesAndRevisions<ConstructibleFromQReal>("Test", 1);
qmlRegisterTypesAndRevisions<StructuredValueType>("Test", 1);
+ qmlRegisterTypesAndRevisions<Padding>("Test", 1);
+ qmlRegisterTypesAndRevisions<MyItem>("Test", 1);
}
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h
index ca1d1b2b7a..fa8eaaf202 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h
+++ b/tests/auto/qml/qqmlvaluetypeproviders/testtypes.h
@@ -331,6 +331,136 @@ private:
QVariant m_aVariant;
};
+class Padding
+{
+ Q_GADGET
+
+ Q_PROPERTY(int left READ left WRITE setLeft)
+ Q_PROPERTY(int right READ right WRITE setRight)
+
+ QML_VALUE_TYPE(padding)
+ QML_STRUCTURED_VALUE
+
+public:
+ enum LogType {
+ DefaultCtor,
+ CopyCtor,
+ MoveCtor,
+ CopyAssign,
+ MoveAssign,
+ InvokableCtor,
+ CustomCtor,
+ Invalid,
+ };
+
+ Q_ENUM(LogType);
+
+ struct LogEntry {
+ LogType type = Invalid;
+ int left = 0;
+ int right = 0;
+
+ friend QDebug operator<<(QDebug &debug, const LogEntry &self)
+ {
+ return debug << self.type << " " << self.left << " " << self.right;
+ }
+ };
+
+ static QList<LogEntry> log;
+
+ void doLog(LogType type) {
+ log.append({
+ type, m_left, m_right
+ });
+ }
+
+ Padding()
+ {
+ doLog(DefaultCtor);
+ }
+
+ Padding(const Padding &other)
+ : m_left(other.m_left)
+ , m_right(other.m_right)
+ {
+ doLog(CopyCtor);
+ }
+
+ Padding(Padding &&other)
+ : m_left(other.m_left)
+ , m_right(other.m_right)
+ {
+ doLog(MoveCtor);
+ }
+
+ Padding(int left, int right)
+ : m_left( left )
+ , m_right( right )
+ {
+ doLog(CustomCtor);
+ }
+
+ Padding &operator=(const Padding &other) {
+ if (this != &other) {
+ m_left = other.m_left;
+ m_right = other.m_right;
+ }
+ doLog(CopyAssign);
+ return *this;
+ }
+
+ Padding &operator=(Padding &&other) {
+ if (this != &other) {
+ m_left = other.m_left;
+ m_right = other.m_right;
+ }
+ doLog(MoveAssign);
+ return *this;
+ }
+
+ Q_INVOKABLE Padding(int padding )
+ : m_left( padding )
+ , m_right( padding )
+ {
+ doLog(InvokableCtor);
+ }
+
+ void setLeft(int padding) { m_left = padding; }
+ int left() const { return m_left; }
+
+ void setRight(int padding) { m_right = padding; }
+ int right() const { return m_right; }
+
+private:
+ int m_left = 0;
+ int m_right = 0;
+};
+
+class MyItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Padding padding READ padding WRITE setPadding NOTIFY paddingChanged)
+ QML_ELEMENT
+
+public:
+ void setPadding(const Padding &padding)
+ {
+ if (padding.left() == m_padding.left() && padding.right() == m_padding.right())
+ return;
+
+ m_padding = padding;
+ emit paddingChanged();
+ }
+
+ const Padding &padding() const{ return m_padding; }
+
+signals:
+ void paddingChanged();
+
+private:
+ Padding m_padding{ 17, 17 };
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
index 25e24e5f40..5dd7759509 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
+++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
@@ -41,6 +41,7 @@ private slots:
void structured();
void recursive();
void date();
+ void constructors();
};
void tst_qqmlvaluetypeproviders::initTestCase()
@@ -386,6 +387,72 @@ void tst_qqmlvaluetypeproviders::date()
QCOMPARE(o->property("aVariant").value<QDateTime>().time().minute(), 44);
}
+void tst_qqmlvaluetypeproviders::constructors()
+{
+
+ QQmlEngine e;
+
+ {
+ const auto guard = qScopeGuard([]() { Padding::log.clear(); });
+ QQmlComponent component(&e);
+ component.setData("import Test\nMyItem { padding : 50 }", QUrl());
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ MyItem *item = qobject_cast<MyItem *>(o.data());
+ QVERIFY(item);
+ QCOMPARE(item->padding().left(), 50);
+ QCOMPARE(item->padding().right(), 50);
+
+ QCOMPARE(Padding::log.length(), 3);
+
+ // Created by default ctor of MyItem
+ QCOMPARE(Padding::log[0].type, Padding::CustomCtor);
+ QCOMPARE(Padding::log[0].left, 17);
+ QCOMPARE(Padding::log[0].right, 17);
+
+ // Created by assignment of integer
+ QCOMPARE(Padding::log[1].type, Padding::InvokableCtor);
+ QCOMPARE(Padding::log[1].left, 50);
+ QCOMPARE(Padding::log[1].right, 50);
+
+ // In MyItem::setPadding()
+ QCOMPARE(Padding::log[2].type, Padding::CopyAssign);
+ QCOMPARE(Padding::log[2].left, 50);
+ QCOMPARE(Padding::log[2].right, 50);
+ }
+
+ {
+ const auto guard = qScopeGuard([]() { Padding::log.clear(); });
+ QQmlComponent component(&e);
+ component.setData("import Test\nMyItem { padding: ({ left: 10, right: 20 }) }", QUrl());
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ MyItem *item = qobject_cast<MyItem *>(o.data());
+ QVERIFY(item);
+ QCOMPARE(item->padding().left(), 10);
+ QCOMPARE(item->padding().right(), 20);
+
+ QCOMPARE(Padding::log.length(), 3);
+
+ // Created by default ctor of MyItem
+ QCOMPARE(Padding::log[0].type, Padding::CustomCtor);
+ QCOMPARE(Padding::log[0].left, 17);
+ QCOMPARE(Padding::log[0].right, 17);
+
+ // Preparing for setting properties of structured value
+ QCOMPARE(Padding::log[1].type, Padding::DefaultCtor);
+ QCOMPARE(Padding::log[1].left, 0);
+ QCOMPARE(Padding::log[1].right, 0);
+
+ // In MyItem::setPadding()
+ QCOMPARE(Padding::log[2].type, Padding::CopyAssign);
+ QCOMPARE(Padding::log[2].left, 10);
+ QCOMPARE(Padding::log[2].right, 20);
+ }
+}
+
QTEST_MAIN(tst_qqmlvaluetypeproviders)
#include "tst_qqmlvaluetypeproviders.moc"