diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-10-09 04:51:40 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-10-09 04:51:40 (GMT) |
commit | 0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2 (patch) | |
tree | 206907243d6ec4fe27c7d4170eaed4b3582d76e5 | |
parent | d131a9f99ebd5d753d2eedfafe0b276410168bc8 (diff) | |
download | Qt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.zip Qt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.tar.gz Qt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.tar.bz2 |
Output file/line for script errors
-rw-r--r-- | src/declarative/qml/qmlbinding.cpp | 4 | ||||
-rw-r--r-- | src/declarative/qml/qmlbinding.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompiler.cpp | 18 | ||||
-rw-r--r-- | src/declarative/qml/qmlcontext.cpp | 20 | ||||
-rw-r--r-- | src/declarative/qml/qmlcontext_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression.cpp | 48 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression.h | 4 | ||||
-rw-r--r-- | src/declarative/qml/qmlexpression_p.h | 4 | ||||
-rw-r--r-- | src/declarative/qml/qmlinstruction_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlparser_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlvme.cpp | 7 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/data/scriptErrors.js | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/data/scriptErrors.qml | 10 | ||||
-rw-r--r-- | tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 20 |
14 files changed, 102 insertions, 45 deletions
diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 3a34f46..58ce02c 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -67,8 +67,8 @@ QmlBindingPrivate::QmlBindingPrivate() { } -QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) -: QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) +QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, const QUrl &url, int lineNumber, QObject *parent) +: QmlExpression(ctxt, data, rc, obj, url, lineNumber, *new QmlBindingPrivate) { setParent(parent); } diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index e3a297c..1c0ccf1 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -90,7 +90,8 @@ class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression, Q_OBJECT public: QmlBinding(const QString &, QObject *, QmlContext *, QObject *parent=0); - QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, QObject *parent); + QmlBinding(void *, QmlRefCount *, QObject *, QmlContext *, const QUrl &, int, + QObject *parent); ~QmlBinding(); void setTarget(const QmlMetaProperty &); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 12e8101..5e6a8aa 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -833,6 +833,8 @@ void QmlCompiler::genObject(QmlParser::Object *obj) QmlInstruction script; script.type = QmlInstruction::StoreScript; script.line = -1; // ### + script.storeScript.fileName = output->indexForString(obj->scriptBlocksFile.at(ii)); + script.storeScript.lineNumber = obj->scriptBlocksLineNumber.at(ii); script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii)); output->bytecode << script; } @@ -1054,6 +1056,8 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj, bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) { QString scriptCode; + QString sourceUrl; + int lineNumber = 1; if (script->properties.count() == 1 && script->properties.begin().key() == QByteArray("source")) { @@ -1066,8 +1070,7 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) source->values.at(0)->object || !source->values.at(0)->value.isString()) COMPILE_EXCEPTION(source, "Invalid Script source value"); - QString sourceUrl = - output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); + sourceUrl = output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); for (int ii = 0; ii < unit->resources.count(); ++ii) { if (unit->resources.at(ii)->url == sourceUrl) { @@ -1079,10 +1082,14 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) } else if (!script->properties.isEmpty()) { COMPILE_EXCEPTION(*script->properties.begin(), "Properties cannot be set on Script block"); } else if (script->defaultProperty) { + sourceUrl = output->url.toString(); + QmlParser::Location currentLocation; for (int ii = 0; ii < script->defaultProperty->values.count(); ++ii) { Value *v = script->defaultProperty->values.at(ii); + if (lineNumber == 1) + lineNumber = v->location.start.line; if (v->object || !v->value.isString()) COMPILE_EXCEPTION(v, "Invalid Script block"); @@ -1105,8 +1112,11 @@ bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) } } - if (!scriptCode.isEmpty()) + if (!scriptCode.isEmpty()) { obj->scriptBlocks.append(scriptCode); + obj->scriptBlocksFile.append(sourceUrl); + obj->scriptBlocksLineNumber.append(lineNumber); + } return true; } @@ -2322,7 +2332,7 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, store.assignBinding.value = output->indexForByteArray(ref.compiledData); store.assignBinding.context = ref.bindingContext.stack; store.assignBinding.owner = ref.bindingContext.owner; - store.line = prop->location.end.line; + store.line = binding->location.start.line; Q_ASSERT(ref.bindingContext.owner == 0 || (ref.bindingContext.owner != 0 && valueTypeProperty)); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index f6795aa..3f61867 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -61,7 +61,8 @@ QmlContextPrivate::QmlContextPrivate() { } -void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject) +void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, + const QString &fileName, int lineNumber) { if (!engine) return; @@ -78,21 +79,10 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject) QScriptValue scope = scriptEngine->newObject(); scriptContext->setActivationObject(scope); - QScriptValue val = scriptEngine->evaluate(script); + QScriptValue val = scriptEngine->evaluate(script, fileName, lineNumber); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){ - qWarning() << exception.property(QLatin1String("fileName")).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - - } else { - qmlInfo(scopeObject) << exception.toString(); - } - } - } + if (scriptEngine->hasUncaughtException()) + QmlExpressionPrivate::printException(scriptEngine); scriptEngine->popContext(); diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index d18bfda..fe74e28 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -94,7 +94,8 @@ public: QScriptValue scriptValue; QList<QScriptValue> scripts; - void addScript(const QString &script, QObject *scope); + void addScript(const QString &script, QObject *scope, + const QString &fileName = QString(), int lineNumber = 1); QUrl url; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 23e1700..6a6ef5d 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -89,8 +89,11 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, } void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, - QObject *me) + QObject *me, const QUrl &url, int lineNumber) { + data->fileName = url.toString(); + data->line = lineNumber; + quint32 *exprData = (quint32 *)expr; Q_ASSERT(*exprData == BasicScriptEngineData || *exprData == PreTransformedQtScriptData); @@ -107,7 +110,8 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); if (!dd->programs.at(progIdx)) { - dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(data->expression)); + dd->programs[progIdx] = + new QScriptProgram(scriptEngine->compile(data->expression, data->fileName, data->line)); } QmlContextPrivate *ctxtPriv = ctxt->d_func(); @@ -145,11 +149,12 @@ QmlExpression::QmlExpression() /*! \internal */ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me, + const QUrl &url, int lineNumber, QmlExpressionPrivate &dd) : QObject(dd, 0) { Q_D(QmlExpression); - d->init(ctxt, expr, rc, me); + d->init(ctxt, expr, rc, me, url, lineNumber); } /*! @@ -251,6 +256,28 @@ QVariant QmlExpressionPrivate::evalSSE() return rv; } +void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) +{ + if (scriptEngine->hasUncaughtException() && + scriptEngine->uncaughtException().isError()) { + + QString fileName; + int lineNumber = scriptEngine->uncaughtExceptionLineNumber(); + + QScriptValue exception = scriptEngine->uncaughtException(); + QLatin1String fileNameProp("fileName"); + + if (!exception.property(fileNameProp).toString().isEmpty()){ + fileName = exception.property(fileNameProp).toString(); + } else { + fileName = QLatin1String("<Unknown File>"); + } + + qWarning().nospace() << qPrintable(fileName) << ":" << lineNumber << ": " + << qPrintable(exception.toString()); + } +} + QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -291,19 +318,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptValue svalue = data->expressionFunction.call(); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - QLatin1String fileNameProp("fileName"); - if (!exception.property(fileNameProp).toString().isEmpty()){ - qWarning() << exception.property(fileNameProp).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - } else { - qWarning() << exception.toString(); - } - } - } + if (scriptEngine->hasUncaughtException()) + printException(scriptEngine); if (secondaryScope) ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index c295a1c..b85e0a7 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -89,8 +89,8 @@ Q_SIGNALS: protected: QmlExpression(QmlContext *, const QString &, QObject *, QmlExpressionPrivate &dd); - QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, - QmlExpressionPrivate &dd); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me, const QUrl &, + int, QmlExpressionPrivate &dd); private Q_SLOTS: void __q_notify(); diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 33016e6..d9bb27b 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -136,7 +136,7 @@ public: }; void init(QmlContext *, const QString &, QObject *); - void init(QmlContext *, void *, QmlRefCount *, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *, const QUrl &, int); QmlExpressionData *data; @@ -150,6 +150,8 @@ public: static QmlExpressionPrivate *get(QmlExpression *expr) { return static_cast<QmlExpressionPrivate *>(QObjectPrivate::get(expr)); } + + static void printException(QScriptEngine *); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 1dcdace..0da40c3 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -240,6 +240,8 @@ public: } storeString; struct { int value; + int fileName; + int lineNumber; } storeScript; struct { int propertyIndex; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 16862eb..d05cc73 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -168,6 +168,8 @@ namespace QmlParser // Script blocks that were nested under this object QStringList scriptBlocks; + QStringList scriptBlocksFile; + QList<int> scriptBlocksLineNumber; // The bytes to cast instances by to get to the QmlParserStatus // interface. -1 indicates the type doesn't support this interface. diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index e4eef64..a057f11 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -567,7 +567,9 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, case QmlInstruction::StoreScript: { QObject *target = stack.top(); - cp->addScript(primitives.at(instr.storeScript.value), target); + cp->addScript(primitives.at(instr.storeScript.value), target, + primitives.at(instr.storeScript.fileName), + instr.storeScript.lineNumber); } break; @@ -597,12 +599,11 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, if (stack.count() == 1 && bindingSkipList.testBit(coreIndex)) break; - QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); + QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->url, instr.line, 0); bindValues.append(bind); bind->m_mePtr = &bindValues.values[bindValues.count - 1]; bind->setTarget(mp); bind->addToObject(target); - bind->setSourceLocation(comp->url, instr.line); } break; diff --git a/tests/auto/declarative/qmlecmascript/data/scriptErrors.js b/tests/auto/declarative/qmlecmascript/data/scriptErrors.js new file mode 100644 index 0000000..1d7b357 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptErrors.js @@ -0,0 +1,2 @@ +// Comment +a = 10 diff --git a/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml new file mode 100644 index 0000000..3fb8ff7 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptErrors.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Object { + Script { source: "scriptErrors.js" } + Script { function getValue() { a = 10; return 0; } } + + property int x: a.value + property int y: getValue(); +} + diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index dde3bb7..673be35 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -61,6 +61,7 @@ private slots: void objectToString(); void selfDeletingBinding(); void extendedObjectPropertyLookup(); + void scriptErrors(); private: QmlEngine engine; @@ -724,6 +725,25 @@ void tst_qmlecmascript::extendedObjectPropertyLookup() QVERIFY(object != 0); } +/* +Test file/lineNumbers for binding/Script errors. +*/ +void tst_qmlecmascript::scriptErrors() +{ + QmlComponent component(&engine, TEST_FILE("scriptErrors.qml")); + QString url = component.url().toString(); + + QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\""; + QString warning2 = url + ":7: TypeError: Result of expression 'a' [undefined] is not an object."; + QString warning3 = url + ":5: Error: Invalid write to global property \"a\""; + + QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData()); + QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData()); + QObject *object = component.create(); + QVERIFY(object != 0); +} + QTEST_MAIN(tst_qmlecmascript) #include "tst_qmlecmascript.moc" |