diff options
Diffstat (limited to 'src/qml/compiler/qqmlpropertyvalidator.cpp')
-rw-r--r-- | src/qml/compiler/qqmlpropertyvalidator.cpp | 228 |
1 files changed, 125 insertions, 103 deletions
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 383c20239f..4714f505a7 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -45,20 +45,20 @@ QT_BEGIN_NAMESPACE -QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, QV4::CompiledData::CompilationUnit *compilationUnit) +QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) : enginePrivate(enginePrivate) + , compilationUnit(compilationUnit) , imports(imports) - , qmlUnit(compilationUnit->data) - , resolvedTypes(compilationUnit->resolvedTypes) + , qmlUnit(compilationUnit->unitData()) , propertyCaches(compilationUnit->propertyCaches) , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject) { - bindingPropertyDataPerObject->resize(qmlUnit->nObjects); + bindingPropertyDataPerObject->resize(compilationUnit->objectCount()); } QVector<QQmlCompileError> QQmlPropertyValidator::validate() { - return validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0); + return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr); } typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector; @@ -81,7 +81,7 @@ struct BindingFinder QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); + const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex); if (obj->flags & QV4::CompiledData::Object::IsComponent) { Q_ASSERT(obj->nBindings == 1); @@ -94,20 +94,10 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, if (!propertyCache) return QVector<QQmlCompileError>(); - QStringList deferredPropertyNames; - { - const QMetaObject *mo = propertyCache->firstCppMetaObject(); - const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames"); - if (namesIndex != -1) { - QMetaClassInfo classInfo = mo->classInfo(namesIndex); - deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); - } - } - - QQmlCustomParser *customParser = 0; - if (auto typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { - if (typeRef->type) - customParser = typeRef->type->customParser(); + QQmlCustomParser *customParser = nullptr; + if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) { + if (typeRef->type.isValid()) + customParser = typeRef->type.customParser(); } QList<const QV4::CompiledData::Binding*> customBindings; @@ -134,7 +124,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, QmlIR::PropertyResolver propertyResolver(propertyCache); QString defaultPropertyName; - QQmlPropertyData *defaultProperty = 0; + QQmlPropertyData *defaultProperty = nullptr; if (obj->indexOfDefaultPropertyOrAlias != -1) { QQmlPropertyCache *cache = propertyCache->parent(); defaultPropertyName = cache->defaultPropertyName(); @@ -167,19 +157,21 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty; bool notInRevision = false; - QQmlPropertyData *pd = 0; + QQmlPropertyData *pd = nullptr; if (!name.isEmpty()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) { pd = propertyResolver.signal(name, ¬InRevision); - else - pd = propertyResolver.property(name, ¬InRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision); + } else { + pd = propertyResolver.property(name, ¬InRevision, + QmlIR::PropertyResolver::CheckRevision); + } if (notInRevision) { QString typeName = stringAt(obj->inheritedTypeNameIndex); - auto *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex); - if (objectType && objectType->type) { - return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion)); + auto *objectType = resolvedType(obj->inheritedTypeNameIndex); + if (objectType && objectType->type.isValid()) { + return recordError(binding->location, 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 { return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); } @@ -197,16 +189,22 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, collectedBindingPropertyData[i] = pd; if (name.constData()->isUpper() && !binding->isAttachedProperty()) { - QQmlType *type = 0; - QQmlImportNamespace *typeNamespace = 0; - imports.resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace); + QQmlType type; + QQmlImportNamespace *typeNamespace = nullptr; + imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, nullptr, &typeNamespace); if (typeNamespace) return recordError(binding->location, tr("Invalid use of namespace")); return recordError(binding->location, tr("Invalid attached object assignment")); } if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { - const QVector<QQmlCompileError> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())); + const bool populatingValueTypeGroupProperty + = pd + && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()) + && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment); + const QVector<QQmlCompileError> subObjectValidatorErrors + = validateObject(binding->value.objectIndex, binding, + populatingValueTypeGroupProperty); if (!subObjectValidatorErrors.isEmpty()) return subObjectValidatorErrors; } @@ -279,7 +277,11 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, } } else { if (!enginePrivate->propertyCacheForType(pd->propType())) { - return recordError(binding->location, tr("Invalid grouped property access")); + return recordError(binding->location, + tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type") + .arg(name) + .arg(QString::fromLatin1(QMetaType::typeName(pd->propType()))) + ); } } } @@ -297,6 +299,9 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, } if (obj->idNameIndex) { + if (populatingValueTypeGroupProperty) + return recordError(obj->locationOfIdProperty, tr("Invalid use of id property with a value type")); + bool notInRevision = false; collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), ¬InRevision); } @@ -306,10 +311,10 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, customParser->validator = this; customParser->engine = enginePrivate; customParser->imports = &imports; - customParser->verifyBindings(qmlUnit, customBindings); - customParser->validator = 0; - customParser->engine = 0; - customParser->imports = (QQmlImports*)0; + customParser->verifyBindings(compilationUnit, customBindings); + customParser->validator = nullptr; + customParser->engine = nullptr; + customParser->imports = (QQmlImports*)nullptr; QVector<QQmlCompileError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) return parserErrors; @@ -333,7 +338,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) return noError; - QString value = binding->valueAsString(qmlUnit); + QString value = binding->valueAsString(compilationUnit.data()); QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex()); bool ok; if (p.isFlagType()) { @@ -347,148 +352,163 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache return noError; } + auto warnOrError = [&](const QString &error) { + if (binding->type == QV4::CompiledData::Binding::Type_Null) { + QQmlError warning; + warning.setUrl(compilationUnit->url()); + warning.setLine(binding->valueLocation.line); + warning.setColumn(binding->valueLocation.column); + warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML " + "is deprecated. This will become a compile error in " + "future versions of Qt.")); + enginePrivate->warning(warning); + return noError; + } + return QQmlCompileError(binding->valueLocation, error); + }; + switch (property->propType()) { case QMetaType::QVariant: break; case QVariant::String: { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string expected")); + return warnOrError(tr("Invalid property assignment: string expected")); } } break; case QVariant::StringList: { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or string list expected")); + return warnOrError(tr("Invalid property assignment: string or string list expected")); } } break; case QVariant::ByteArray: { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: byte array expected")); + return warnOrError(tr("Invalid property assignment: byte array expected")); } } break; case QVariant::Url: { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url expected")); + return warnOrError(tr("Invalid property assignment: url expected")); } } break; case QVariant::UInt: { if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(); + double d = binding->valueAsNumber(compilationUnit->constants); if (double(uint(d)) == d) return noError; } - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected")); + return warnOrError(tr("Invalid property assignment: unsigned int expected")); } break; case QVariant::Int: { if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(); + double d = binding->valueAsNumber(compilationUnit->constants); if (double(int(d)) == d) return noError; } - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int expected")); + return warnOrError(tr("Invalid property assignment: int expected")); } break; case QMetaType::Float: { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected")); + return warnOrError(tr("Invalid property assignment: number expected")); } } break; case QVariant::Double: { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected")); + return warnOrError(tr("Invalid property assignment: number expected")); } } break; case QVariant::Color: { bool ok = false; - QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: color expected")); + return warnOrError(tr("Invalid property assignment: color expected")); } } break; #if QT_CONFIG(datestring) case QVariant::Date: { bool ok = false; - QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: date expected")); + return warnOrError(tr("Invalid property assignment: date expected")); } } break; case QVariant::Time: { bool ok = false; - QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: time expected")); + return warnOrError(tr("Invalid property assignment: time expected")); } } break; case QVariant::DateTime: { bool ok = false; - QQmlStringConverters::dateTimeFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: datetime expected")); + return warnOrError(tr("Invalid property assignment: datetime expected")); } } break; #endif // datestring case QVariant::Point: { bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; case QVariant::PointF: { bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; case QVariant::Size: { bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected")); + return warnOrError(tr("Invalid property assignment: size expected")); } } break; case QVariant::SizeF: { bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected")); + return warnOrError(tr("Invalid property assignment: size expected")); } } break; case QVariant::Rect: { bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: rect expected")); + return warnOrError(tr("Invalid property assignment: rect expected")); } } break; case QVariant::RectF: { bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok); + QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; case QVariant::Bool: { if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: boolean expected")); + return warnOrError(tr("Invalid property assignment: boolean expected")); } } break; @@ -497,8 +517,8 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float xp; float yp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + return warnOrError(tr("Invalid property assignment: 2D vector expected")); } } break; @@ -508,8 +528,8 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float yp; float zy; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected")); + if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + return warnOrError(tr("Invalid property assignment: 3D vector expected")); } } break; @@ -520,8 +540,8 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float zy; float wp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected")); + if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + return warnOrError(tr("Invalid property assignment: 4D vector expected")); } } break; @@ -532,55 +552,59 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float yp; float zp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + return warnOrError(tr("Invalid property assignment: quaternion expected")); } } break; case QVariant::RegExp: - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); + case QVariant::RegularExpression: + return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); default: { // generate single literal value assignment to a list property if required if (property->propType() == qMetaTypeId<QList<qreal> >()) { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected")); + return warnOrError(tr("Invalid property assignment: number or array of numbers expected")); } break; } else if (property->propType() == qMetaTypeId<QList<int> >()) { bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number); if (ok) { - double n = binding->valueAsNumber(); + double n = binding->valueAsNumber(compilationUnit->constants); if (double(int(n)) != n) ok = false; } if (!ok) - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected")); + return warnOrError(tr("Invalid property assignment: int or array of ints expected")); break; } else if (property->propType() == qMetaTypeId<QList<bool> >()) { if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected")); + return warnOrError(tr("Invalid property assignment: bool or array of bools expected")); } break; } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected")); + return warnOrError(tr("Invalid property assignment: url or array of urls expected")); } break; } else if (property->propType() == qMetaTypeId<QList<QString> >()) { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected")); + return warnOrError(tr("Invalid property assignment: string or array of strings expected")); } break; } else if (property->propType() == qMetaTypeId<QJSValue>()) { break; } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) { break; + } else if (property->isQObject() + && binding->type == QV4::CompiledData::Binding::Type_Null) { + break; } // otherwise, try a custom type assignment QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType()); if (!converter) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType())))); + return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType())))); } } break; @@ -628,21 +652,19 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * bool isValueSource = false; bool isPropertyInterceptor = false; - QQmlType *qmlType = 0; - const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex); - if (auto *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex)) { - QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex); + if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) { + QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); const QMetaObject *mo = cache->firstCppMetaObject(); - while (mo && !qmlType) { + QQmlType qmlType; + while (mo && !qmlType.isValid()) { qmlType = QQmlMetaType::qmlType(mo); mo = mo->superClass(); } - Q_ASSERT(qmlType); - } + Q_ASSERT(qmlType.isValid()); - if (qmlType) { - isValueSource = qmlType->propertyValueSourceCast() != -1; - isPropertyInterceptor = qmlType->propertyValueInterceptorCast() != -1; + isValueSource = qmlType.propertyValueSourceCast() != -1; + isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1; } if (!isValueSource && !isPropertyInterceptor) { @@ -656,7 +678,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * // Can only check at instantiation time if the created sub-object successfully casts to the // target interface. return noError; - } else if (property->propType() == QMetaType::QVariant) { + } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) { // We can convert everything to QVariant :) return noError; } else if (property->isQList()) { @@ -668,21 +690,20 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } } return noError; - } else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) { - return noError; } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) { return noError; } else if (QQmlValueTypeFactory::isValueType(property->propType())) { - return QQmlCompileError(binding->location, tr("Unexpected object assignment")); + return QQmlCompileError(binding->location, tr("Unexpected object assignment for property \"%1\"").arg(propertyName)); } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) { return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); } else { - // We want to raw metaObject here as the raw metaobject is the + // We want to use the raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might // effect the properties on the type, but don't effect assignability - QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType()); + // Using -1 for the minor version ensures that we get the raw metaObject. + QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1); - // Will be true if the assgned type inherits propertyMetaObject + // Will be true if the assigned type inherits propertyMetaObject bool isAssignable = false; // Determine isAssignable value if (propertyMetaObject) { @@ -694,7 +715,8 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } if (!isAssignable) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to property")); + return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") + .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType())))); } } return noError; |