aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp53
-rw-r--r--src/declarative/qml/qdeclarativecompiler_p.h2
-rw-r--r--src/declarative/qml/qdeclarativescript.cpp17
-rw-r--r--src/declarative/qml/qdeclarativescript_p.h6
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml45
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp14
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml5
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt1
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/property.5.qml6
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt2
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml5
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/readonly.qml17
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp36
13 files changed, 160 insertions, 49 deletions
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index 4788491bbc..782a20eeb4 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -208,7 +208,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p
{
const QDeclarativeScript::Variant &value = v->value;
- if (!prop->core.isWritable())
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
if (prop->core.isEnum()) {
@@ -2004,7 +2004,7 @@ bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *pr
}
}
- if (!obj->metaObject()->property(prop->index).isWritable()) {
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) {
COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
}
@@ -2082,8 +2082,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type,
bool isEnumAssignment = false;
if (prop->core.isEnum())
- COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj,
- value, &isEnumAssignment));
+ COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment));
if (isEnumAssignment) {
value->type = Value::Literal;
@@ -2222,7 +2221,7 @@ bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Pro
Q_ASSERT(prop->index != -1);
Q_ASSERT(v->object->type != -1);
- if (!obj->metaObject()->property(prop->index).isWritable())
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
if (QDeclarativeMetaType::isInterface(prop->type)) {
@@ -2303,7 +2302,9 @@ bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Propert
Q_ASSERT(prop->index != -1);
Q_ASSERT(v->object->type != -1);
- if (!obj->metaObject()->property(prop->index).isWritable())
+ Q_UNUSED(obj);
+
+ if (!prop->core.isWritable())
COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
@@ -2350,8 +2351,7 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Pr
//optimization for <Type>.<EnumValue> enum assignments
if (prop->core.isEnum()) {
bool isEnumAssignment = false;
- COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj,
- v, &isEnumAssignment));
+ COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment));
if (isEnumAssignment) {
v->type = Value::Literal;
return true;
@@ -2372,17 +2372,19 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Pr
return true;
}
-bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop,
+bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
QDeclarativeScript::Object *obj,
QDeclarativeScript::Value *v,
bool *isAssignment)
{
*isAssignment = false;
- if (!prop.isEnumType())
+ if (!prop->core.isEnum())
return true;
- if (!prop.isWritable())
- COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name())));
+ QMetaProperty mprop = obj->metaObject()->property(prop->index);
+
+ if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration)
+ COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
QString string = v->value.asString();
if (!string.at(0).isUpper())
@@ -2413,10 +2415,10 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop
if (objTypeName == type->qmlTypeName()) {
// When these two match, we can short cut the search
- if (prop.isFlagType()) {
- value = prop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ if (mprop.isFlagType()) {
+ value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
} else {
- value = prop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
}
} else {
// Otherwise we have to search the whole type
@@ -2571,7 +2573,8 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj)
bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj)
{
- for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) {
+ for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p;
+ p = obj->dynamicProperties.next(p)) {
if (!p->defaultValue || p->type == Object::DynamicProperty::Alias)
continue;
@@ -2585,6 +2588,9 @@ bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object
COMPILE_EXCEPTION(property, tr("Property value set multiple times"));
}
+ if (p->isReadOnly)
+ property->isReadOnlyDeclaration = true;
+
if (property->value)
COMPILE_EXCEPTION(property, tr("Invalid property nesting"));
@@ -2755,6 +2761,9 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn
if (p->type == Object::DynamicProperty::Var)
continue;
+ if (p->isReadOnly)
+ readonly = true;
+
if (buildData) {
VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data();
vmd->propertyCount++;
@@ -2790,8 +2799,10 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn
(vmd->propertyData() + effectivePropertyIndex)->propertyType = -1;
}
- builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)-1,
- QFastMetaBuilder::Writable, effectivePropertyIndex);
+ builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef,
+ (QMetaType::Type)-1,
+ p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable,
+ effectivePropertyIndex);
p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()"));
builder.setSignal(effectivePropertyIndex, p->changedSignatureRef);
@@ -3098,8 +3109,8 @@ bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder,
if (!aliasProperty.isScriptable())
COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location"));
- writable = aliasProperty.isWritable();
- resettable = aliasProperty.isResettable();
+ writable = aliasProperty.isWritable() && !prop.isReadOnly;
+ resettable = aliasProperty.isResettable() && !prop.isReadOnly;
if (aliasProperty.type() < QVariant::UserType)
type = aliasProperty.type();
@@ -3175,7 +3186,7 @@ bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value,
Q_ASSERT(prop->parent);
Q_ASSERT(prop->parent->metaObject());
- if (!prop->core.isWritable() && !prop->core.isQList())
+ if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration)
COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
BindingReference *reference = pool->New<BindingReference>();
diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h
index 2615109cd7..f6229bc666 100644
--- a/src/declarative/qml/qdeclarativecompiler_p.h
+++ b/src/declarative/qml/qdeclarativecompiler_p.h
@@ -336,7 +336,7 @@ private:
bool doesPropertyExist(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj);
bool testLiteralAssignment(QDeclarativeScript::Property *prop,
QDeclarativeScript::Value *value);
- bool testQualifiedEnumAssignment(const QMetaProperty &prop,
+ bool testQualifiedEnumAssignment(QDeclarativeScript::Property *prop,
QDeclarativeScript::Object *obj,
QDeclarativeScript::Value *value,
bool *isAssignment);
diff --git a/src/declarative/qml/qdeclarativescript.cpp b/src/declarative/qml/qdeclarativescript.cpp
index fb4f26a781..9d18cb3889 100644
--- a/src/declarative/qml/qdeclarativescript.cpp
+++ b/src/declarative/qml/qdeclarativescript.cpp
@@ -182,7 +182,7 @@ Property *QDeclarativeScript::Object::getProperty(const QString &name, bool crea
}
QDeclarativeScript::Object::DynamicProperty::DynamicProperty()
-: isDefaultProperty(false), type(Variant), defaultValue(0), nextProperty(0),
+: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0),
resolvedCustomTypeName(0)
{
}
@@ -225,8 +225,8 @@ int QDeclarativeScript::Object::DynamicSlot::parameterNamesLength() const
QDeclarativeScript::Property::Property()
: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false),
- isValueTypeSubProperty(false), isAlias(false), scriptStringScope(-1),
- nextMainProperty(0), nextProperty(0)
+ isValueTypeSubProperty(false), isAlias(false), isReadOnlyDeclaration(false),
+ scriptStringScope(-1), nextMainProperty(0), nextProperty(0)
{
}
@@ -1028,18 +1028,9 @@ bool ProcessAST::visit(AST::UiPublicMember *node)
return false;
}
- if (node->isReadonlyMember) {
- QDeclarativeError error;
- error.setDescription(QCoreApplication::translate("QDeclarativeParser","Readonly not yet supported"));
- error.setLine(node->readonlyToken.startLine);
- error.setColumn(node->readonlyToken.startColumn);
- _parser->_errors << error;
- return false;
-
- }
-
Object::DynamicProperty *property = _parser->_pool.New<Object::DynamicProperty>();
property->isDefaultProperty = node->isDefaultMember;
+ property->isReadOnly = node->isReadonlyMember;
property->type = type;
if (type >= Object::DynamicProperty::Custom) {
QDeclarativeScript::TypeReference *typeRef =
diff --git a/src/declarative/qml/qdeclarativescript_p.h b/src/declarative/qml/qdeclarativescript_p.h
index dbf94b265c..a83cd9f8f0 100644
--- a/src/declarative/qml/qdeclarativescript_p.h
+++ b/src/declarative/qml/qdeclarativescript_p.h
@@ -279,6 +279,8 @@ public:
// True if this property is a property alias. Set by the
// QDeclarativeCompiler
bool isAlias;
+ // True if this is a readonly property declaration
+ bool isReadOnlyDeclaration;
// Used for scriptStringProperties
int scriptStringScope;
@@ -388,7 +390,9 @@ public:
enum Type { Var, Variant, Int, Bool, Real, String, Url, Color,
Time, Date, DateTime, Alias, Custom, CustomList };
- bool isDefaultProperty;
+ quint32 isDefaultProperty:1;
+ quint32 isReadOnly:1;
+
Type type;
QHashedStringRef customType;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml
new file mode 100644
index 0000000000..5377d2dcbf
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+
+QtObject {
+ property int dummy: 13
+
+ readonly property int test1: 19
+ readonly property int test2: dummy * 49
+ readonly property alias test3: other.test
+
+ property bool test: false
+
+ property var dummyObj: QtObject {
+ id: other
+ property int test: 9
+ }
+
+ Component.onCompleted: {
+ if (test1 != 19) return;
+ if (test2 != 637) return;
+ if (test3 != 9) return;
+
+ var caught = false;
+
+ caught = false;
+ try { test1 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ caught = false;
+ try { test2 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ caught = false;
+ try { test3 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ other.test = 13;
+ dummy = 9;
+
+ if (test1 != 19) return;
+ if (test2 != 441) return;
+ if (test3 != 13) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index 31aefd264e..c92dc809e9 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -169,7 +169,7 @@ private slots:
void booleanConversion();
void handleReferenceManagement();
void stringArg();
-
+ void readonlyDeclaration();
void bug1();
void bug2();
void dynamicCreationCrash();
@@ -4036,6 +4036,18 @@ void tst_qdeclarativeecmascript::stringArg()
delete object;
}
+void tst_qdeclarativeecmascript::readonlyDeclaration()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qdeclarativeecmascript::nullObjectBinding()
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml
new file mode 100644
index 0000000000..456ac762fc
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ readonly property int readOnlyProperty: 19
+}
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt
deleted file mode 100644
index 32a8dc11e1..0000000000
--- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt
+++ /dev/null
@@ -1 +0,0 @@
-4:5:Readonly not yet supported
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml
deleted file mode 100644
index a1401d2fdc..0000000000
--- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml
+++ /dev/null
@@ -1,6 +0,0 @@
-import QtQuick 2.0
-
-QtObject {
- readonly property int a: value
-}
-
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt
index baf47667bc..e71ae4447c 100644
--- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt
+++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt
@@ -1 +1 @@
-3:27:Invalid property assignment: "readOnlyEnumProperty" is a read-only property
+2:23:Invalid property assignment: "readOnlyProperty" is a read-only property
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml
index 422d13d8d0..d80b27a1e3 100644
--- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml
+++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml
@@ -1,4 +1,3 @@
-import Test 1.0
-MyTypeObject {
- readOnlyEnumProperty: MyTypeObject.EnumValue1
+ReadOnlyType {
+ readOnlyProperty: 13
}
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml
new file mode 100644
index 0000000000..493a9ad502
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml
@@ -0,0 +1,17 @@
+import Test 1.0
+
+MyQmlObject {
+ property int testData: 9
+ property alias testData2: myObject.test1
+
+ readonly property int test1: 10
+ readonly property int test2: testData + 9
+ readonly property alias test3: myObject.test1
+
+
+ property variant dummy: MyQmlObject {
+ id: myObject
+ property int test1: 13
+ }
+}
+
diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
index 538ebbb1a3..64ab5d8d39 100644
--- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
+++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
@@ -156,6 +156,7 @@ private slots:
void inlineAssignmentsOverrideBindings();
void nestedComponentRoots();
void registrationOrder();
+ void readonly();
void basicRemote_data();
void basicRemote();
@@ -364,7 +365,6 @@ void tst_qdeclarativelanguage::errors_data()
QTest::newRow("property.2") << "property.2.qml" << "property.2.errors.txt" << false;
QTest::newRow("property.3") << "property.3.qml" << "property.3.errors.txt" << false;
QTest::newRow("property.4") << "property.4.qml" << "property.4.errors.txt" << false;
- QTest::newRow("property.5") << "property.5.qml" << "property.5.errors.txt" << false;
QTest::newRow("property.6") << "property.6.qml" << "property.6.errors.txt" << false;
QTest::newRow("property.7") << "property.7.qml" << "property.7.errors.txt" << false;
@@ -2142,6 +2142,40 @@ void tst_qdeclarativelanguage::registrationOrder()
delete o;
}
+void tst_qdeclarativelanguage::readonly()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("readonly.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toInt(), 10);
+ QCOMPARE(o->property("test2").toInt(), 18);
+ QCOMPARE(o->property("test3").toInt(), 13);
+
+ o->setProperty("testData", 13);
+
+ QCOMPARE(o->property("test1").toInt(), 10);
+ QCOMPARE(o->property("test2").toInt(), 22);
+ QCOMPARE(o->property("test3").toInt(), 13);
+
+ o->setProperty("testData2", 2);
+
+ QCOMPARE(o->property("test1").toInt(), 10);
+ QCOMPARE(o->property("test2").toInt(), 22);
+ QCOMPARE(o->property("test3").toInt(), 2);
+
+ o->setProperty("test1", 11);
+ o->setProperty("test2", 11);
+ o->setProperty("test3", 11);
+
+ QCOMPARE(o->property("test1").toInt(), 10);
+ QCOMPARE(o->property("test2").toInt(), 22);
+ QCOMPARE(o->property("test3").toInt(), 2);
+
+ delete o;
+}
+
// QTBUG-18268
void tst_qdeclarativelanguage::remoteLoadCrash()
{