From 204cf6be3d63b16981843b0ae6a544e30da35134 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 30 Apr 2010 08:19:00 +1000 Subject: Warn on assigning a function to a QML property. This is not supported, and should not silently be converting the function to a string. See QTBUG-10302 for why we check !isRegExp as well as isFunction. Task-number: QTBUG-10237 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativebinding.cpp | 13 +++++++- .../qml/qdeclarativeobjectscriptclass.cpp | 3 ++ .../data/functionAssignment.1.qml | 5 +++ .../data/functionAssignment.2.qml | 13 ++++++++ .../tst_qdeclarativeecmascript.cpp | 39 ++++++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index d44e7fb..8043ea9 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -193,7 +193,18 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) data->error.setColumn(-1); data->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(data->property.propertyType()))); - } else if (data->property.object() && + } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) { + + QUrl url = QUrl(data->url); + int line = data->line; + if (url.isEmpty()) url = QUrl(QLatin1String("")); + + data->error.setUrl(url); + data->error.setLine(line); + data->error.setColumn(-1); + data->error.setDescription(QLatin1String("Unable to assign a function to a property.")); + + } else if (data->property.object() && !QDeclarativePropertyPrivate::write(data->property, value, flags)) { QUrl url = QUrl(data->url); diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 671a262..33e47fb 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -368,6 +368,9 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(lastData->propType)); context->throwError(error); + } else if (!value.isRegExp() && value.isFunction()) { + QString error = QLatin1String("Cannot assign a function to a property."); + context->throwError(error); } else { QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml new file mode 100644 index 0000000..09540f1 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.1.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyQmlObject { + property variant a: function myFunction() { return 2; } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml new file mode 100644 index 0000000..948b39c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/functionAssignment.2.qml @@ -0,0 +1,13 @@ +import Qt.test 1.0 + +MyQmlObject { + property variant a + property bool runTest: false + onRunTestChanged: { + function myFunction() { + console.log("hello world"); + } + a = myFunction; + } + +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 54c14c2..49ee335 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -145,6 +145,7 @@ private slots: void qtcreatorbug_1289(); void noSpuriousWarningsAtShutdown(); void canAssignNullToQObject(); + void functionAssignment(); void callQtInvokables(); private: @@ -2291,6 +2292,44 @@ void tst_qdeclarativeecmascript::canAssignNullToQObject() } } +void tst_qdeclarativeecmascript::functionAssignment() +{ + { + QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml")); + + QString url = component.url().toString(); + QString warning = url + ":4: Unable to assign a function to a property."; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + MyQmlObject *o = qobject_cast(component.create()); + QVERIFY(o != 0); + + QVERIFY(!o->property("a").isValid()); + + delete o; + } + + { + QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml")); + + MyQmlObject *o = qobject_cast(component.create()); + QVERIFY(o != 0); + + QVERIFY(!o->property("a").isValid()); + + QString url = component.url().toString(); + QString warning = url + ":10: Error: Cannot assign a function to a property."; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + o->setProperty("runTest", true); + + QVERIFY(!o->property("a").isValid()); + + delete o; + } +} + + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" -- cgit v0.12