summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2010-04-08 06:13:31 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2010-04-08 06:18:43 (GMT)
commitdf1788b4dbbb2826ae63f26bdf166342595343f4 (patch)
treeb021f683c6da72f9c46d0decbf0f8aa97dd2a9d4
parent942a605a52dbbd6dfa824e3b76e37576c7d79f6e (diff)
downloadQt-df1788b4dbbb2826ae63f26bdf166342595343f4.zip
Qt-df1788b4dbbb2826ae63f26bdf166342595343f4.tar.gz
Qt-df1788b4dbbb2826ae63f26bdf166342595343f4.tar.bz2
Cleanup handling of errors in bindings and scripts
QML used to silently ignore a log of errors - such as a failed assignment to a QObject property. These errors are now all reported as exceptions in JavaScript. Other questionable activities, like assigning a JavaScript array to a "property var" property which appeared to work, thanks to QtScript's transparent conversion of arrays to a QVariantList, are now blocked entirely. QTBUG-9152 QTBUG-9382 QTBUG-9341 QTBUG-6886
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp44
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp2
-rw-r--r--src/declarative/qml/qdeclarativecontextscriptclass.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp32
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp71
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h10
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp68
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeparser.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeparser_p.h1
-rw-r--r--src/declarative/qml/qdeclarativescriptparser.cpp1
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp2
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp3
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject_p.h2
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/functionErrors.qml10
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/propertyAssignmentErrors.qml28
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp42
18 files changed, 228 insertions, 96 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 71cf3cb..9a7a242 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -148,14 +148,46 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
idx, a);
} else {
+ QDeclarativeEnginePrivate *ep = (data->context() && data->context()->engine)?
+ QDeclarativeEnginePrivate::get(data->context()->engine):0;
+
bool isUndefined = false;
- QVariant value = this->value(&isUndefined);
+ QVariant value;
+
+ QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
+ if (data->property.propertyTypeCategory() == QDeclarativeProperty::List) {
+ value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
+ } else {
+ value = ep->scriptValueToVariant(scriptValue, data->property.propertyType());
+ if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
+ // If the object is null, we extract the predicted type. While this isn't
+ // 100% reliable, in many cases it gives us better error messages if we
+ // assign this null-object to an incompatible property
+ int type = ep->objectClass->objectType(scriptValue);
+ value = QVariant(type, (void *)0);
+ }
+ }
+
+ if (data->error.isValid()) {
+
+ } else if (!scriptValue.isVariant() && value.userType() == QMetaType::QVariantList &&
+ data->property.propertyType() == qMetaTypeId<QVariant>()) {
+
+ // This case catches QtScript's automatic conversion to QVariantList for arrays
+ QUrl url = QUrl(data->url);
+ int line = data->line;
+ if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
+
+ data->error.setUrl(url);
+ data->error.setLine(line);
+ data->error.setColumn(-1);
+ data->error.setDescription(QLatin1String("Unable to assign JavaScript array to QML variant property"));
- if (isUndefined && !data->error.isValid() && data->property.isResettable()) {
+ } else if (isUndefined && data->property.isResettable()) {
data->property.reset();
- } else if (isUndefined && !data->error.isValid()) {
+ } else if (isUndefined) {
QUrl url = QUrl(data->url);
int line = data->line;
@@ -166,7 +198,7 @@ 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 (!isUndefined && data->property.object() &&
+ } else if (data->property.object() &&
!QDeclarativePropertyPrivate::write(data->property, value, flags)) {
QUrl url = QUrl(data->url);
@@ -187,9 +219,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
}
if (data->error.isValid()) {
- QDeclarativeEnginePrivate *p = (data->context() && data->context()->engine)?
- QDeclarativeEnginePrivate::get(data->context()->engine):0;
- if (!data->addError(p))
+ if (!data->addError(ep))
qWarning().nospace() << qPrintable(this->error().toString());
} else {
data->removeError();
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index f20ffa6..e34cd66 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -2520,7 +2520,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++;
QDeclarativeVMEMetaData::MethodData methodData =
- { s.parameterNames.count(), 0, funcScript.length(), 0 };
+ { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line };
dynamicData.append((char *)&methodData, sizeof(methodData));
}
diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp
index 6d31c22..461fab5 100644
--- a/src/declarative/qml/qdeclarativecontextscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp
@@ -295,7 +295,7 @@ void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifie
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- ep->objectClass->setProperty(lastScopeObject, name, value, bindContext);
+ ep->objectClass->setProperty(lastScopeObject, name, value, context(), bindContext);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index ee0bd18..1bcadf2 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -1323,7 +1323,6 @@ QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine
return qScriptValueFromValue(engine, qVariantFromValue(finalColor));
}
-
QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
{
if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
@@ -1334,6 +1333,14 @@ QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &v
} else {
return scriptEngine.nullValue();
}
+ } else if (val.userType() == qMetaTypeId<QList<QObject *> >()) {
+ const QList<QObject *> &list = *(QList<QObject *>*)val.constData();
+ QScriptValue rv = scriptEngine.newArray(list.count());
+ for (int ii = 0; ii < list.count(); ++ii) {
+ QObject *object = list.at(ii);
+ rv.setProperty(ii, objectClass->newQObject(object));
+ }
+ return rv;
}
bool objOk;
@@ -1345,22 +1352,29 @@ QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &v
}
}
-QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val)
+QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
{
QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
if (dc == objectClass)
return QVariant::fromValue(objectClass->toQObject(val));
+ else if (dc == valueTypeClass)
+ return valueTypeClass->toVariant(val);
else if (dc == contextClass)
return QVariant();
- QScriptDeclarativeClass *sc = QScriptDeclarativeClass::scriptClass(val);
- if (!sc) {
- return val.toVariant();
- } else if (sc == valueTypeClass) {
- return valueTypeClass->toVariant(val);
- } else {
- return QVariant();
+ // Convert to a QList<QObject*> only if val is an array and we were explicitly hinted
+ if (hint == qMetaTypeId<QList<QObject *> >() && val.isArray()) {
+ QList<QObject *> list;
+ int length = val.property(QLatin1String("length")).toInt32();
+ for (int ii = 0; ii < length; ++ii) {
+ QScriptValue arrayItem = val.property(ii);
+ QObject *d = arrayItem.toQObject();
+ list << d;
+ }
+ return QVariant::fromValue(list);
}
+
+ return val.toVariant();
}
// XXX this beyonds in QUrl::toLocalFile()
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index 45089d0..3f22d61 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -308,7 +308,7 @@ public:
QHash<QString, QScriptValue> m_sharedScriptImports;
QScriptValue scriptValueFromVariant(const QVariant &);
- QVariant scriptValueToVariant(const QScriptValue &);
+ QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
void sendQuit ();
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index a250f21..7493690 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -175,7 +175,8 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
- const QString &program, QScriptValue *contextObject)
+ const QString &program, const QString &fileName,
+ int lineNumber, QScriptValue *contextObject)
{
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
@@ -186,7 +187,7 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
scriptContext->pushScope(ep->contextClass->newContext(context, object));
}
scriptContext->pushScope(ep->globalClass->globalObject());
- QScriptValue rv = ep->scriptEngine.evaluate(program);
+ QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
ep->scriptEngine.popContext();
return rv;
}
@@ -351,7 +352,7 @@ void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine
}
}
-QVariant QDeclarativeExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUndefined)
+QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *isUndefined)
{
QDeclarativeExpressionData *data = this->data;
QDeclarativeEngine *engine = data->context()->engine;
@@ -376,7 +377,7 @@ QVariant QDeclarativeExpressionPrivate::evalQtScript(QObject *secondaryScope, bo
const QString code = rewriteBinding(data->expression, &ok);
if (!ok) {
scriptEngine->popContext();
- return QVariant();
+ return QScriptValue();
}
data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line);
}
@@ -413,54 +414,20 @@ QVariant QDeclarativeExpressionPrivate::evalQtScript(QObject *secondaryScope, bo
if (scriptEngine->hasUncaughtException()) {
exceptionToError(scriptEngine, data->error);
scriptEngine->clearExceptions();
- return QVariant();
+ return QScriptValue();
} else {
data->error = QDeclarativeError();
+ return svalue;
}
-
- QVariant rv;
-
- if (svalue.isArray()) {
- int length = svalue.property(QLatin1String("length")).toInt32();
- if (length && svalue.property(0).isObject()) {
- QList<QObject *> list;
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = svalue.property(ii);
- QObject *d = arrayItem.toQObject();
- list << d;
- }
- rv = QVariant::fromValue(list);
- }
- } else if (svalue.isObject() &&
- ep->objectClass->scriptClass(svalue) == ep->objectClass) {
- QObject *o = svalue.toQObject();
- int type = QMetaType::QObjectStar;
- // If the object is null, we extract the predicted type. While this isn't
- // 100% reliable, in many cases it gives us better error messages if we
- // assign this null-object to an incompatible property
- if (!o) type = ep->objectClass->objectType(svalue);
-
- return QVariant(type, &o);
- }
-
- if (rv.isNull())
- rv = svalue.toVariant();
-
- return rv;
}
-QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
+QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
{
Q_Q(QDeclarativeExpression);
-
- QVariant rv;
- if (!q->engine()) {
- qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
- return rv;
- }
+ Q_ASSERT(q->engine());
if (data->expression.isEmpty())
- return rv;
+ return QScriptValue();
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
@@ -476,7 +443,7 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
QDeclarativeExpressionData *localData = data;
localData->addref();
- rv = evalQtScript(secondaryScope, isUndefined);
+ QScriptValue value = eval(secondaryScope, isUndefined);
ep->currentExpression = lastCurrentExpression;
ep->captureProperties = lastCaptureProperties;
@@ -494,7 +461,21 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
lastCapturedProperties.copyAndClear(ep->capturedProperties);
- return rv;
+ return value;
+}
+
+QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
+{
+ Q_Q(QDeclarativeExpression);
+
+ if (!q->engine()) {
+ qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context");
+ return QVariant();
+ }
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+
+ return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined));
}
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
index 9a90fb6..d39aa2c 100644
--- a/src/declarative/qml/qdeclarativeexpression_p.h
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -150,7 +150,9 @@ public:
QDeclarativeExpressionData *data;
QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
- QVariant evalQtScript(QObject *secondaryScope, bool *isUndefined = 0);
+ QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ QScriptValue eval(QObject *secondaryScope, bool *isUndefined = 0);
void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
void clearGuards();
@@ -165,8 +167,10 @@ public:
virtual void emitValueChanged();
static void exceptionToError(QScriptEngine *, QDeclarativeError &);
- static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, QScriptValue * = 0);
- static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &, QScriptValue * = 0);
+ static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, const QString &,
+ int, QScriptValue *);
+ static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &,
+ QScriptValue *);
};
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
index 32ba2c3..8f37a1e 100644
--- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
@@ -52,6 +52,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qvarlengtharray.h>
+#include <QtScript/qscriptcontextinfo.h>
Q_DECLARE_METATYPE(QScriptValue);
@@ -225,15 +226,10 @@ QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name)
if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex));
} else {
-#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE)
// Uncomment to use QtScript method call logic
// QScriptValue sobj = scriptEngine->newQObject(obj);
// return Value(scriptEngine, sobj.property(toString(name)));
return Value(scriptEngine, methods.newMethod(obj, lastData));
-#else
- QScriptValue sobj = scriptEngine->newQObject(obj);
- return Value(scriptEngine, sobj.property(toString(name)));
-#endif
}
} else {
if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) {
@@ -298,7 +294,6 @@ QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name)
QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
return Value(scriptEngine, enginePriv->scriptValueFromVariant(var));
}
-
}
}
@@ -306,40 +301,40 @@ void QDeclarativeObjectScriptClass::setProperty(Object *object,
const Identifier &name,
const QScriptValue &value)
{
- return setProperty(toQObject(object), name, value);
+ return setProperty(toQObject(object), name, value, context());
}
void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
- const Identifier &name,
- const QScriptValue &value,
- QDeclarativeContextData *evalContext)
+ const Identifier &name,
+ const QScriptValue &value,
+ QScriptContext *context,
+ QDeclarativeContextData *evalContext)
{
Q_UNUSED(name);
Q_ASSERT(obj);
Q_ASSERT(lastData);
+ Q_ASSERT(context);
if (!lastData->isValid()) {
QString error = QLatin1String("Cannot assign to non-existent property \"") +
toString(name) + QLatin1Char('\"');
- if (context())
- context()->throwError(error);
+ context->throwError(error);
return;
}
if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable)) {
QString error = QLatin1String("Cannot assign to read-only property \"") +
toString(name) + QLatin1Char('\"');
- if (context())
- context()->throwError(error);
+ context->throwError(error);
return;
}
QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- if (!evalContext && context()) {
+ if (!evalContext) {
// Global object, QScriptContext activation object, QDeclarativeContext object
- QScriptValue scopeNode = scopeChainValue(context(), -3);
+ QScriptValue scopeNode = scopeChainValue(context, -3);
if (scopeNode.isValid()) {
Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass);
@@ -355,10 +350,29 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) {
void *a[] = { 0 };
QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a);
+ } else if (value.isUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(lastData->propType));
+ context->throwError(error);
} else {
- // ### Can well known types be optimized?
- QVariant v = enginePriv->scriptValueToVariant(value);
- QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext);
+ QVariant v = enginePriv->scriptValueToVariant(value, lastData->propType);
+
+ if (!value.isVariant() && v.userType() == QMetaType::QVariantList &&
+ lastData->propType == qMetaTypeId<QVariant>()) {
+
+ QString error = QLatin1String("Cannot assign JavaScript array to QML variant property");
+ context->throwError(error);
+ } else if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(lastData->propType));
+ context->throwError(error);
+ }
}
}
@@ -459,8 +473,6 @@ bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2)
return d1 == d2 || d1->object == d2->object;
}
-#if (QT_VERSION > QT_VERSION_CHECK(4, 6, 2)) || defined(QT_HAVE_QSCRIPTDECLARATIVECLASS_VALUE)
-
struct MethodData : public QScriptDeclarativeClass::Object {
MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {}
@@ -690,7 +702,17 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine,
new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value));
type = callType;
} else if (callType == qMetaTypeId<QList<QObject*> >()) {
- new (&data) QList<QObject *>(); // We don't support passing in QList<QObject*>
+ QList<QObject *> *list = new (&data) QList<QObject *>();
+ if (value.isArray()) {
+ int length = value.property(QLatin1String("length")).toInt32();
+ for (int ii = 0; ii < length; ++ii) {
+ QScriptValue arrayItem = value.property(ii);
+ QObject *d = arrayItem.toQObject();
+ list->append(d);
+ }
+ } else if (QObject *d = value.toQObject()) {
+ list->append(d);
+ }
type = callType;
} else {
new (&data) QVariant();
@@ -803,7 +825,5 @@ QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::
return Value();
}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
index 8a2f7c7..5a59ef8 100644
--- a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
+++ b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
@@ -118,7 +118,7 @@ public:
Value property(QObject *, const Identifier &);
void setProperty(QObject *, const Identifier &name, const QScriptValue &,
- QDeclarativeContextData *evalContext = 0);
+ QScriptContext *context, QDeclarativeContextData *evalContext = 0);
virtual QStringList propertyNames(Object *);
virtual bool compare(Object *, Object *);
diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp
index 69186b6..d1f209a 100644
--- a/src/declarative/qml/qdeclarativeparser.cpp
+++ b/src/declarative/qml/qdeclarativeparser.cpp
@@ -200,7 +200,7 @@ QDeclarativeParser::Object::DynamicSlot::DynamicSlot()
}
QDeclarativeParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o)
-: name(o.name), body(o.body), parameterNames(o.parameterNames)
+: name(o.name), body(o.body), parameterNames(o.parameterNames), location(o.location)
{
}
diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h
index 57df04c..00fc65b 100644
--- a/src/declarative/qml/qdeclarativeparser_p.h
+++ b/src/declarative/qml/qdeclarativeparser_p.h
@@ -227,6 +227,7 @@ namespace QDeclarativeParser
QByteArray name;
QString body;
QList<QByteArray> parameterNames;
+ LocationSpan location;
};
// The list of dynamic properties
diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp
index b4938bb..507ff5b 100644
--- a/src/declarative/qml/qdeclarativescriptparser.cpp
+++ b/src/declarative/qml/qdeclarativescriptparser.cpp
@@ -828,6 +828,7 @@ bool ProcessAST::visit(AST::UiSourceElement *node)
if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
Object::DynamicSlot slot;
+ slot.location = location(funDecl->firstSourceLocation(), funDecl->lastSourceLocation());
AST::FormalParameterList *f = funDecl->formals;
while (f) {
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
index 324b3de..2a3417a 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
+++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
@@ -159,7 +159,7 @@ void QDeclarativeTypeNameScriptClass::setProperty(Object *o, const Identifier &n
Q_ASSERT(!type);
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- ep->objectClass->setProperty(((TypeNameData *)o)->object, n, v);
+ ep->objectClass->setProperty(((TypeNameData *)o)->object, n, v, context());
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index 2644ecf..2e2a8e8 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -671,7 +671,8 @@ QScriptValue QDeclarativeVMEMetaObject::method(int index)
// XXX We should evaluate all methods in a single big script block to
// improve the call time between dynamic methods defined on the same
// object
- methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code);
+ methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(),
+ data->lineNumber, 0);
}
return methods[index];
diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h
index f13dd34..76390c9 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject_p.h
+++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h
@@ -94,7 +94,7 @@ struct QDeclarativeVMEMetaData
int parameterCount;
int bodyOffset;
int bodyLength;
- int scriptProgram;
+ int lineNumber;
};
PropertyData *propertyData() const {
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/functionErrors.qml b/tests/auto/declarative/qdeclarativeecmascript/data/functionErrors.qml
new file mode 100644
index 0000000..4aca111
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/functionErrors.qml
@@ -0,0 +1,10 @@
+import Qt 4.6
+
+QtObject {
+ function myFunction() {
+ a = 10;
+ }
+
+ Component.onCompleted: myFunction();
+}
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/propertyAssignmentErrors.qml b/tests/auto/declarative/qdeclarativeecmascript/data/propertyAssignmentErrors.qml
new file mode 100644
index 0000000..483179a
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/propertyAssignmentErrors.qml
@@ -0,0 +1,28 @@
+import Qt 4.6
+
+QtObject {
+ id: root
+
+ property int a
+ property var b
+
+ Component.onCompleted: {
+ try {
+ root.a = undefined;
+ } catch(e) {
+ console.log (e.fileName + ":" + e.lineNumber + ":" + e);
+ }
+
+ try {
+ root.b = [ 10, root ]
+ } catch(e) {
+ console.log (e.fileName + ":" + e.lineNumber + ":" + e);
+ }
+
+ try {
+ root.a = "Hello";
+ } catch(e) {
+ console.log (e.fileName + ":" + e.lineNumber + ":" + e);
+ }
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index 8e73afa..32d407f 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -108,6 +108,8 @@ private slots:
void selfDeletingBinding();
void extendedObjectPropertyLookup();
void scriptErrors();
+ void functionErrors();
+ void propertyAssignmentErrors();
void signalTriggeredBindings();
void listProperties();
void exceptionClearsOnReeval();
@@ -995,6 +997,46 @@ void tst_qdeclarativeecmascript::scriptErrors()
}
/*
+Test file/lineNumbers for inline functions.
+*/
+void tst_qdeclarativeecmascript::functionErrors()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
+ QString url = component.url().toString();
+
+ QString warning = url + ":5: Error: Invalid write to global property \"a\"";
+
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
+/*
+Test various errors that can occur when assigning a property from script
+*/
+void tst_qdeclarativeecmascript::propertyAssignmentErrors()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
+
+ QString url = component.url().toString();
+
+ QString warning1 = url + ":11:Error: Cannot assign [undefined] to int";
+ QString warning2 = url + ":17:Error: Cannot assign JavaScript array to QML variant property";
+ QString warning3 = url + ":23:Error: Cannot assign QString to int";
+
+ QTest::ignoreMessage(QtDebugMsg, warning1.toLatin1().constData());
+ QTest::ignoreMessage(QtDebugMsg, warning2.toLatin1().constData());
+ QTest::ignoreMessage(QtDebugMsg, warning3.toLatin1().constData());
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ delete object;
+}
+
+/*
Test bindings still work when the reeval is triggered from within
a signal script.
*/