aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-30 08:37:37 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-30 18:21:45 +0200
commit385890bfdb165b397b29d3b62099f0687b358510 (patch)
tree3a1fd22eec98e521e560ae0d4cdfe16fa84ea045 /src/qml/qml
parentd05151d735540f22ee3af75fdc7b2848dde2fe6f (diff)
Fix error messages when assigning to non-existent properties in new compiler
Introduce a simple valdator pass early on to catch those assignments. Also fix storing the correct line/col for default property object bindings and remember the minor/major version of an import in the final type reference. Change-Id: Ib2a93dfe1a30fcd9c09b5443fb8199ad11b19769 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqmlcompiler_p.h8
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp82
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h21
-rw-r--r--src/qml/qml/qqmltypeloader.cpp10
4 files changed, 114 insertions, 7 deletions
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 475e43823a..b0fad4708b 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -101,12 +101,18 @@ public:
struct TypeReference
{
TypeReference()
- : type(0), typePropertyCache(0), component(0) {}
+ : type(0), typePropertyCache(0), component(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ {}
QQmlType *type;
QQmlPropertyCache *typePropertyCache;
QQmlCompiledData *component;
+ int majorVersion;
+ int minorVersion;
+
QQmlPropertyCache *propertyCache() const;
QQmlPropertyCache *createPropertyCache(QQmlEngine *);
};
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index c320ca9e4a..8cc0246153 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1025,12 +1025,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
return false;
}
- // Child item:
- // ...
- // Item {
- // ...
- // }
- if (!property)
+ if (!property) // ### error
return true;
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
@@ -1674,3 +1669,78 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
}
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, &notInRevision);
+
+ 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));
+ }
+ }
+ }
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 8412e227dd..ec4b362491 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -115,6 +115,27 @@ protected:
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)
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 63dff012a2..3dd071dafc 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2297,6 +2297,8 @@ void QQmlTypeData::compile()
ref.type = resolvedType->type;
Q_ASSERT(ref.type);
}
+ ref.majorVersion = resolvedType->majorVersion;
+ ref.minorVersion = resolvedType->minorVersion;
m_compiledData->resolvedTypes.insert(resolvedType.key(), ref);
}
@@ -2425,6 +2427,14 @@ void QQmlTypeData::compile()
}
}
+ // 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();