[new compiler] Report errors when trying to bind to read-only properties
authorSimon Hausmann <simon.hausmann@digia.com>
Mon, 27 Jan 2014 12:09:01 +0000 (13:09 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Tue, 28 Jan 2014 09:41:52 +0000 (10:41 +0100)
The only exception are initializers for read-only property declarations.

Also adjusted the error location of one test to point to the correct value
location as opposed to the property location, as with all the other similar
errors.

Change-Id: I2333d3c485fc374b1b39a5f5a4408af5cf08a20f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qqmlcodegenerator.cpp
src/qml/compiler/qqmlcodegenerator_p.h
src/qml/compiler/qv4compileddata_p.h
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmlobjectcreator.cpp
tests/auto/qml/qqmllanguage/data/readOnly.2.errors.txt

index dfbee74..344c38b 100644 (file)
@@ -100,6 +100,7 @@ QStringList Signal::parameterStringList(const QStringList &stringPool) const
 QQmlCodeGenerator::QQmlCodeGenerator(const QSet<QString> &illegalNames)
     : illegalNames(illegalNames)
     , _object(0)
+    , _propertyDeclaration(0)
     , jsGenerator(0)
 {
 }
@@ -708,8 +709,11 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
                  propertyValue += alias.at(2);
              }
              property->aliasPropertyValueIndex = registerString(propertyValue);
-        } else if (node->statement)
-            appendBinding(node->identifierToken, property->nameIndex, node->statement);
+        } else if (node->statement) {
+            qSwap(_propertyDeclaration, property);
+            appendBinding(node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
+            qSwap(_propertyDeclaration, property);
+        }
 
         _object->properties->append(property);
 
@@ -725,8 +729,12 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
             _object->indexOfDefaultProperty = _object->properties->count - 1;
         }
 
-        // process QML-like initializers (e.g. property Object o: Object {})
-        AST::Node::accept(node->binding, this);
+        if (node->binding) {
+            qSwap(_propertyDeclaration, property);
+            // process QML-like initializers (e.g. property Object o: Object {})
+            AST::Node::accept(node->binding, this);
+            qSwap(_propertyDeclaration, property);
+        }
     }
 
     return false;
@@ -804,6 +812,8 @@ void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, AST
     binding->valueLocation.line = loc.startLine;
     binding->valueLocation.column = loc.startColumn;
     binding->type = QV4::CompiledData::Binding::Type_Invalid;
+    if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+        binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
 
     if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(statement)) {
         AST::ExpressionNode *expr = stmt->expression;
@@ -898,6 +908,9 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i
 
     binding->flags = 0;
 
+    if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly))
+        binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+
     // No type name on the initializer means it must be a group property
     if (stringAt(_objects.at(objectIndex)->inheritedTypeNameIndex).isEmpty())
         binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
index b597afc..92692a2 100644 (file)
@@ -299,6 +299,7 @@ public:
     QV4::CompiledData::TypeReferenceMap _typeReferences;
 
     QmlObject *_object;
+    QmlProperty *_propertyDeclaration;
 
     QQmlJS::MemoryPool *pool;
     QString sourceCode;
index 8fa3f83..06361fb 100644 (file)
@@ -282,7 +282,8 @@ struct Q_QML_EXPORT Binding
 
     enum Flags {
         IsSignalHandlerExpression = 0x1,
-        IsOnAssignment = 0x2
+        IsOnAssignment = 0x2,
+        InitializerForReadOnlyDeclaration = 0x4
     };
 
     quint32 flags : 16;
index 0dd4ea0..821ac46 100644 (file)
@@ -3456,7 +3456,7 @@ bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
     Q_ASSERT(prop->parent->metatype);
 
     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()));
+        COMPILE_EXCEPTION(value, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString()));
 
     JSBindingReference *reference = pool->New<JSBindingReference>();
     reference->expression = value->value;
index 67c2170..bd5a212 100644 (file)
@@ -594,7 +594,7 @@ void QmlObjectCreator::setupBindings()
     QString id = stringAt(_compiledObject->idIndex);
     if (!id.isEmpty()) {
         QQmlPropertyData *idProperty = _propertyCache->property(QStringLiteral("id"), _qobject, context);
-        if (idProperty) {
+        if (idProperty && idProperty->isWritable()) {
             QV4::CompiledData::Binding idBinding;
             idBinding.propertyNameIndex = 0; // Not used
             idBinding.flags = 0;
@@ -635,6 +635,17 @@ void QmlObjectCreator::setupBindings()
 
 bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
 {
+    if (property && !property->isWritable()
+        && !property->isQList()
+        && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
+        && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+        && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+        && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+        ) {
+        recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(property->name(_qobject)));
+        return false;
+    }
+
     if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
         Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
         QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex);
index d857a04..b8c3404 100644 (file)
@@ -1 +1 @@
-3:5:Invalid property assignment: "readOnlyString" is a read-only property
+3:21:Invalid property assignment: "readOnlyString" is a read-only property