aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4engine.cpp25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp9
-rw-r--r--tests/auto/qml/qqmllanguage/data/arrayToContainer.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp27
5 files changed, 63 insertions, 7 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index c81661033a..81f55673cd 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1508,12 +1508,35 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
+ QVariant retn;
#if QT_CONFIG(qml_sequence_object)
bool succeeded = false;
- QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
+ retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
if (succeeded)
return retn;
#endif
+ retn = QVariant(typeHint, QMetaType::create(typeHint));
+ auto retnAsIterable = retn.value<QtMetaTypePrivate::QSequentialIterableImpl>();
+ if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) {
+ auto const length = a->getLength();
+ QV4::ScopedValue arrayValue(scope);
+ for (qint64 i = 0; i < length; ++i) {
+ arrayValue = a->get(i);
+ QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects);
+ auto originalType = asVariant.userType();
+ bool couldConvert = asVariant.convert(retnAsIterable._metaType_id);
+ if (!couldConvert) {
+ qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3")
+ .arg(QString::number(i),
+ QMetaType::typeName(originalType),
+ QMetaType::typeName(retnAsIterable._metaType_id));
+ // create default constructed value
+ asVariant = QVariant(retnAsIterable._metaType_id, nullptr);
+ }
+ retnAsIterable.append(asVariant.constData());
+ }
+ return retn;
+ }
}
if (value.isUndefined())
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
index 75beafd1ee..c2c8c1b52b 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
@@ -12,7 +12,7 @@ Item {
function performTest() {
// we have NOT registered QList<QPoint> as a type
- var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ];
+ var pointList = [ Qt.point(7,7), "hello world", Qt.point(8,8), Qt.point(9,9) ];
msco.pointListProperty = pointList; // error.
}
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 370ef5f065..26232ac1a3 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -5792,13 +5792,12 @@ void tst_qqmlecmascript::sequenceConversionWrite()
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
QVERIFY(seq != nullptr);
- // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
- QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QJSValue to QList<QPoint>");
- QTest::ignoreMessage(QtWarningMsg, warningOne.toLatin1().constData());
-
+ // Behavior change in 5.14: due to added auto-magical conversions, it is possible to assign to
+ // QList<QPoint>, even though it is not a registered sequence type
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Could not convert array value at position 1 from QString to QPoint"));
QMetaObject::invokeMethod(object, "performTest");
- QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
+ QList<QPoint> pointList; pointList << QPoint(7, 7) << QPoint(0,0) << QPoint(8, 8) << QPoint(9, 9); // original values, shouldn't have changed
QCOMPARE(seq->pointListProperty(), pointList);
delete object;
diff --git a/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml
new file mode 100644
index 0000000000..ee400eb41f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml
@@ -0,0 +1,7 @@
+import QtQml 2.14
+import qt.test 1.0
+
+TestItem {
+ property var vector
+ positions: vector
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index fae74f1f25..4a8ce77f92 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -303,6 +303,8 @@ private slots:
void typeWrapperToVariant();
+ void arrayToContainer();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -5238,6 +5240,31 @@ void tst_qqmllanguage::typeWrapperToVariant()
QVERIFY(target);
}
+class TestItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( QVector<QPointF> positions MEMBER m_points )
+
+public:
+ TestItem() = default;
+ QVector< QPointF > m_points;
+};
+
+
+Q_DECLARE_METATYPE(QVector<QPointF>);
+void tst_qqmllanguage::arrayToContainer()
+{
+ QQmlEngine engine;
+ qmlRegisterType<TestItem>("qt.test", 1, 0, "TestItem");
+ QVector<QPointF> points { QPointF (2.0, 3.0) };
+ engine.rootContext()->setContextProperty("test", QVariant::fromValue(points));
+ QQmlComponent component(&engine, testFileUrl("arrayToContainer.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<TestItem> root(qobject_cast<TestItem *>(component.createWithInitialProperties( {{"vector", QVariant::fromValue(points)}} )));
+ QVERIFY(root);
+ QCOMPARE(root->m_points.at(0), QPointF (2.0, 3.0) );
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"