diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-30 08:37:37 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-30 18:21:45 +0200 |
commit | 385890bfdb165b397b29d3b62099f0687b358510 (patch) | |
tree | 3a1fd22eec98e521e560ae0d4cdfe16fa84ea045 /src/qml/qml | |
parent | d05151d735540f22ee3af75fdc7b2848dde2fe6f (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.h | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 82 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 21 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 10 |
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, ¬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)); + } + } + } +} 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(); |