summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-05-02 18:40:40 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-05-04 11:48:09 +0200
commit44ca1085d65d15ffd8cfaf45bb79cc82938e965d (patch)
tree30018ae125053bc91818d5fdbb9543cc76cb69af
parentb8814dfb364e1316e3ee049d5d7cda9e23537d93 (diff)
downloadqtdeclarative-44ca1085d65d15ffd8cfaf45bb79cc82938e965d.tar.gz
QML: Fix call frame conversion for QVariant return types
The function may return a QVariant in place of the actual type because it cannot express the actual type as-is. This case needs special care because QMetaType::convert() doesn't know what to do with it. Pick-to: 6.5 Fixes: QTBUG-112837 Change-Id: Ibf93a28aa6a60d49c5ab63fa7eed5f5a8e58e163 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp11
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt3
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/variantReturn.qml15
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/variantreturn.h63
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/weathermoduleurl.h51
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp26
6 files changed, 169 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 5e4e93fbd9..38a7652ef0 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -514,6 +514,17 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
= (resultObj && resultObj->metaObject()->inherits(frameReturn.metaObject()))
? resultObj
: nullptr;
+ } else if (returnType == QMetaType::fromType<QVariant>()) {
+ const QVariant *resultVariant = static_cast<QVariant *>(transformedResult);
+ if (resultVariant->metaType() == frameReturn) {
+ frameReturn.construct(frame->returnValue(), resultVariant->data());
+ } else {
+ // Convert needs a pre-constructed target.
+ frameReturn.construct(frame->returnValue());
+ QMetaType::convert(resultVariant->metaType(), resultVariant->data(),
+ frameReturn, frame->returnValue());
+ }
+ resultVariant->~QVariant();
} else {
// Convert needs a pre-constructed target.
frameReturn.construct(frame->returnValue());
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index 7e3ffc06c6..74f56f0bb3 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -20,6 +20,8 @@ set(cpp_sources
theme.cpp theme.h
timelinetheme.cpp timelinetheme.h
variantMapLookup.h
+ variantreturn.h
+ weathermoduleurl.h
wrapwithvariant.h
withlength.h
)
@@ -221,6 +223,7 @@ set(qml_files
valueTypeProperty.qml
valueTypeReference.qml
variantMapLookup.qml
+ variantReturn.qml
variantlist.qml
versionmismatch.qml
voidfunction.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/variantReturn.qml b/tests/auto/qml/qmlcppcodegen/data/variantReturn.qml
new file mode 100644
index 0000000000..cca26265c9
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/variantReturn.qml
@@ -0,0 +1,15 @@
+pragma Strict
+import QtQml
+import TestTypes
+
+QtObject {
+ property DirectBindable a: DirectBindable {
+ id: aId
+ x: WeatherModelUrlUtils.url(1)
+ }
+
+ property IndirectBindable b: IndirectBindable {
+ id: bId
+ y: aId.x
+ }
+}
diff --git a/tests/auto/qml/qmlcppcodegen/data/variantreturn.h b/tests/auto/qml/qmlcppcodegen/data/variantreturn.h
new file mode 100644
index 0000000000..bb8ba75839
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/variantreturn.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef VARIANTERETURN_H
+#define VARIANTERETURN_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
+#include <QtQml/qqmlregistration.h>
+
+#include "weathermoduleurl.h"
+
+class DirectBindable : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(WeatherModelUrl x READ x WRITE setX NOTIFY xChanged BINDABLE bindableX)
+
+public:
+ explicit DirectBindable(QObject *parent = nullptr) : QObject(parent) {}
+
+ WeatherModelUrl x() const { return m_x.value(); }
+ void setX(const WeatherModelUrl& newX) { m_x.setValue(newX);}
+ QBindable<WeatherModelUrl> bindableX() { return QBindable<WeatherModelUrl>(&m_x); }
+
+Q_SIGNALS:
+ void xChanged();
+
+private:
+ Q_OBJECT_BINDABLE_PROPERTY(DirectBindable, WeatherModelUrl, m_x, &DirectBindable::xChanged)
+};
+
+class IndirectBindable : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(WeatherModelUrl y READ y WRITE setY NOTIFY yChanged BINDABLE bindableY)
+ Q_PROPERTY(int z READ z NOTIFY zChanged)
+
+public:
+ explicit IndirectBindable(QObject *parent = nullptr) : QObject(parent) {
+ m_z.setBinding([this]()->int {
+ return m_y.value().timeIndex() * 2;
+ });
+ }
+
+ WeatherModelUrl y() const { return m_y.value(); }
+ void setY(const WeatherModelUrl& newY) { m_y.setValue(newY); }
+ QBindable<WeatherModelUrl> bindableY() { return QBindable<WeatherModelUrl>(&m_y); }
+
+ int z() const { return m_z.value(); }
+ QBindable<int> bindableZ() const { return QBindable<int>(&m_z); }
+
+Q_SIGNALS:
+ void yChanged();
+ void zChanged();
+
+private:
+ Q_OBJECT_BINDABLE_PROPERTY(IndirectBindable, WeatherModelUrl, m_y, &IndirectBindable::yChanged)
+ Q_OBJECT_BINDABLE_PROPERTY(IndirectBindable, int, m_z, &IndirectBindable::zChanged)
+};
+
+#endif // VARIANTRETURN_H
diff --git a/tests/auto/qml/qmlcppcodegen/data/weathermoduleurl.h b/tests/auto/qml/qmlcppcodegen/data/weathermoduleurl.h
new file mode 100644
index 0000000000..51d464fb2c
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/weathermoduleurl.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef WEATHERMODELURL_H
+#define WEATHERMODELURL_H
+
+#include <QtQml/qqmlregistration.h>
+#include <QtCore/qobject.h>
+
+class WeatherModelUrl
+{
+ Q_GADGET
+ QML_VALUE_TYPE(weatherModelUrl)
+ Q_PROPERTY(qsizetype timeIndex READ timeIndex CONSTANT)
+
+public:
+ WeatherModelUrl() : m_timeIndex(-1) {}
+ WeatherModelUrl(qsizetype timeIdx) : m_timeIndex(timeIdx) {}
+
+ qsizetype timeIndex() const { return m_timeIndex; }
+
+private:
+ friend bool operator==(const WeatherModelUrl &a, const WeatherModelUrl &b)
+ {
+ return a.m_timeIndex == b.m_timeIndex;
+ }
+
+ friend bool operator!=(const WeatherModelUrl &a, const WeatherModelUrl &b)
+ {
+ return !(a == b);
+ }
+
+ qsizetype m_timeIndex;
+};
+
+class WeatherModelUrlUtils : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
+public:
+ WeatherModelUrlUtils(QObject *parent = nullptr) : QObject(parent) {}
+
+ Q_INVOKABLE static WeatherModelUrl url(int timeIdx)
+ {
+ return WeatherModelUrl(timeIdx);
+ }
+};
+
+#endif // WEATHERMODELURL_H
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 0cad3eb68e..a856d57cfe 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -187,6 +187,7 @@ private slots:
void shadowedMethod();
void topLevelComponent();
void intToEnum();
+ void variantReturn();
};
void tst_QmlCppCodegen::initTestCase()
@@ -3807,6 +3808,31 @@ void tst_QmlCppCodegen::intToEnum()
QCOMPARE(m->property("b").toInt(), 24);
}
+void tst_QmlCppCodegen::variantReturn()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, QUrl(u"qrc:/qt/qml/TestTypes/variantReturn.qml"_s));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QObject *a = o->property("a").value<QObject *>();
+ QVERIFY(a);
+ const QVariant x = a->property("x");
+ const QMetaObject *meta = x.metaType().metaObject();
+ QVERIFY(meta);
+ const QMetaProperty property = meta->property(meta->indexOfProperty("timeIndex"));
+ QVERIFY(property.isValid());
+ const QVariant timeIndex = property.readOnGadget(x.data());
+ QCOMPARE(timeIndex.metaType(), QMetaType::fromType<qsizetype>());
+ QCOMPARE(timeIndex.value<qsizetype>(), qsizetype(1));
+
+ QObject *b = o->property("b").value<QObject *>();
+ QVERIFY(b);
+ QCOMPARE(b->property("z").toInt(), 2);
+}
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"