Skip to content

Commit

Permalink
Let V8 throw the exception when QML property lookup fails
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kent Hansen authored and Qt by Nokia committed Mar 14, 2012
1 parent 8f077f2 commit a27fd58
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 20 deletions.
18 changes: 6 additions & 12 deletions src/qml/qml/v8/qv8contextwrapper.cpp
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions tests/auto/qml/qqmlecmascript/data/qtbug_24448.js
@@ -0,0 +1,6 @@
var test = false;
try {
eval(foo);
} catch (e) {
test = (typeof foo) === "undefined";
}
7 changes: 7 additions & 0 deletions tests/auto/qml/qqmlecmascript/data/qtbug_24448.qml
@@ -0,0 +1,7 @@
import "qtbug_24448.js" as Test
import QtQuick 2.0

QtObject {
property bool test: Test.test
}

17 changes: 9 additions & 8 deletions tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
Expand Up @@ -207,6 +207,7 @@ private slots:
void deleteLater();
void in();
void typeOf();
void qtbug_24448();
void sharedAttachedObject();
void objectName();
void writeRemovesBinding();
Expand Down Expand Up @@ -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"));
Expand All @@ -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"));
Expand Down

0 comments on commit a27fd58

Please sign in to comment.