diff options
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 64 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 63 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 6 |
6 files changed, 84 insertions, 64 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 7fb3b123b0..dfbee74446 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -800,6 +800,9 @@ QStringRef QQmlCodeGenerator::textRefAt(const AST::SourceLocation &first, const void QQmlCodeGenerator::setBindingValue(QV4::CompiledData::Binding *binding, AST::Statement *statement) { + AST::SourceLocation loc = statement->firstSourceLocation(); + binding->valueLocation.line = loc.startLine; + binding->valueLocation.column = loc.startColumn; binding->type = QV4::CompiledData::Binding::Type_Invalid; if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(statement)) { @@ -889,6 +892,10 @@ void QQmlCodeGenerator::appendBinding(const AST::SourceLocation &nameLocation, i binding->propertyNameIndex = propertyNameIndex; binding->location.line = nameLocation.startLine; binding->location.column = nameLocation.startColumn; + + const QmlObject *obj = _objects.at(objectIndex); + binding->valueLocation = obj->location; + binding->flags = 0; // No type name on the initializer means it must be a group property @@ -978,6 +985,7 @@ bool QQmlCodeGenerator::resolveQualifiedId(AST::UiQualifiedId **nameToResolve, Q binding->propertyNameIndex = registerString(currentName); binding->location.line = qualifiedIdElement->identifierToken.startLine; binding->location.column = qualifiedIdElement->identifierToken.startColumn; + binding->valueLocation.line = binding->valueLocation.column = 0; binding->flags = 0; if (qualifiedIdElement->name.unicode()->isUpper()) diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 06ee180119..c090f0ab41 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -380,6 +380,20 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r const QmlObject *obj = qmlObjects.at(objectIndex); QQmlPropertyCache *baseTypeCache = 0; + QQmlPropertyData *instantiatingProperty = 0; + if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { + Q_ASSERT(referencingObjectIndex >= 0); + QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); + Q_ASSERT(parentCache); + Q_ASSERT(!stringAt(instantiatingBinding->propertyNameIndex).isEmpty()); + + bool notInRevision = false; + instantiatingProperty = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); + if (instantiatingProperty && instantiatingProperty->isQObject()) { + baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType); + Q_ASSERT(baseTypeCache); + } + } bool needVMEMetaObject = obj->properties->count != 0 || obj->qmlSignals->count != 0 || obj->functions->count != 0; if (!needVMEMetaObject) { @@ -393,22 +407,10 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r // group properties and value type group properties. For the former the base type is derived from // the property that references us, for the latter we only need a meta-object on the referencing object // because interceptors can't go to the shared value type instances. - if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { - QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); - Q_ASSERT(parentCache); - Q_ASSERT(!stringAt(instantiatingBinding->propertyNameIndex).isEmpty()); - - bool notInRevision = false; - QQmlPropertyData *pd = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); - Q_ASSERT(pd); - if (QQmlValueTypeFactory::isValueType(pd->propType)) { - needVMEMetaObject = false; - if (!ensureMetaObject(referencingObjectIndex)) - return false; - } else if (pd->isQObject()) { - baseTypeCache = enginePrivate->rawPropertyCacheForType(pd->propType); - Q_ASSERT(baseTypeCache); - } + if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) { + needVMEMetaObject = false; + if (!ensureMetaObject(referencingObjectIndex)) + return false; } break; } @@ -431,10 +433,12 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r baseTypeCache->addref(); } - for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) - if (binding->type == QV4::CompiledData::Binding::Type_Object) - if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) - return false; + if (propertyCaches.at(objectIndex)) { + for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) + if (binding->type == QV4::CompiledData::Binding::Type_Object || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) + if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) + return false; + } return true; } @@ -1152,7 +1156,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler, con bool QQmlPropertyValidator::validate() { - if (!validateObject(qmlUnit->indexOfRootObject)) + if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) return false; compiler->setCustomParserBindings(customParserBindings); return true; @@ -1179,22 +1183,19 @@ QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::Comp return id; } -bool QQmlPropertyValidator::validateObject(int objectIndex) +bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding) { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); - if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) - return true; - if (isComponent(objectIndex)) return true; QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); - Q_ASSERT(propertyCache); + if (!propertyCache) + return true; QQmlCustomParser *customParser = 0; QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex); - Q_ASSERT(objectType); - if (objectType->type) + if (objectType && objectType->type) customParser = objectType->type->customParser(); QList<const QV4::CompiledData::Binding*> customBindings; @@ -1223,7 +1224,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex) } if (binding->type >= QV4::CompiledData::Binding::Type_Object) { - if (!validateObject(binding->value.objectIndex)) + if (!validateObject(binding->value.objectIndex, binding)) return false; // Nothing further to check for attached properties. if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) @@ -1244,13 +1245,16 @@ bool QQmlPropertyValidator::validateObject(int objectIndex) if (notInRevision) { QString typeName = stringAt(obj->inheritedTypeNameIndex); - if (objectType->type) { + if (objectType && objectType->type) { COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion)); } else { COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); } } } else { + if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) + COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property")); + pd = defaultProperty; bindingToDefaultProperty = true; } diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 28229a13a9..29c045816d 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -190,7 +190,7 @@ public: virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser); private: - bool validateObject(int objectIndex); + bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding); bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 4208ec9441..8fa3f83ea4 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -70,8 +70,8 @@ struct RegExp; struct Location { - int line; - int column; + qint32 line; + qint32 column; }; // map from name index to location of first use @@ -296,6 +296,7 @@ struct Q_QML_EXPORT Binding quint32 stringIndex; // Set for Type_String and Type_Script (the latter because of script strings) Location location; + Location valueLocation; QString valueAsString(const Unit *unit) const; QString valueAsScriptString(const Unit *unit) const; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 24a8327722..67c21706c5 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -187,7 +187,8 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C // ### This should be resolved earlier at compile time and the binding value should be changed accordingly. if (property->isEnum()) { QVariant value = binding->valueAsString(&qmlUnit->header); - QQmlPropertyPrivate::write(_qobject, *property, value, context); + if (!QQmlPropertyPrivate::write(_qobject, *property, value, context)) + recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); return; } @@ -240,7 +241,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: string expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: string expected")); } } break; @@ -250,7 +251,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: string or string list expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected")); } } break; @@ -260,7 +261,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: byte array expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected")); } } break; @@ -276,7 +277,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: url expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: url expected")); } } break; @@ -290,7 +291,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C break; } } - recordError(binding->location, tr("Invalid property assignment: unsigned int expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected")); } break; case QVariant::Int: { @@ -303,7 +304,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C break; } } - recordError(binding->location, tr("Invalid property assignment: int expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: int expected")); } break; case QMetaType::Float: { @@ -312,7 +313,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: number expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: number expected")); } } break; @@ -322,7 +323,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: number expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: number expected")); } } break; @@ -337,7 +338,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } } else { - recordError(binding->location, tr("Invalid property assignment: color expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: color expected")); } } break; @@ -349,7 +350,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: date expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: date expected")); } } break; @@ -360,7 +361,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: time expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: time expected")); } } break; @@ -371,7 +372,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: datetime expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected")); } } break; @@ -383,7 +384,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: point expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); } } break; @@ -394,7 +395,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: point expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); } } break; @@ -405,7 +406,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: size expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: size expected")); } } break; @@ -416,7 +417,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: size expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: size expected")); } } break; @@ -427,7 +428,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: point expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: rect expected")); } } break; @@ -438,7 +439,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: point expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); } } break; @@ -448,7 +449,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = &value; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: boolean expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected")); } } break; @@ -462,7 +463,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&vec); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: 3D vector expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected")); } } break; @@ -477,12 +478,12 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&vec); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: 4D vector expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected")); } } break; case QVariant::RegExp: - recordError(binding->location, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); + recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); break; default: { // generate single literal value assignment to a list property if required @@ -493,7 +494,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&value); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: real or array of reals expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected")); } break; } else if (property->propType == qMetaTypeId<QList<int> >()) { @@ -506,7 +507,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); break; } else { - recordError(binding->location, tr("Invalid property assignment: int or array of ints expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected")); } } break; @@ -517,7 +518,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&value); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: bool or array of bools expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected")); } break; } else if (property->propType == qMetaTypeId<QList<QUrl> >()) { @@ -529,7 +530,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&value); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: url or array of urls expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected")); } break; } else if (property->propType == qMetaTypeId<QList<QString> >()) { @@ -539,7 +540,7 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C argv[0] = reinterpret_cast<void *>(&value); QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Invalid property assignment: string or array of strings expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected")); } break; } else if (property->propType == qMetaTypeId<QJSValue>()) { @@ -667,6 +668,10 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI QObject *createdSubObject = 0; if (binding->type == QV4::CompiledData::Binding::Type_Object) { + if (_valueTypeProperty) { + recordError(binding->location, tr("Unexpected object assignment")); + return false; + } createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget); if (!createdSubObject) return false; @@ -866,7 +871,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI argv[0] = &createdSubObject; QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } else { - recordError(binding->location, tr("Cannot assign object to property")); + recordError(binding->valueLocation, tr("Cannot assign object to property")); return false; } } diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 6110e4870f..fade1256b0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -520,11 +520,13 @@ void tst_qqmllanguage::errors() { QFETCH(QString, file); QFETCH(QString, errorFile); - QFETCH(bool, create); + // ### FIXME: re-enable these create "checks" when the new compiler is default and does property binding compatibility tests + // in the loader thread. +// QFETCH(bool, create); QQmlComponent component(&engine, testFileUrl(file)); - if(create) { + if (/*create && */component.isReady()) { QObject *object = component.create(); QVERIFY(object == 0); } |