aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlglobal.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-08 13:05:33 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-08 22:37:40 +0200
commit01427bd0d9fc74794f6cfb22650aa5f7fdcbda76 (patch)
tree0f0cd2d970a036ed95795b03ee0d8ef5a9b865d6 /src/qml/qml/qqmlglobal.cpp
parent062843124470e90ada7323b0734ff35addb0a9cb (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.cpp68
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>