diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-05-02 18:40:40 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-05-04 11:48:09 +0200 |
commit | 44ca1085d65d15ffd8cfaf45bb79cc82938e965d (patch) | |
tree | 30018ae125053bc91818d5fdbb9543cc76cb69af | |
parent | b8814dfb364e1316e3ee049d5d7cda9e23537d93 (diff) | |
download | qtdeclarative-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.cpp | 11 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/variantReturn.qml | 15 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/variantreturn.h | 63 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/weathermoduleurl.h | 51 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 26 |
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" |