Improve warning for QtQml.Binding

Print a warning if there is no property with the given
name of the specified target object, or the property
is read-only.

Change-Id: I5dc2e8330fb1ce53be396b7bf5baf13c1702d2f4
Task-number: QTBUG-39243
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
This commit is contained in:
Tobias Koenig 2015-09-24 10:24:20 +02:00
parent fe7d35e3cb
commit 61ce37de40
4 changed files with 91 additions and 3 deletions

View File

@ -36,6 +36,7 @@
#include <private/qqmlnullablevalue_p.h>
#include <private/qqmlproperty_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlmetatype_p.h>
#include <qqmlengine.h>
#include <qqmlcontext.h>
@ -49,6 +50,29 @@
QT_BEGIN_NAMESPACE
namespace {
void validateProperty(QObject *target, const QString &propertyName, QObject *binding)
{
if (!target)
return;
const QMetaObject *mo = target->metaObject();
const int index = mo->indexOfProperty(propertyName.toUtf8());
if (index == -1) {
qmlInfo(binding) << "Property '" << propertyName << "' does not exist on " << QQmlMetaType::prettyTypeName(target) << ".";
return;
}
const QMetaProperty mp = mo->property(index);
if (!mp.isWritable()) {
qmlInfo(binding) << "Property '" << propertyName << "' on " << QQmlMetaType::prettyTypeName(target) << " is read-only.";
return;
}
}
}
class QQmlBindPrivate : public QObjectPrivate
{
public:
@ -186,8 +210,10 @@ void QQmlBind::setObject(QObject *obj)
d->when = true;
}
d->obj = obj;
if (d->componentComplete)
if (d->componentComplete) {
validateProperty(d->obj, d->propName, this);
d->prop = QQmlProperty(d->obj, d->propName);
}
eval();
}
@ -213,8 +239,10 @@ void QQmlBind::setProperty(const QString &p)
d->when = true;
}
d->propName = p;
if (d->componentComplete)
if (d->componentComplete) {
validateProperty(d->obj, d->propName, this);
d->prop = QQmlProperty(d->obj, d->propName);
}
eval();
}
@ -253,8 +281,10 @@ void QQmlBind::componentComplete()
{
Q_D(QQmlBind);
d->componentComplete = true;
if (!d->prop.isValid())
if (!d->prop.isValid()) {
validateProperty(d->obj, d->propName, this);
d->prop = QQmlProperty(d->obj, d->propName);
}
eval();
}

View File

@ -0,0 +1,13 @@
import QtQuick 2.0
Item {
id: root
readonly property string name: "John"
Binding {
target: root
property: "name"
value: "Doe"
}
}

View File

@ -0,0 +1,11 @@
import QtQuick 2.0
Item {
id: root
Binding {
target: root
property: "unknown"
value: 42
}
}

View File

@ -50,6 +50,8 @@ private slots:
void restoreBindingWithLoop();
void restoreBindingWithoutCrash();
void deletedObject();
void warningOnUnknownProperty();
void warningOnReadOnlyProperty();
private:
QQmlEngine engine;
@ -224,6 +226,38 @@ void tst_qqmlbinding::deletedObject()
delete rect;
}
void tst_qqmlbinding::warningOnUnknownProperty()
{
QQmlTestMessageHandler messageHandler;
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("unknownProperty.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item);
delete item;
QCOMPARE(messageHandler.messages().count(), 1);
const QString expectedMessage = c.url().toString() + QLatin1String(":6:5: QML Binding: Property 'unknown' does not exist on Item.");
QCOMPARE(messageHandler.messages().first(), expectedMessage);
}
void tst_qqmlbinding::warningOnReadOnlyProperty()
{
QQmlTestMessageHandler messageHandler;
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("readonlyProperty.qml"));
QQuickItem *item = qobject_cast<QQuickItem*>(c.create());
QVERIFY(item);
delete item;
QCOMPARE(messageHandler.messages().count(), 1);
const QString expectedMessage = c.url().toString() + QLatin1String(":8:5: QML Binding: Property 'name' on Item is read-only.");
QCOMPARE(messageHandler.messages().first(), expectedMessage);
}
QTEST_MAIN(tst_qqmlbinding)
#include "tst_qqmlbinding.moc"