diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2024-05-23 13:51:15 +0200 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-05-28 15:22:14 +0200 |
| commit | c16a3e5adb59f6da5e39e51ca15a4d5324d68d1c (patch) | |
| tree | 20a8b5e59f392e332b49e0854fe869d001c139e1 | |
| parent | d2e355d10179890e41df1fe50e3f2322ff08c038 (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.7 6.5
Fixes: QTBUG-125429
Change-Id: If175a02b3a794573abc03df206fbddd41f2855b4
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
| -rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 16 | ||||
| -rw-r--r-- | tests/auto/qml/qqmllanguage/data/nestedVectors.qml | 27 | ||||
| -rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 1 | ||||
| -rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 32 | ||||
| -rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 22 |
5 files changed, 92 insertions, 6 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index bd6251caa9..6754c3c887 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2479,18 +2479,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 d3e1bc8390..526cca4b5b 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -181,6 +181,7 @@ void registerTypes() InvokableUncreatable, InvokableValueType >("Test", 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 773afcb64b..ce6abf3504 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -3011,4 +3011,36 @@ public: QString m_s; }; +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 83209a05cf..7a32b2ed7f 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -459,6 +459,8 @@ private slots: void jsonArrayPropertyBehavesLikeAnArray(); + void nestedVectors(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -8893,6 +8895,26 @@ void tst_qqmllanguage::invokableCtors() QVERIFY(l); } +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" |
