From 2935ec84073898ed4fe700f41ca108d420fb5ba9 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 11 Dec 2009 13:00:15 +1000 Subject: Throw error when attempting to write to a non-existant property via script. --- src/declarative/qml/qmlcontextscriptclass.cpp | 4 ++-- src/declarative/qml/qmlobjectscriptclass.cpp | 21 ++++++++++++++++++++- src/declarative/qml/qmlobjectscriptclass_p.h | 9 +++++++-- .../declarative/qmlecmascript/data/scriptErrors.qml | 1 + tests/auto/declarative/qmlecmascript/testtypes.h | 1 + .../declarative/qmlecmascript/tst_qmlecmascript.cpp | 4 ++++ 6 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 5635ceb..54a5ca3 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -173,7 +173,7 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObje if (scopeObject) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(scopeObject, name, flags, bindContext); + ep->objectClass->queryProperty(scopeObject, name, flags, bindContext, QmlObjectScriptClass::ImplicitObject); if (rv) { lastScopeObject = scopeObject; lastContext = bindContext; @@ -183,7 +183,7 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObje for (int ii = cp->defaultObjects.count() - 1; ii >= 0; --ii) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext); + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext, QmlObjectScriptClass::ImplicitObject); if (rv) { lastDefaultObject = ii; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index d7ab631..3d0581d 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -123,7 +123,8 @@ QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags, QmlContext *evalContext) + QScriptClass::QueryFlags flags, QmlContext *evalContext, + QueryHints hints) { Q_UNUSED(flags); lastData = 0; @@ -179,6 +180,12 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, } } + if (!(hints & ImplicitObject)) { + local.coreIndex = -1; + lastData = &local; + return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + } + return 0; } @@ -194,6 +201,9 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name else if (name == m_toStringId.identifier) return m_toString; + if (lastData && !lastData->isValid()) + return QmlEnginePrivate::getScriptEngine(engine)->undefinedValue(); + Q_ASSERT(obj); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); @@ -263,11 +273,20 @@ void QmlObjectScriptClass::setProperty(QObject *obj, Q_ASSERT(obj); Q_ASSERT(lastData); + if (!lastData->isValid()) { + QString error = QLatin1String("Cannot assign to non-existant property \"") + + toString(name) + QLatin1Char('\"'); + if (context()) + context()->throwError(error); + return; + } + if (!(lastData->flags & QmlPropertyCache::Data::IsWritable)) { QString error = QLatin1String("Cannot assign to read-only property \"") + toString(name) + QLatin1Char('\"'); if (context()) context()->throwError(error); + return; } QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index d8ef1d2..20c68ce 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -76,11 +76,16 @@ public: QObject *toQObject(const QScriptValue &) const; int objectType(const QScriptValue &) const; - enum QueryMode { IncludeAttachedProperties, SkipAttachedProperties }; + enum QueryHint { + ImplicitObject = 0x01, + SkipAttachedProperties = 0x02 + }; + Q_DECLARE_FLAGS(QueryHints, QueryHint) QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, QScriptClass::QueryFlags flags, - QmlContext *evalContext); + QmlContext *evalContext, + QueryHints hints = 0); QScriptValue property(QObject *, const Identifier &); void setProperty(QObject *, const Identifier &name, const QScriptValue &, QmlContext *evalContext = 0); diff --git a/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml index 5c8b1f8..c2edb41 100644 --- a/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml +++ b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml @@ -12,5 +12,6 @@ MyQmlObject { onBasicSignal: { console.log(a.value); } id: myObj onAnotherBasicSignal: myObj.trueProperty = false; + onThirdBasicSignal: myObj.fakeProperty = ""; } diff --git a/tests/auto/declarative/qmlecmascript/testtypes.h b/tests/auto/declarative/qmlecmascript/testtypes.h index d7f7d31..ff20487 100644 --- a/tests/auto/declarative/qmlecmascript/testtypes.h +++ b/tests/auto/declarative/qmlecmascript/testtypes.h @@ -118,6 +118,7 @@ signals: void stringChanged(); void objectChanged(); void anotherBasicSignal(); + void thirdBasicSignal(); public slots: void deleteMe() { delete this; } diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 30ecc51..749f803 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -831,6 +831,7 @@ void tst_qmlecmascript::scriptErrors() QString warning5 = url + ":10: TypeError: Result of expression 'a' [undefined] is not an object."; QString warning6 = url + ":9: Unable to assign [undefined] to int"; QString warning7 = url + ":14: Error: Cannot assign to read-only property \"trueProperty\""; + QString warning8 = url + ":15: Error: Cannot assign to non-existant property \"fakeProperty\""; QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData()); QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData()); @@ -845,6 +846,9 @@ void tst_qmlecmascript::scriptErrors() QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData()); emit object->anotherBasicSignal(); + + QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData()); + emit object->thirdBasicSignal(); } /* -- cgit v0.12