aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2024-04-08 15:28:12 +0200
committerOlivier De Cannière <olivier.decanniere@qt.io>2024-04-23 15:21:34 +0200
commitf1e3b4f2ad7f7ca4e74ee701ee2ad43e09b28952 (patch)
tree0ce103b0a2859a6d0ac98456bbe19393f48e373f
parenta61222c44714756c058b5407613ac3b95e30e4e2 (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.cpp14
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h7
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp4
-rw-r--r--tests/auto/qml/qqmlengine/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qqmlengine/data/variantListQJsonConversion.qml18
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp16
-rw-r--r--tests/auto/qml/qqmlengine/variantlistQJsonConversion.h54
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