Don't check for revisions when assigning to grouped properties

This leads to wrong behavior in some cases, where we reject
valid revisions, and there is probably no case, where this could
lead to a conflict for the user of the API.

Change-Id: I1614332cf4c07c6a227551612331dd69b2ae71f3
Task-number: QTBUG-40043
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
This commit is contained in:
Lars Knoll 2016-01-19 15:37:26 +01:00
parent b13412f4db
commit e9a6c1d4e3
7 changed files with 55 additions and 10 deletions

View File

@ -1875,17 +1875,17 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
#ifndef V4_BOOTSTRAP
QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, QObject *object, QQmlContextData *context)
QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check)
{
if (notInRevision) *notInRevision = false;
QQmlPropertyData *d = cache->property(name, object, context);
QQmlPropertyData *d = cache->property(name, 0, 0);
// Find the first property
while (d && d->isFunction())
d = cache->overrideData(d);
if (d && !cache->isAllowedInRevision(d)) {
if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) {
if (notInRevision) *notInRevision = true;
return 0;
} else {
@ -1894,11 +1894,11 @@ QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRev
}
QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision, QObject *object, QQmlContextData *context)
QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision)
{
if (notInRevision) *notInRevision = false;
QQmlPropertyData *d = cache->property(name, object, context);
QQmlPropertyData *d = cache->property(name, 0, 0);
if (notInRevision) *notInRevision = false;
while (d && !(d->isFunction()))
@ -1914,7 +1914,7 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
if (name.endsWith(QStringLiteral("Changed"))) {
QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
d = property(propName, notInRevision, object, context);
d = property(propName, notInRevision);
if (d)
return cache->signal(d->notifyIndex);
}

View File

@ -460,10 +460,15 @@ struct Q_QML_EXPORT PropertyResolver
return cache->property(index);
}
QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, QObject *object = 0, QQmlContextData *context = 0);
enum RevisionCheck {
CheckRevision,
IgnoreRevision
};
QQmlPropertyData *property(const QString &name, bool *notInRevision = 0, RevisionCheck check = CheckRevision);
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
QQmlPropertyData *signal(const QString &name, bool *notInRevision, QObject *object = 0, QQmlContextData *context = 0);
QQmlPropertyData *signal(const QString &name, bool *notInRevision);
QQmlPropertyCache *cache;
};

View File

@ -1859,6 +1859,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
}
bool bindingToDefaultProperty = false;
bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
QQmlPropertyData *pd = 0;
@ -1867,7 +1868,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|| binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
pd = propertyResolver.signal(name, &notInRevision);
else
pd = propertyResolver.property(name, &notInRevision);
pd = propertyResolver.property(name, &notInRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision);
if (notInRevision) {
QString typeName = stringAt(obj->inheritedTypeNameIndex);
@ -1879,7 +1880,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
}
}
} else {
if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty)
if (isGroupProperty)
COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property"));
pd = defaultProperty;

View File

@ -0,0 +1,12 @@
import Qt.test 1.1
import QtQuick 2.0
MyItemUsingRevisionedObject {
property real test
revisioned.prop1: 10
revisioned.prop2: 1
Component.onCompleted: test = revisioned.prop1 + revisioned.prop2
}

View File

@ -452,6 +452,7 @@ void registerTypes()
qmlRegisterType<MyRevisionedSubclass>("Qt.test",1,0,"MyRevisionedSubclass");
// MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
qmlRegisterType<MyRevisionedSubclass,1>("Qt.test",1,1,"MyRevisionedSubclass");
qmlRegisterType<MyItemUsingRevisionedObject>("Qt.test", 1, 0, "MyItemUsingRevisionedObject");
#ifndef QT_NO_WIDGETS
qmlRegisterExtendedType<QWidget,QWidgetDeclarativeUI>("Qt.test",1,0,"QWidget");

View File

@ -1084,10 +1084,27 @@ protected:
qreal m_p4;
};
class MyItemUsingRevisionedObject : public QObject
{
Q_OBJECT
Q_PROPERTY(MyRevisionedClass *revisioned READ revisioned)
public:
MyItemUsingRevisionedObject() {
m_revisioned = new MyRevisionedClass;
}
MyRevisionedClass *revisioned() const { return m_revisioned; }
private:
MyRevisionedClass *m_revisioned;
};
QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered)
QML_DECLARE_TYPE(MyRevisionedBaseClassUnregistered)
QML_DECLARE_TYPE(MyRevisionedClass)
QML_DECLARE_TYPE(MyRevisionedSubclass)
QML_DECLARE_TYPE(MyItemUsingRevisionedObject)
Q_DECLARE_METATYPE(MyQmlObject::MyType)

View File

@ -6578,6 +6578,15 @@ void tst_qqmlecmascript::revision()
QCOMPARE(object->property("test").toReal(), 11.);
delete object;
}
{
QQmlComponent component(&engine, testFileUrl("metaobjectRevision5.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toReal(), 11.);
delete object;
}
}
void tst_qqmlecmascript::realToInt()