Let V8 throw the exception when QML property lookup fails
authorKent Hansen <kent.hansen@nokia.com>
Wed, 14 Mar 2012 12:39:31 +0000 (13:39 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 14 Mar 2012 18:49:35 +0000 (19:49 +0100)
Only V8 knows whether a failed property lookup should actually cause
a ReferenceError to be thrown. When evaluating a "typeof" expression,
for example, a ReferenceError should not be thrown even if the
expression involves global variables that don't exist, according to
the ECMA-262 specification.

QML should try to match the standard JavaScript behavior. This is
achieved by simply returning an empty value handle (to signify the
absence of the property), and leaving it to V8 to throw an exception
as appropriate.

Task-number: QTBUG-21864
Task-number: QTBUG-24448
Change-Id: I9945adcab98fc3b801371163367473d6af0ab31a
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
src/qml/qml/v8/qv8contextwrapper.cpp
tests/auto/qml/qqmlecmascript/data/qtbug_24448.js [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/qtbug_24448.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

index e7c26fd..39392b8 100644 (file)
@@ -238,16 +238,11 @@ QQmlContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
     return r?r->getContext():0;
 }
 
-v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property, 
-                                                    const v8::AccessorInfo &info)
+v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String>,
+                                                    const v8::AccessorInfo &)
 {
-    QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
-
-    QV8Engine *engine = resource->engine;
-
-    QString error = engine->toString(property) + QLatin1String(" is not defined");
-    v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
-    return v8::Undefined();
+    // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
+    return v8::Handle<v8::Value>();
 }
 
 v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, 
@@ -365,9 +360,8 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
 
     expressionContext->unresolvedNames = true;
 
-    QString error = engine->toString(property) + QLatin1String(" is not defined");
-    v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
-    return v8::Undefined();
+    // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
+    return v8::Handle<v8::Value>();
 }
 
 v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property, 
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_24448.js b/tests/auto/qml/qqmlecmascript/data/qtbug_24448.js
new file mode 100644 (file)
index 0000000..eefe003
--- /dev/null
@@ -0,0 +1,6 @@
+var test = false;
+try {
+    eval(foo);
+} catch (e) {
+    test = (typeof foo) === "undefined";
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_24448.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_24448.qml
new file mode 100644 (file)
index 0000000..d8d305d
--- /dev/null
@@ -0,0 +1,7 @@
+import "qtbug_24448.js" as Test
+import QtQuick 2.0
+
+QtObject {
+    property bool test: Test.test
+}
+
index 3fe0a2b..8fea635 100644 (file)
@@ -207,6 +207,7 @@ private slots:
     void deleteLater();
     void in();
     void typeOf();
+    void qtbug_24448();
     void sharedAttachedObject();
     void objectName();
     void writeRemovesBinding();
@@ -5376,17 +5377,9 @@ void tst_qqmlecmascript::typeOf()
 {
     QQmlComponent component(&engine, testFileUrl("typeOf.qml"));
 
-    // These warnings should not happen once QTBUG-21864 is fixed
-    QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
-    QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: a is not defined");
-
-    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
-    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
-
     QObject *o = component.create();
     QVERIFY(o != 0);
 
-    QEXPECT_FAIL("", "QTBUG-21864", Abort);
     QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
     QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
     QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
@@ -5400,6 +5393,14 @@ void tst_qqmlecmascript::typeOf()
     delete o;
 }
 
+void tst_qqmlecmascript::qtbug_24448()
+{
+    QQmlComponent component(&engine, testFileUrl("qtbug_24448.qml"));
+    QScopedPointer<QObject> o(component.create());
+    QVERIFY(o != 0);
+    QVERIFY(o->property("test").toBool());
+}
+
 void tst_qqmlecmascript::sharedAttachedObject()
 {
     QQmlComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));