summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-10-09 04:51:40 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-10-09 04:51:40 (GMT)
commit0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2 (patch)
tree206907243d6ec4fe27c7d4170eaed4b3582d76e5
parentd131a9f99ebd5d753d2eedfafe0b276410168bc8 (diff)
downloadQt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.zip
Qt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.tar.gz
Qt-0dc2fe6685323a8aa6bc0e79f908aa9f2dafe6f2.tar.bz2
Output file/line for script errors
-rw-r--r--src/declarative/qml/qmlbinding.cpp4
-rw-r--r--src/declarative/qml/qmlbinding.h3
-rw-r--r--src/declarative/qml/qmlcompiler.cpp18
-rw-r--r--src/declarative/qml/qmlcontext.cpp20
-rw-r--r--src/declarative/qml/qmlcontext_p.h3
-rw-r--r--src/declarative/qml/qmlexpression.cpp48
-rw-r--r--src/declarative/qml/qmlexpression.h4
-rw-r--r--src/declarative/qml/qmlexpression_p.h4
-rw-r--r--src/declarative/qml/qmlinstruction_p.h2
-rw-r--r--src/declarative/qml/qmlparser_p.h2
-rw-r--r--src/declarative/qml/qmlvme.cpp7
-rw-r--r--tests/auto/declarative/qmlecmascript/data/scriptErrors.js2
-rw-r--r--tests/auto/declarative/qmlecmascript/data/scriptErrors.qml10
-rw-r--r--tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp20
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"