diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2024-10-24 14:15:49 +0200 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-11-05 10:08:12 +0100 |
| commit | b497a43916d5dbb7899b38b5f4027b8effa07664 (patch) | |
| tree | d451ef530f4779b3c623bfcaab2ecae96e4972fc | |
| parent | ef1dc2a9ca1997b01acc4f5c70756cef6d3db1ab (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.cpp | 18 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4jscall_p.h | 2 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 2 | ||||
| -rw-r--r-- | src/qml/qml/qqmlglobal.cpp | 266 | ||||
| -rw-r--r-- | src/qml/qml/qqmlglobal_p.h | 12 | ||||
| -rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 3 | ||||
| -rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 8 | ||||
| -rw-r--r-- | tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp | 1 |
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); |
