From 385890bfdb165b397b29d3b62099f0687b358510 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 30 Sep 2013 08:37:37 +0200 Subject: [PATCH] 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 --- src/qml/compiler/qqmlcodegenerator.cpp | 2 +- src/qml/qml/qqmlcompiler_p.h | 8 +++- src/qml/qml/qqmlobjectcreator.cpp | 82 +++++++++++++++++++++++++++++++--- src/qml/qml/qqmlobjectcreator_p.h | 21 +++++++++ src/qml/qml/qqmltypeloader.cpp | 10 +++++ 5 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index ca4d8ec..84bab99 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -197,7 +197,7 @@ bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node) bool isType = lastId->name.unicode()->isUpper(); if (isType) { int idx = defineQMLObject(node); - appendBinding(AST::SourceLocation(), emptyStringIndex, idx); + appendBinding(node->qualifiedTypeNameId->identifierToken, emptyStringIndex, idx); } else { int idx = defineQMLObject(/*qualfied type name id*/0, node->initializer); appendBinding(node->qualifiedTypeNameId, idx); diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 475e438..b0fad47 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 c320ca9..8cc0246 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 &resolvedTypes, + const QList &propertyCaches, const QHash > &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 8412e22..ec4b362 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -115,6 +115,27 @@ protected: QHash > *objectIndexToIdPerComponent; }; +class QQmlPropertyValidator : public QQmlCompilePass +{ + Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) +public: + QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit, + const QHash &resolvedTypes, + const QList &propertyCaches, + const QHash > &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 &resolvedTypes; + const QList &propertyCaches; + const QHash > 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 63dff01..3dd071d 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(); -- 2.7.4