diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-08 13:05:33 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-06-08 22:37:40 +0200 |
commit | 01427bd0d9fc74794f6cfb22650aa5f7fdcbda76 (patch) | |
tree | 0f0cd2d970a036ed95795b03ee0d8ef5a9b865d6 /src/qml/qml/qqmlglobal.cpp | |
parent | 062843124470e90ada7323b0734ff35addb0a9cb (diff) |
QML: Call value type ctors with derived types of formal parameter
If you pass an argument of a derived type to a ctor that's declared to
accept the base type, this will generally work, even if no QMetaType
conversion is explicitly declared.
Pick-to: 6.5 6.6
Task-number: QTBUG-113752
Change-Id: I0364c2d6b2a1b0f6c067b5a4fd5c000e483afca6
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/qml/qml/qqmlglobal.cpp')
-rw-r--r-- | src/qml/qml/qqmlglobal.cpp | 68 |
1 files changed, 30 insertions, 38 deletions
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index fbfa03dbc5..8fc5339e76 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -104,9 +104,9 @@ static void fromVerifiedType( } -template<typename Allocate> +template<typename Allocate, typename Retrieve> static bool fromMatchingType( - const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate) + const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve) { for (int i = 0, end = targetMetaObject->constructorCount(); i < end; ++i) { const QMetaMethod ctor = targetMetaObject->constructor(i); @@ -114,18 +114,29 @@ static bool fromMatchingType( continue; const QMetaType parameterType = ctor.parameterMetaType(0); - QVariant parameter = QV4::ExecutionEngine::toVariant(source, parameterType); - if (parameter.metaType() == parameterType) { - callConstructor(targetMetaObject, i, parameter.data(), allocate()); + + QVariant source = retrieve(parameterType); + const QMetaType sourceMetaType = source.metaType(); + if (sourceMetaType == parameterType) { + callConstructor(targetMetaObject, i, source.data(), allocate()); return true; } + if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) { + if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject(); + sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) { + // Allow construction from derived types. + callConstructor(targetMetaObject, i, source.data(), allocate()); + return true; + } + } + // Do not recursively try to create parameters here. This may end up in infinite recursion. // At this point, s should be a builtin type. For builtin types // the QMetaType converters are good enough. QVariant converted(parameterType); - if (QMetaType::convert(parameter.metaType(), parameter.constData(), + if (QMetaType::convert(sourceMetaType, source.constData(), parameterType, converted.data())) { callConstructor(targetMetaObject, i, converted.data(), allocate()); return true; @@ -137,40 +148,21 @@ static bool fromMatchingType( template<typename Allocate> static bool fromMatchingType( - const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate) + const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate) { - const QMetaType sourceMetaType = source.metaType(); - if (sourceMetaType == QMetaType::fromType<QJSValue>()) { - QJSValue val = source.value<QJSValue>(); - return fromMatchingType( - targetMetaObject, QV4::Value(QJSValuePrivate::asReturnedValue(&val)), - std::forward<Allocate>(allocate)); - } - - for (int i = 0, end = targetMetaObject->constructorCount(); i < end; ++i) { - const QMetaMethod ctor = targetMetaObject->constructor(i); - if (ctor.parameterCount() != 1) - continue; - - const QMetaType parameterType = ctor.parameterMetaType(0); - if (sourceMetaType == parameterType) { - callConstructor(targetMetaObject, i, source.data(), allocate()); - return true; - } - - // Do not recursively try to create parameters here. This may end up in infinite recursion. - - // At this point, s should be a builtin type. For builtin types - // the QMetaType converters are good enough. - QVariant parameter(parameterType); - if (QMetaType::convert( - sourceMetaType, source.constData(), parameterType, parameter.data())) { - callConstructor(targetMetaObject, i, parameter.data(), allocate()); - return true; - } - } + return fromMatchingType( + targetMetaObject, std::forward<Allocate>(allocate), [&](QMetaType parameterType) { + return QV4::ExecutionEngine::toVariant(source, parameterType); + }); +} - return false; +template<typename Allocate> +static bool fromMatchingType( + const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate) +{ + return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](QMetaType) { + return source; + }); } template<typename Allocate> |