From: Mark Visser Date: Tue, 30 Apr 2013 18:12:37 +0000 (-0400) Subject: QQmlError.object now holds the scope object that caused exceptions. X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=13afb2b49daec9f5f65dc9a99151c91d685dce13;p=konrad%2Fqtdeclarative.git QQmlError.object now holds the scope object that caused exceptions. Exception errors sent via QQmlEngine::warnings lacked a pointer to the containing scope. I added an object property to QQmlError, and the necessary code to fill it with the QObject* scope from binding exception callbacks. Task-number: QTBUG-30930 Change-Id: I2a987e8cefc3a2a474d338893e9ebcb77c167adf Reviewed-by: Kai Koehne Reviewed-by: Alan Alpert --- diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 98d8259..0c8e46b 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -84,10 +84,11 @@ public: QString description; quint16 line; quint16 column; + QObject *object; }; QQmlErrorPrivate::QQmlErrorPrivate() -: line(0), column(0) +: line(0), column(0), object() { } @@ -122,6 +123,7 @@ QQmlError &QQmlError::operator=(const QQmlError &other) d->description = other.d->description; d->line = other.d->line; d->column = other.d->column; + d->object = other.d->object; } return *this; } @@ -215,6 +217,27 @@ void QQmlError::setColumn(int column) } /*! + Returns the nearest object where this error occurred. + Exceptions in bound property expressions set this to the object + to which the property belongs. It will be 0 for all + other exceptions. + */ +QObject *QQmlError::object() const +{ + if (d) return d->object; + else return 0; +} + +/*! + Sets the nearest \a object where this error occurred. + */ +void QQmlError::setObject(QObject *object) +{ + if (!d) d = new QQmlErrorPrivate; + d->object = object; +} + +/*! Returns the error as a human readable string. */ QString QQmlError::toString() const diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h index cea9ee4..cfa0dfc 100644 --- a/src/qml/qml/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -70,6 +70,8 @@ public: void setLine(int); int column() const; void setColumn(int); + QObject *object() const; + void setObject(QObject *); QString toString() const; private: diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 4568307..2a1ed14 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -79,6 +79,11 @@ void QQmlDelayedError::setErrorDescription(const QString &description) m_error.setDescription(description); } +void QQmlDelayedError::setErrorObject(QObject *object) +{ + m_error.setObject(object); +} + /* Converting from a message to an error is relatively expensive. @@ -348,6 +353,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, error.setDescription(QLatin1String("Exception occurred during function compilation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); + error.setObject(scope); v8::Local message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); @@ -360,6 +366,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, error.setDescription(QLatin1String("Exception occurred during function evaluation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); + error.setObject(scope); v8::Local message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); @@ -390,6 +397,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, error.setDescription(QLatin1String("Exception occurred during function compilation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); + error.setObject(scope); v8::Local message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); @@ -402,6 +410,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, error.setDescription(QLatin1String("Exception occurred during function evaluation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); + error.setObject(scope); v8::Local message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index c48972e..b521ea3 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -84,6 +84,7 @@ public: void setMessage(v8::Handle message); void setErrorLocation(const QUrl &url, quint16 line, quint16 column); void setErrorDescription(const QString &description); + void setErrorObject(QObject *object); private: void convertMessageToError(QQmlEngine *engine) const; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 0baf450..0936df5 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1555,6 +1555,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, // we explicitly disallow this case to avoid confusion. Users can still store one // in an array in a var property if they need to, but the common case is user error. expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + expression->delayedError()->setErrorObject(object); return false; } @@ -1570,6 +1571,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, if (!result.IsEmpty() && result->IsFunction() && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) { expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + expression->delayedError()->setErrorObject(object); return false; } writeValueProperty(object, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags); @@ -1580,12 +1582,14 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, else errorStr += QLatin1String(QMetaType::typeName(type)); expression->delayedError()->setErrorDescription(errorStr); + expression->delayedError()->setErrorObject(object); return false; } else if (result->IsFunction()) { if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); else expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); + expression->delayedError()->setErrorObject(object); return false; } else if (!writeValueProperty(object, core, value, context, flags)) { @@ -1618,6 +1622,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(propertyType)); + expression->delayedError()->setErrorObject(object); return false; } diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index b680bf7..668f7b4 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -793,6 +793,7 @@ static void throwException(int id, QQmlDelayedError *error, error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object")); else error->setErrorDescription(description); + error->setErrorObject(context->contextObject); if (id != 0xFF) { quint32 e = *((quint32 *)(program->data() + program->exceptionDataOffset) + id); error->setErrorLocation(context->url, (e >> 16), (e & 0xFFFF)); diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp index 8d133e7..757d9d9 100644 --- a/src/qml/qml/v8/qv8bindings.cpp +++ b/src/qml/qml/v8/qv8bindings.cpp @@ -191,6 +191,7 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags) delayedError()->setErrorLocation(parent->url(), instruction->line, 0); if (hasError()) { + delayedError()->setErrorObject(object()); if (!delayedError()->addError(ep)) ep->warning(this->error(context->engine)); } else { clearError();