return false;
}
- // Child item:
- // ...
- // Item {
- // ...
- // }
- if (!property)
+ if (!property) // ### error
return true;
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
}
return true;
}
+
+
+QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent)
+ : QQmlCompilePass(url, qmlUnit)
+ , resolvedTypes(resolvedTypes)
+ , propertyCaches(propertyCaches)
+ , objectIndexToIdPerComponent(objectIndexToIdPerComponent)
+{
+}
+
+bool QQmlPropertyValidator::validate()
+{
+ for (int i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ continue;
+
+ if (isComponent(i))
+ continue;
+
+ QQmlPropertyCache *propertyCache = propertyCaches.value(i);
+ Q_ASSERT(propertyCache);
+
+ if (!validateObject(obj, i, propertyCache))
+ return false;
+ }
+ return true;
+}
+
+bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache)
+{
+ PropertyResolver propertyResolver(propertyCache);
+
+ QQmlPropertyData *defaultProperty = propertyCache->defaultProperty();
+
+ const QV4::CompiledData::Binding *binding = obj->bindingTable();
+ for (int i = 0; i < obj->nBindings; ++i, ++binding) {
+ if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty
+ || binding->type == QV4::CompiledData::Binding::Type_GroupProperty)
+ continue;
+
+ const QString name = stringAt(binding->propertyNameIndex);
+
+ bool bindingToDefaultProperty = false;
+
+ bool notInRevision = false;
+ QQmlPropertyData *pd = 0;
+ if (!name.isEmpty()) {
+ pd = propertyResolver.property(name, ¬InRevision);
+
+ if (notInRevision) {
+ QString typeName = stringAt(obj->inheritedTypeNameIndex);
+ QQmlCompiledData::TypeReference type = resolvedTypes.value(objectIndex);
+ if (type.type) {
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion));
+ } else {
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
+ }
+ }
+ } else {
+ pd = defaultProperty;
+ bindingToDefaultProperty = true;
+ }
+
+ if (!pd) {
+ if (bindingToDefaultProperty) {
+ COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property"));
+ } else {
+ COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
+ }
+ }
+ }
+}
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
};
+class QQmlPropertyValidator : public QQmlCompilePass
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
+public:
+ QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
+ const QList<QQmlPropertyCache *> &propertyCaches,
+ const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent);
+
+ bool validate();
+
+private:
+ bool validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache);
+
+ bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
+
+ const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes;
+ const QList<QQmlPropertyCache *> &propertyCaches;
+ const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
+};
+
class QmlObjectCreator : public QQmlCompilePass
{
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
ref.type = resolvedType->type;
Q_ASSERT(ref.type);
}
+ ref.majorVersion = resolvedType->majorVersion;
+ ref.minorVersion = resolvedType->minorVersion;
m_compiledData->resolvedTypes.insert(resolvedType.key(), ref);
}
}
}
+ // Sanity check property bindings
+ if (errors.isEmpty()) {
+ QQmlPropertyValidator validator(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes,
+ m_compiledData->propertyCaches, m_compiledData->objectIndexToIdPerComponent);
+ if (!validator.validate())
+ errors << validator.errors;
+ }
+
if (!errors.isEmpty()) {
setError(errors);
m_compiledData->release();