diff options
author | Olivier De Cannière <olivier.decanniere@qt.io> | 2024-04-08 15:28:12 +0200 |
---|---|---|
committer | Olivier De Cannière <olivier.decanniere@qt.io> | 2024-04-23 15:21:34 +0200 |
commit | f1e3b4f2ad7f7ca4e74ee701ee2ad43e09b28952 (patch) | |
tree | 0ce103b0a2859a6d0ac98456bbe19393f48e373f | |
parent | a61222c44714756c058b5407613ac3b95e30e4e2 (diff) |
V4: Handle all array-like containers when converting to QJsonArray
Commit b9bfdea0e2c6721d2306af0ecc44f88da9988957 removed specialized
code for QVariantList conversions by relying on sequences instead.
Some checks for sequences and other array-like containers were missed.
Add those and perform all calls to QJsonObject::toJsonArray through a
common QV4::Object interface.
Amends b9bfdea0e2c6721d2306af0ecc44f88da9988957
Fixes: QTBUG-123993
Change-Id: Ia671d556af4f2b4d44f652fa93182977d88621f2
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit 152e6716baeffd22c381df8c37c188b8eab7d9df)
-rw-r--r-- | src/qml/jsruntime/qv4jsonobject.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jsonobject_p.h | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/data/variantListQJsonConversion.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 16 | ||||
-rw-r--r-- | tests/auto/qml/qqmlengine/variantlistQJsonConversion.h | 54 |
7 files changed, 103 insertions, 11 deletions
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index a834cf20d5..d78d09113a 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -988,12 +988,16 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec Q_ASSERT(value.isObject()); Scope scope(value.as<Object>()->engine()); - ScopedArrayObject a(scope, value); - if (a) + if (ScopedArrayObject a{ scope, value }) { return toJsonArray(a, visitedObjects); - ScopedObject o(scope, value); - if (o) + } else if (Scoped<QV4::Sequence> a{ scope, value }) { + return toJsonArray(a, visitedObjects); + } else if (Scoped<QmlListWrapper> lw{ scope, value }) { + return toJsonArray(lw, visitedObjects); + } else if (ScopedObject o{ scope, value }) { return toJsonObject(o, visitedObjects); + } + return QJsonValue(value.toQString()); } @@ -1058,7 +1062,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso return a.asReturnedValue(); } -QJsonArray JsonObject::toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects) +QJsonArray JsonObject::toJsonArray(const Object *a, V4ObjectSet &visitedObjects) { QJsonArray result; if (!a) diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index abdfcf5d37..f6f63d7eb3 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -63,14 +63,13 @@ public: { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); } static inline QJsonObject toJsonObject(const QV4::Object *o) { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); } - static inline QJsonArray toJsonArray(const QV4::ArrayObject *a) - { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); } + static inline QJsonArray toJsonArray(const QV4::Object *o) + { V4ObjectSet visitedObjects; return toJsonArray(o, visitedObjects); } private: static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects); static QJsonObject toJsonObject(const Object *o, V4ObjectSet &visitedObjects); - static QJsonArray toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects); - + static QJsonArray toJsonArray(const Object *o, V4ObjectSet &visitedObjects); }; class JsonParser diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8b86b7fab3..e554b31167 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -2350,8 +2350,8 @@ bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const return true; case QMetaType::QJsonArray: { Scope scope(engine); - ScopedArrayObject a(scope, value); - jsonArrayPtr = new (&allocData) QJsonArray(JsonObject::toJsonArray(a)); + ScopedObject o(scope, value); + jsonArrayPtr = new (&allocData) QJsonArray(JsonObject::toJsonArray(o)); return true; } case QMetaType::QJsonObject: { diff --git a/tests/auto/qml/qqmlengine/CMakeLists.txt b/tests/auto/qml/qqmlengine/CMakeLists.txt index 7951baedb8..9745f31bdb 100644 --- a/tests/auto/qml/qqmlengine/CMakeLists.txt +++ b/tests/auto/qml/qqmlengine/CMakeLists.txt @@ -40,6 +40,7 @@ qt_add_qml_module(tst_qqmlengine_qml SOURCES "declarativelyregistered.h" "declarativelyregistered.cpp" + "variantlistQJsonConversion.h" RESOURCE_PREFIX "/" OUTPUT_DIRECTORY diff --git a/tests/auto/qml/qqmlengine/data/variantListQJsonConversion.qml b/tests/auto/qml/qqmlengine/data/variantListQJsonConversion.qml new file mode 100644 index 0000000000..fd0820a3c5 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/variantListQJsonConversion.qml @@ -0,0 +1,18 @@ +import QtQuick +import OnlyDeclarative + +Item { + + MiscUtils { + id: miscUtils + } + + Component.onCompleted: { + const varlist = miscUtils.createVariantList(); + const obj = { test: varlist }; + const listProperty = miscUtils.createQmlListProperty(); + miscUtils.logArray(varlist); + miscUtils.logObject(obj); + miscUtils.logArray(listProperty); + } +} diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index ec0d1b4386..56140836bf 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -80,6 +80,7 @@ private slots: void lockedRootObject(); void crossReferencingSingletonsDeletion(); void bindingInstallUseAfterFree(); + void variantListQJsonConversion(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1734,6 +1735,21 @@ void tst_qqmlengine::bindingInstallUseAfterFree() QVERIFY(o); } +void tst_qqmlengine::variantListQJsonConversion() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("variantListQJsonConversion.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + QTest::ignoreMessage(QtMsgType::QtDebugMsg, R"(["cpp","variant","list"])"); + QTest::ignoreMessage(QtMsgType::QtDebugMsg, R"({"test":["cpp","variant","list"]})"); + QTest::ignoreMessage(QtMsgType::QtDebugMsg, + R"([{"objectName":"o0"},{"objectName":"o1"},{"objectName":"o2"}])"); + + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmlengine/variantlistQJsonConversion.h b/tests/auto/qml/qqmlengine/variantlistQJsonConversion.h new file mode 100644 index 0000000000..7a47d9ff86 --- /dev/null +++ b/tests/auto/qml/qqmlengine/variantlistQJsonConversion.h @@ -0,0 +1,54 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef VARIANTLIST_QJSON_CONVERSION_HPP +#define VARIANTLIST_QJSON_CONVERSION_HPP + +#include "qqmlintegration.h" +#include <QJsonObject> +#include <QJsonArray> +#include <QObject> +#include <QJsonDocument> +#include <QDebug> +#include <QQmlEngine> +#include <private/qjsvalue_p.h> +#include <private/qqmllistwrapper_p.h> +#include <private/qv4engine_p.h> +#include <private/qv4jsonobject_p.h> + +class MiscUtils : public QObject +{ + Q_OBJECT + QML_ELEMENT + +public: + Q_INVOKABLE QVariantList createVariantList() const + { + return { QString("cpp"), QString("variant"), QString("list") }; + } + + Q_INVOKABLE QQmlListProperty<QObject> createQmlListProperty() + { + QV4::ExecutionEngine engine(qmlEngine(this)); + static QObject objects[] = { QObject{}, QObject{}, QObject{} }; + objects[0].setObjectName("o0"); + objects[1].setObjectName("o1"); + objects[2].setObjectName("o2"); + static QList<QObject *> list{ &objects[0], &objects[1], &objects[2] }; + return QQmlListProperty<QObject>(this, &list); + } + + Q_INVOKABLE void logArray(const QJsonArray &arr) const + { + const auto str = QString(QJsonDocument(arr).toJson(QJsonDocument::Compact)); + qDebug().noquote() << str; + } + + Q_INVOKABLE void logObject(const QJsonObject &obj) const + { + const auto str = QString(QJsonDocument(obj).toJson(QJsonDocument::Compact)); + qDebug().noquote() << str; + } +}; + +#endif // VARIANTLIST_QJSON_CONVERSION_HPP |