aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-10-24 14:15:49 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-11-05 10:08:12 +0100
commitb497a43916d5dbb7899b38b5f4027b8effa07664 (patch)
treed451ef530f4779b3c623bfcaab2ecae96e4972fc
parentef1dc2a9ca1997b01acc4f5c70756cef6d3db1ab (diff)
QtQml: Support conversion to QJSValue when constructing value types
Anything can be converted to QJSValue, but QMetaType::convert cannot perform the conversion. Fixes: QTBUG-130522 Change-Id: I5614db21a0fcc0afa4a605cbd28ea92788aa146d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit d61c0ce1bbdee9a6b43d889c8663176111646ce4) Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
-rw-r--r--src/qml/jsruntime/qv4engine.cpp18
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
-rw-r--r--src/qml/qml/qqmlglobal.cpp266
-rw-r--r--src/qml/qml/qqmlglobal_p.h12
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp3
-rw-r--r--src/qml/qml/qqmlproperty.cpp8
-rw-r--r--tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp1
8 files changed, 224 insertions, 88 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index e80c15f785..713fbd2e0a 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1637,7 +1637,8 @@ static QVariant toVariant(const QV4::Value &value, QMetaType metaType, JSToQVari
#endif
if (metaType.isValid() && !(metaType.flags() & QMetaType::PointerToQObject)) {
- const QVariant result = QQmlValueTypeProvider::createValueType(value, metaType);
+ const QVariant result
+ = QQmlValueTypeProvider::createValueType(value, metaType, scope.engine);
if (result.isValid())
return result;
}
@@ -2683,14 +2684,18 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
d->readReference();
if (void *gadgetPtr = d->gadgetPtr()) {
- if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, gadgetPtr))
+ if (QQmlValueTypeProvider::populateValueType(
+ metaType, data, valueType, gadgetPtr, vtw->engine())) {
return true;
+ }
if (QMetaType::canConvert(valueType, metaType))
return QMetaType::convert(valueType, gadgetPtr, metaType, data);
} else {
QVariant empty(valueType);
- if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, empty.data()))
+ if (QQmlValueTypeProvider::populateValueType(
+ metaType, data, valueType, empty.data(), vtw->engine())) {
return true;
+ }
if (QMetaType::canConvert(valueType, metaType))
return QMetaType::convert(valueType, empty.data(), metaType, data);
}
@@ -2756,7 +2761,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
}
}
} else if (QQmlValueTypeProvider::populateValueType(
- metaType, data, var.metaType(), var.data())) {
+ metaType, data, var.metaType(), var.data(), variantObject->engine())) {
return true;
}
} else if (value.isNull() && isPointer) {
@@ -2769,8 +2774,11 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
*reinterpret_cast<QJSPrimitiveValue *>(data) = createPrimitive(&value);
return true;
} else if (!isPointer) {
- if (QQmlValueTypeProvider::populateValueType(metaType, data, value))
+ const QV4::Managed *managed = value.as<QV4::Managed>();
+ if (QQmlValueTypeProvider::populateValueType(
+ metaType, data, value, managed ? managed->engine() : nullptr)) {
return true;
+ }
}
if (const QV4::Sequence *sequence = value.as<Sequence>()) {
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index 43776e4b62..85dfa89985 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -389,7 +389,7 @@ inline ReturnedValue coerce(
return value.asReturnedValue();
}
- if (void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value)) {
+ if (void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value, engine)) {
Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
nullptr, metaType, qmlType.metaObjectForValueType(),
nullptr, -1, Heap::ReferenceObject::NoFlag);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 667efac555..9ff13032af 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -833,7 +833,7 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType targetT
// Try value type constructors.
const QVariant converted = QQmlValueTypeProvider::createValueType(
- variant, valueMetaType);
+ variant, valueMetaType, scope.engine);
if (converted.isValid()) {
meta.addValue(result.data(), converted.constData());
continue;
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 1712e879af..c516dcf238 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -71,6 +71,96 @@ static bool isConstructibleMetaType(const QMetaType metaType)
return true;
}
+template<typename JSValue>
+JSValue nullValue()
+{
+ if constexpr (std::is_same_v<JSValue, QJSValue>)
+ return QJSValue::NullValue;
+ if constexpr (std::is_same_v<JSValue, QJSPrimitiveValue>)
+ return QJSPrimitiveNull();
+}
+
+template<typename JSValue>
+bool coerceToJSValue(QMetaType fromType, const void *from, JSValue *to)
+{
+ if (!fromType.isValid()) {
+ *to = JSValue();
+ return true;
+ }
+
+ if ((fromType.flags() & QMetaType::PointerToQObject)
+ && *static_cast<QObject *const *>(from) == nullptr) {
+ *to = nullValue<JSValue>();
+ return true;
+ }
+
+ switch (fromType.id()) {
+ case QMetaType::Void:
+ *to = JSValue();
+ return true;
+ case QMetaType::Bool:
+ *to = JSValue(*static_cast<const bool *>(from));
+ return true;
+ case QMetaType::Int:
+ *to = JSValue(*static_cast<const int *>(from));
+ return true;
+ case QMetaType::Double:
+ *to = JSValue(*static_cast<const double *>(from));
+ return true;
+ case QMetaType::QString:
+ *to = JSValue(*static_cast<const QString *>(from));
+ return true;
+ case QMetaType::Nullptr:
+ *to = nullValue<JSValue>();
+ return true;
+ }
+
+ return false;
+}
+
+static bool coerceValue(
+ QMetaType fromType, const void *from, QMetaType toType, void *to,
+ QV4::ExecutionEngine *engine)
+{
+ // We would like to convert via metaTypeFromJS here, but that would allow conversion of
+ // anything to numbers and strings. That would mean a value type with a ctor that takes
+ // a number or a string would be constructible from any other value. While this would be
+ // quite JavaScript-y, it's probably too permissive here.
+
+ if (QMetaType::convert(fromType, from, toType, to))
+ return true;
+
+ if (toType == QMetaType::fromType<QJSPrimitiveValue>())
+ return coerceToJSValue(fromType, from, static_cast<QJSPrimitiveValue *>(to));
+
+ if (toType == QMetaType::fromType<QJSValue>()) {
+ if (coerceToJSValue(fromType, from, static_cast<QJSValue *>(to)))
+ return true;
+
+ if (!engine)
+ return false;
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(fromType, from));
+ *static_cast<QJSValue *>(to) = QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
+ return true;
+ }
+
+ if (toType == QMetaType::fromType<QJSManagedValue>()) {
+ if (!engine)
+ return false;
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(fromType, from));
+ *static_cast<QJSManagedValue *>(to) = QJSManagedValue(
+ QJSValuePrivate::fromReturnedValue(v->asReturnedValue()), engine->jsEngine());
+ return true;
+ }
+
+
+ return false;
+}
+
static void *createVariantData(QMetaType type, QVariant *variant)
{
const QtPrivate::QMetaTypeInterface *iface = type.iface();
@@ -107,7 +197,8 @@ static void fromVerifiedType(
template<typename Allocate, typename Retrieve>
static bool fromMatchingType(
- const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve)
+ const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve,
+ QV4::ExecutionEngine *engine)
{
const int end = targetMetaObject->constructorCount();
for (int i = 0; i < end; ++i) {
@@ -161,10 +252,8 @@ static bool fromMatchingType(
const QMetaType parameterType = ctor.parameterMetaType(0);
if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
- // At this point, sourceData should be a builtin type. For builtin types
- // the QMetaType converters are good enough.
QVariant converted(parameterType);
- if (QMetaType::convert(sourceMetaType, sourceData, parameterType, converted.data())) {
+ if (coerceValue(sourceMetaType, sourceData, parameterType, converted.data(), engine)) {
callConstructor(targetMetaObject, i, converted.data(), allocate());
return true;
}
@@ -180,23 +269,25 @@ static bool fromMatchingType(
template<typename Allocate>
static bool fromMatchingType(
- const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate)
+ const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate,
+ QV4::ExecutionEngine *engine)
{
QVariant variant;
return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
if (!variant.isValid())
variant = QV4::ExecutionEngine::toVariant(source, QMetaType());
return callback(variant.metaType(), variant.data());
- });
+ }, engine);
}
template<typename Allocate>
static bool fromMatchingType(
- const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate)
+ const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate,
+ QV4::ExecutionEngine *engine)
{
return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
return callback(source.metaType(), source.data());
- });
+ }, engine);
}
template<typename Allocate>
@@ -217,8 +308,9 @@ static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
}
template<typename Get, typename Convert>
-static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
- Get &&get, Convert &&convert)
+static bool doWriteProperty(
+ const QMetaProperty &metaProperty, void *target, Get &&get, Convert &&convert,
+ QV4::ExecutionEngine *engine)
{
const QMetaType propertyType = metaProperty.metaType();
QVariant property = get(propertyType);
@@ -234,8 +326,9 @@ static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
}
converted = QVariant(propertyType);
- if (QMetaType::convert(property.metaType(), property.constData(),
- propertyType, converted.data())) {
+ if (coerceValue(
+ property.metaType(), property.constData(), propertyType, converted.data(),
+ engine)) {
metaProperty.writeOnGadget(target, std::move(converted));
return true;
}
@@ -244,7 +337,8 @@ static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
}
static void doWriteProperties(
- const QMetaObject *targetMetaObject, void *target, const QV4::Value &source)
+ const QMetaObject *targetMetaObject, void *target, const QV4::Value &source,
+ QV4::ExecutionEngine *engine)
{
const QV4::Object *o = static_cast<const QV4::Object *>(&source);
QV4::Scope scope(o->engine());
@@ -265,8 +359,8 @@ static void doWriteProperties(
if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
}, [&](const QMetaType &propertyType) {
- return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
- })) {
+ return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType, engine);
+ }, engine)) {
continue;
}
@@ -277,15 +371,17 @@ static void doWriteProperties(
continue;
}
- QVariant converted = QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ QVariant converted = QQmlValueTypeProvider::createValueType(
+ v4PropValue, propertyType, engine);
if (converted.isValid()) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
converted = QVariant(propertyType);
- if (QMetaType::convert(property.metaType(), property.constData(),
- propertyType, converted.data())) {
+ if (coerceValue(
+ property.metaType(), property.constData(), propertyType, converted.data(),
+ engine)) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
@@ -298,20 +394,21 @@ static void doWriteProperties(
}
static QVariant byProperties(
- const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source)
+ const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source,
+ QV4::ExecutionEngine *engine)
{
if (!source.isObject() || !targetMetaObject)
return QVariant();
QVariant result(metaType);
- doWriteProperties(targetMetaObject, result.data(), source);
+ doWriteProperties(targetMetaObject, result.data(), source, engine);
return result;
}
template<typename Read>
static void doWriteProperties(
const QMetaObject *targetMetaObject, void *target,
- const QMetaObject *sourceMetaObject, Read &&read)
+ const QMetaObject *sourceMetaObject, Read &&read, QV4::ExecutionEngine *engine)
{
for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
const QMetaProperty metaProperty = targetMetaObject->property(i);
@@ -330,15 +427,16 @@ static void doWriteProperties(
continue;
}
- QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
if (converted.isValid()) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
converted = QVariant(propertyType);
- if (QMetaType::convert(property.metaType(), property.constData(),
- propertyType, converted.data())) {
+ if (coerceValue(
+ property.metaType(), property.constData(), propertyType, converted.data(),
+ engine)) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
@@ -351,29 +449,31 @@ static void doWriteProperties(
}
-static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source)
+static void doWriteProperties(
+ const QMetaObject *targetMeta, void *target, QObject *source, QV4::ExecutionEngine *engine)
{
doWriteProperties(
targetMeta, target, source->metaObject(),
[source](const QMetaObject *sourceMetaObject, int sourceProperty) {
return sourceMetaObject->property(sourceProperty).read(source);
- });
+ }, engine);
}
static QVariant byProperties(
- const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source)
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source,
+ QV4::ExecutionEngine *engine)
{
if (!source || !targetMetaObject)
return QVariant();
QVariant result(targetMetaType);
- doWriteProperties(targetMetaObject, result.data(), source);
+ doWriteProperties(targetMetaObject, result.data(), source, engine);
return result;
}
static QVariant byProperties(
- const QMetaObject *targetMetaObject, QMetaType targetMetaType,
- const QMetaObject *sourceMetaObject, const void *source)
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType,
+ const QMetaObject *sourceMetaObject, const void *source, QV4::ExecutionEngine *engine)
{
if (!source || !sourceMetaObject || !targetMetaObject)
return QVariant();
@@ -383,12 +483,14 @@ static QVariant byProperties(
targetMetaObject, result.data(), sourceMetaObject,
[source](const QMetaObject *sourceMetaObject, int sourceProperty) {
return sourceMetaObject->property(sourceProperty).readOnGadget(source);
- });
+ }, engine);
return result;
}
template<typename Map>
-void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const Map &source)
+void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target, const Map &source,
+ QV4::ExecutionEngine *engine)
{
for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
const QMetaProperty metaProperty = targetMetaObject->property(i);
@@ -406,15 +508,16 @@ void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const
continue;
}
- QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
if (converted.isValid()) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
converted = QVariant(propertyType);
- if (QMetaType::convert(property.metaType(), property.constData(),
- propertyType, converted.data())) {
+ if (coerceValue(
+ property.metaType(), property.constData(), propertyType, converted.data(),
+ engine)) {
metaProperty.writeOnGadget(target, std::move(converted));
continue;
}
@@ -428,15 +531,17 @@ void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const
template<typename Map>
QVariant byProperties(
- const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source)
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source,
+ QV4::ExecutionEngine *engine)
{
QVariant result(targetMetaType);
- doWriteProperties(targetMetaObject, result.data(), source);
+ doWriteProperties(targetMetaObject, result.data(), source, engine);
return result;
}
static QVariant byProperties(
- const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source)
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source,
+ QV4::ExecutionEngine *engine)
{
if (!targetMetaObject)
return QVariant();
@@ -444,26 +549,29 @@ static QVariant byProperties(
if (source.metaType() == QMetaType::fromType<QJSValue>()) {
QJSValue val = source.value<QJSValue>();
return byProperties(
- targetMetaObject, targetMetaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
+ targetMetaObject, targetMetaType,
+ QV4::Value(QJSValuePrivate::asReturnedValue(&val)), engine);
}
if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
return byProperties(
- targetMetaObject, targetMetaType,
- *static_cast<const QVariantMap *>(source.constData()));
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantMap *>(source.constData()), engine);
}
if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
return byProperties(
- targetMetaObject, targetMetaType,
- *static_cast<const QVariantHash *>(source.constData()));
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantHash *>(source.constData()), engine);
}
if (source.metaType().flags() & QMetaType::PointerToQObject)
- return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>());
+ return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>(), engine);
- if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType()))
- return byProperties(targetMetaObject, targetMetaType, sourceMeta, source.constData());
+ if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType())) {
+ return byProperties(
+ targetMetaObject, targetMetaType, sourceMeta, source.constData(), engine);
+ }
return QVariant();
}
@@ -471,7 +579,7 @@ static QVariant byProperties(
template<typename Allocate, typename DefaultConstruct>
bool createOrConstructValueType(
const QQmlType &targetType, const QV4::Value &source,
- Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
{
const auto warn = [&](const QMetaObject *targetMetaObject) {
qWarning().noquote()
@@ -483,18 +591,18 @@ bool createOrConstructValueType(
if (targetType.canPopulateValueType()) {
if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
if (source.isObject()) {
- doWriteProperties(targetMetaObject, defaultConstruct(), source);
+ doWriteProperties(targetMetaObject, defaultConstruct(), source, engine);
return true;
}
if (targetType.canConstructValueType()) {
- if (fromMatchingType(targetMetaObject, source, allocate))
+ if (fromMatchingType(targetMetaObject, source, allocate, engine))
return true;
warn(targetMetaObject);
}
}
} else if (targetType.canConstructValueType()) {
if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
- if (fromMatchingType(targetMetaObject, source, allocate))
+ if (fromMatchingType(targetMetaObject, source, allocate, engine))
return true;
warn(targetMetaObject);
}
@@ -516,7 +624,7 @@ bool createOrConstructValueType(
template<typename Allocate, typename DefaultConstruct>
bool createOrConstructValueType(
const QQmlType &targetType, QMetaType sourceMetaType, void *source,
- Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
{
const auto warn = [&](const QMetaObject *targetMetaObject) {
@@ -533,28 +641,28 @@ bool createOrConstructValueType(
targetMetaObject, defaultConstruct(), sourceMetaObject,
[&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
return sourceMetaObject->property(sourceProperty).readOnGadget(source);
- });
+ }, engine);
return true;
}
if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
doWriteProperties(
targetMetaObject, defaultConstruct(),
- *static_cast<const QVariantMap *>(source));
+ *static_cast<const QVariantMap *>(source), engine);
return true;
}
if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
doWriteProperties(
targetMetaObject, defaultConstruct(),
- *static_cast<const QVariantHash *>(source));
+ *static_cast<const QVariantHash *>(source), engine);
return true;
}
if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
doWriteProperties(
targetMetaObject, defaultConstruct(),
- *static_cast<QObject *const *>(source));
+ *static_cast<QObject *const *>(source), engine);
return true;
}
}
@@ -565,7 +673,7 @@ bool createOrConstructValueType(
if (fromMatchingType(
targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
return callback(sourceMetaType, source);
- })) {
+ }, engine)) {
return true;
}
warn(targetMetaObject);
@@ -584,12 +692,13 @@ bool createOrConstructValueType(
* efficient if you're going to create a QVariant anyway.
*/
bool QQmlValueTypeProvider::populateValueType(
- QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source,
+ QV4::ExecutionEngine *engine)
{
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
const QJSValue *val = static_cast<const QJSValue *>(source);
return populateValueType(
- targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)), engine);
}
if (!isConstructibleMetaType(targetMetaType))
@@ -602,7 +711,7 @@ bool QQmlValueTypeProvider::populateValueType(
return target;
}, [target]() {
return target;
- });
+ }, engine);
}
/*!
@@ -614,7 +723,8 @@ bool QQmlValueTypeProvider::populateValueType(
* efficient if you're going to create a QVariant anyway.
*/
bool QQmlValueTypeProvider::populateValueType(
- QMetaType targetMetaType, void *target, const QV4::Value &source)
+ QMetaType targetMetaType, void *target, const QV4::Value &source,
+ QV4::ExecutionEngine *engine)
{
if (!isConstructibleMetaType(targetMetaType))
return false;
@@ -625,7 +735,7 @@ bool QQmlValueTypeProvider::populateValueType(
return target;
}, [target]() {
return target;
- });
+ }, engine);
}
/*!
@@ -633,7 +743,7 @@ bool QQmlValueTypeProvider::populateValueType(
* Specialization that constructs the value type on the heap using new and returns a pointer to it.
*/
void *QQmlValueTypeProvider::heapCreateValueType(
- const QQmlType &targetType, const QV4::Value &source)
+ const QQmlType &targetType, const QV4::Value &source, QV4::ExecutionEngine *engine)
{
void *target = nullptr;
if (createOrConstructValueType(
@@ -647,7 +757,7 @@ void *QQmlValueTypeProvider::heapCreateValueType(
}, [&]() {
target = targetType.typeId().create();
return target;
- })) {
+ }, engine)) {
Q_ASSERT(target != nullptr);
}
@@ -698,7 +808,8 @@ QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType meta
return fromJSValue(type, s, metaType);
}
-QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType)
+QVariant QQmlValueTypeProvider::createValueType(
+ const QV4::Value &s, QMetaType metaType, QV4::ExecutionEngine *engine)
{
if (!isConstructibleMetaType(metaType))
return QVariant();
@@ -711,20 +822,26 @@ QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType m
if (type.canPopulateValueType()) {
if (const QMetaObject *mo = type.metaObject()) {
- QVariant result = byProperties(mo, metaType, s);
+ QVariant result = byProperties(mo, metaType, s, engine);
if (result.isValid())
return result;
if (type.canConstructValueType()) {
- if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ if (fromMatchingType(
+ mo, s, [&]() { return createVariantData(metaType, &result); },
+ engine)) {
return result;
+ }
warn(mo);
}
}
} else if (type.canConstructValueType()) {
if (const QMetaObject *mo = type.metaObject()) {
QVariant result;
- if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ if (fromMatchingType(
+ mo, s, [&]() { return createVariantData(metaType, &result); },
+ engine)) {
return result;
+ }
warn(mo);
}
}
@@ -737,7 +854,8 @@ QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType m
* \internal
* This should only be called with either builtin types or wrapped QJSValues as source.
*/
-QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType metaType)
+QVariant QQmlValueTypeProvider::createValueType(
+ const QVariant &s, QMetaType metaType, QV4::ExecutionEngine *engine)
{
if (!isConstructibleMetaType(metaType))
return QVariant();
@@ -750,20 +868,26 @@ QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType met
if (type.canPopulateValueType()) {
if (const QMetaObject *mo = type.metaObjectForValueType()) {
- QVariant result = byProperties(mo, metaType, s);
+ QVariant result = byProperties(mo, metaType, s, engine);
if (result.isValid())
return result;
if (type.canConstructValueType()) {
- if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ if (fromMatchingType(
+ mo, s, [&]() { return createVariantData(metaType, &result); },
+ engine)) {
return result;
+ }
warn(mo);
}
}
} else if (type.canConstructValueType()) {
if (const QMetaObject *mo = type.metaObjectForValueType()) {
QVariant result;
- if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ if (fromMatchingType(
+ mo, s, [&]() { return createVariantData(metaType, &result); },
+ engine)) {
return result;
+ }
warn(mo);
}
}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 5aa2f3ee6f..9b8482724e 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -207,20 +207,22 @@ class QQmlValueTypeProvider
{
public:
static bool populateValueType(
- QMetaType targetMetaType, void *target, const QV4::Value &source);
+ QMetaType targetMetaType, void *target, const QV4::Value &source,
+ QV4::ExecutionEngine *engine);
static bool populateValueType(
- QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source,
+ QV4::ExecutionEngine *engine);
static Q_QML_EXPORT void *heapCreateValueType(
- const QQmlType &targetType, const QV4::Value &source);
+ const QQmlType &targetType, const QV4::Value &source, QV4::ExecutionEngine *engine);
static QVariant constructValueType(
QMetaType targetMetaType, const QMetaObject *targetMetaObject,
int ctorIndex, void *ctorArg);
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);
+ static QVariant createValueType(const QV4::Value &, QMetaType, QV4::ExecutionEngine *);
+ static QVariant createValueType(const QVariant &, QMetaType, QV4::ExecutionEngine *);
};
class Q_QML_EXPORT QQmlColorProvider
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index fab2790baa..e1cc198477 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -671,7 +671,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
- QVariant target = QQmlValueTypeProvider::createValueType(source, propertyType);
+ QVariant target = QQmlValueTypeProvider::createValueType(
+ source, propertyType, engine->handle());
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 d21f63d15c..49fbd1c49c 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1369,7 +1369,7 @@ struct ConvertAndAssignResult {
static ConvertAndAssignResult tryConvertAndAssign(
QObject *object, const QQmlPropertyData &property, const QVariant &value,
QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
- bool isUrl) {
+ bool isUrl, QQmlEnginePrivate *enginePriv) {
if (isUrl
|| variantMetaType == QMetaType::fromType<QString>()
@@ -1423,7 +1423,8 @@ static ConvertAndAssignResult tryConvertAndAssign(
}
}
- QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
+ QVariant converted = QQmlValueTypeProvider::createValueType(
+ value, propertyMetaType, enginePriv ? enginePriv->v4engine() : nullptr);
if (!converted.isValid()) {
converted = QVariant(propertyMetaType);
if (!QMetaType::convert(value.metaType(), value.constData(),
@@ -1542,7 +1543,8 @@ bool QQmlPropertyPrivate::write(
return false;
}
} else if (ConvertAndAssignResult result = tryConvertAndAssign(
- object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
+ object, property, value, flags, propertyMetaType, variantMetaType, isUrl,
+ enginePriv)) {
return result.couldWrite;
} else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
index c06c53cef3..bd3e2b50ff 100644
--- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
+++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp
@@ -586,7 +586,6 @@ void tst_qqmlvaluetypeproviders::constructFromJSValue()
FromJSPrimitive::constructorCalls = 0;
QScopedPointer<QObject> o(component.create());
- QEXPECT_FAIL("", "Until we can handle QJSValue the ctor should not be called", Abort);
QVERIFY(!o.isNull());
QCOMPARE(FromJSValue::constructorCalls, 1);