aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-05-23 13:51:15 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-05-30 09:55:41 +0200
commitf5f99985b8cb1d04a3d230a21ccf603b220dcdfd (patch)
tree61c0ff4184535ea86b67c224cc420682067af2c6
parent5911f307e1b0b5c6e263e74fd5ec9c73c8c865ec (diff)
QtQml: Document and uphold precondition of metaTypeFromJS()
The value needs to be a default-constructed instance. Otherwise a number of branches in this method produce unwanted effects, such as appending to an already existing array rather than creating a new one. Amends commit 1b89c1edcae68351632c2755e5408410c2ff98e3. Pick-to: 6.5 Fixes: QTBUG-125429 Change-Id: If175a02b3a794573abc03df206fbddd41f2855b4 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit c16a3e5adb59f6da5e39e51ca15a4d5324d68d1c) Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
-rw-r--r--src/qml/jsruntime/qv4engine.cpp16
-rw-r--r--tests/auto/qml/qqmllanguage/data/nestedVectors.qml27
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h32
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp22
5 files changed, 92 insertions, 6 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 3a45823734..dd70e84dcc 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2440,18 +2440,22 @@ bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
return false;
const QMetaType elementMetaType = iterable.valueMetaType();
- QVariant element(elementMetaType);
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
- if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
- element = QVariant(elementMetaType);
+ QVariant element(elementMetaType);
+ ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data());
iterable.addValue(element, QSequentialIterable::AtEnd);
}
return true;
}
-// Converts a JS value to a meta-type.
-// data must point to a place that can store a value of the given type.
-// Returns true if conversion succeeded, false otherwise.
+/*!
+ * \internal
+ *
+ * Converts a JS value to a meta-type.
+ * \a data must point to a default-constructed instance of \a metaType.
+ * Returns \c true if conversion succeeded, \c false otherwise. In the latter case,
+ * \a data is not modified.
+ */
bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
{
// check if it's one of the types we know
diff --git a/tests/auto/qml/qqmllanguage/data/nestedVectors.qml b/tests/auto/qml/qqmllanguage/data/nestedVectors.qml
new file mode 100644
index 0000000000..0bcea52133
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nestedVectors.qml
@@ -0,0 +1,27 @@
+import Test
+import QtQml
+
+NestedVectors {
+ id: self
+
+ property var list1
+
+ Component.onCompleted: {
+ list1 = self.getList()
+
+ let list2 = []
+ let data1 = []
+ data1.push(2)
+ data1.push(3)
+ data1.push(4)
+
+ let data2 = []
+ data2.push(5)
+ data2.push(6)
+
+ list2.push(data1)
+ list2.push(data2)
+
+ self.setList(list2)
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index ffff0a6979..2fce6567be 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -174,6 +174,7 @@ void registerTypes()
qmlRegisterTypesAndRevisions<NonSingleton>("EnumScopeTest", 1);
qmlRegisterTypesAndRevisions<EnumProviderSingletonQml>("EnumScopeTest", 1);
+ qmlRegisterTypesAndRevisions<NestedVectors>("Test", 1);
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index bcf02c1cf9..6d5c9b5b38 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -2942,4 +2942,36 @@ public:
}
};
+class NestedVectors : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ NestedVectors(QObject *parent = nullptr) : QObject(parent)
+ {
+ std::vector<int> data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ m_list.push_back(data);
+ data.clear();
+ data.push_back(4);
+ data.push_back(5);
+ m_list.push_back(data);
+ }
+
+ Q_INVOKABLE std::vector<std::vector<int>> getList()
+ {
+ return m_list;
+ }
+
+ Q_INVOKABLE void setList(std::vector<std::vector<int>> list)
+ {
+ m_list = list;
+ }
+
+private:
+ std::vector<std::vector<int>> m_list;
+};
+
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 7231b977ce..1e4de3449c 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -454,6 +454,8 @@ private slots:
void typedObjectList();
+ void nestedVectors();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -8655,6 +8657,26 @@ void tst_qqmllanguage::typedObjectList()
QVERIFY(list.at(&list, 0) != nullptr);
}
+void tst_qqmllanguage::nestedVectors()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("nestedVectors.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ NestedVectors *n = qobject_cast<NestedVectors *>(o.data());
+ QVERIFY(n);
+
+ const std::vector<std::vector<int>> expected1 { { 1, 2, 3 }, { 4, 5 } };
+ const QVariant list1 = n->property("list1");
+ QCOMPARE(list1.metaType(), QMetaType::fromType<std::vector<std::vector<int>>>());
+ QCOMPARE(list1.value<std::vector<std::vector<int>>>(), expected1);
+
+ const std::vector<std::vector<int>> expected2 { { 2, 3, 4 }, { 5, 6 } };
+ QCOMPARE(n->getList(), expected2);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"