aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertyvalidator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlpropertyvalidator.cpp')
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp279
1 files changed, 138 insertions, 141 deletions
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 7aeef30d9d..ff22c3043a 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -1,57 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvalidator_p.h"
#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlglobal_p.h>
#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlstringconverters_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
-static bool isPrimitiveType(int typeId)
+static bool isPrimitiveType(QMetaType metaType)
{
- switch (typeId) {
+ switch (metaType.id()) {
#define HANDLE_PRIMITIVE(Type, id, T) \
case QMetaType::Type:
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
@@ -62,7 +28,8 @@ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
}
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
, imports(imports)
@@ -106,19 +73,26 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return errors;
}
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
+ && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return validateObject(componentBinding->value.objectIndex, componentBinding);
}
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches.at(objectIndex);
if (!propertyCache)
return QVector<QQmlError>();
QQmlCustomParser *customParser = nullptr;
if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
+
+ // This binding instantiates a separate object. The separate object can have an ID and its
+ // own group properties even if it's then assigned to a value type, for example a 'var', or
+ // anything with an invokable ctor taking a QObject*.
+ populatingValueTypeGroupProperty = false;
+
const auto type = typeRef->type();
if (type.isValid())
customParser = type.customParser();
@@ -134,7 +108,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -148,9 +122,9 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
QQmlPropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
+ const QQmlPropertyData *defaultProperty = nullptr;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
+ const QQmlPropertyCache *cache = propertyCache->parent().data();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
@@ -158,19 +132,21 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
defaultProperty = propertyCache->defaultProperty();
}
- QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
QString name = stringAt(binding->propertyNameIndex);
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
continue;
}
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ } else if (QQmlSignalNames::isHandlerName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
continue;
@@ -178,13 +154,14 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+ bool isGroupProperty = instantiatingBinding
+ && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
- QQmlPropertyData *pd = nullptr;
+ const QQmlPropertyData *pd = nullptr;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
@@ -222,17 +199,20 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
QQmlType type;
QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, &typeNamespace);
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &type, 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())) {
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty() || binding->isGroupProperty())) {
const bool populatingValueTypeGroupProperty
= pd
- && QQmlMetaType::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
+ && QQmlMetaType::metaObjectForValueType(pd->propType())
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
@@ -241,15 +221,25 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
+ | QV4::CompiledData::Binding::IsSignalHandlerObject
+ | QV4::CompiledData::Binding::IsPropertyObserver)) {
continue;
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- return recordError(binding->location, tr("Attached properties cannot be used here"));
+ if ((pd && bindingType == QV4::CompiledData::Binding::Type_AttachedProperty)
+ || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupProperty)) {
+ if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
+ || instantiatingBinding->isGroupProperty())) {
+ return recordError(
+ binding->location, tr("%1 properties cannot be used here")
+ .arg(bindingType == QV4::CompiledData::Binding::Type_AttachedProperty
+ ? QStringLiteral("Attached")
+ : QStringLiteral("Group")));
}
continue;
+ } else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ continue;
}
if (pd) {
@@ -259,15 +249,15 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!pd->isWritable()
&& !pd->isQList()
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
) {
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
QString error;
if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
@@ -278,7 +268,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!bindingToDefaultProperty
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& assigningToGroupProperty) {
QV4::CompiledData::Location loc = binding->valueLocation;
if (loc < (*assignedGroupProperty)->valueLocation)
@@ -289,17 +279,17 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
if (bindingError.isValid())
return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
QQmlError bindingError = validateObjectBinding(pd, name, binding);
if (bindingError.isValid())
return recordError(bindingError);
} else if (binding->isGroupProperty()) {
if (QQmlMetaType::isValueType(pd->propType())) {
- if (QQmlMetaType::metaObjectForMetaType(pd->propType())) {
+ if (QQmlMetaType::metaObjectForValueType(pd->propType())) {
if (!pd->isWritable()) {
return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
@@ -307,22 +297,30 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- const int typeId = pd->propType().id();
- if (isPrimitiveType(typeId)) {
+ const QMetaType type = pd->propType();
+ if (isPrimitiveType(type)) {
return recordError(
binding->location,
tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType(typeId).name()))
+ .arg(name, QString::fromUtf8(type.name()))
);
}
- if (!enginePrivate->propertyCacheForType(typeId)) {
- 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(typeId).name()))
- );
+ if (!QQmlMetaType::propertyCacheForType(type)) {
+ auto mo = type.metaObject();
+ if (!mo) {
+ return recordError(binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ if (QMetaObjectPrivate::get(mo)->flags & DynamicMetaObject) {
+ return recordError(binding->location,
+ tr("Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ // fall through, this is okay
}
}
}
@@ -351,8 +349,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
customParser->clearErrors();
customParser->validator = this;
customParser->engine = enginePrivate;
- customParser->imports = &imports;
- customParser->verifyBindings(compilationUnit, customBindings);
+ customParser->imports = imports;
+ customParser->verifyBindings(
+ enginePrivate->v4engine()->executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>(compilationUnit)),
+ customBindings);
customParser->validator = nullptr;
customParser->engine = nullptr;
customParser->imports = (QQmlImports*)nullptr;
@@ -367,7 +368,9 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return noError;
}
-QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateLiteralBinding(
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
+ const QV4::CompiledData::Binding *binding) const
{
if (property->isQList()) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
@@ -376,7 +379,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
QQmlError noError;
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
+ return noError;
+
+ // TODO: For historical reasons you can assign any number to an enum property alias
+ // This can be fixed with an opt-out mechanism, for example a pragma.
+ if (property->isAlias() && binding->isNumberBinding())
return noError;
QString value = compilationUnit->bindingValueAsString(binding);
@@ -394,24 +402,14 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line));
- warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(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);
};
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
const auto isStringBinding = [&]() -> bool {
// validateLiteralBinding is not supposed to be used on scripts
- Q_ASSERT(binding->type != QV4::CompiledData::Binding::Type_Script);
- return binding->type == QV4::CompiledData::Binding::Type_String;
+ Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
+ return bindingType == QV4::CompiledData::Binding::Type_String;
};
switch (property->propType().id()) {
@@ -430,19 +428,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::QByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
case QMetaType::QUrl: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
case QMetaType::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -451,7 +447,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -460,13 +456,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
case QMetaType::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
@@ -564,7 +560,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
@@ -582,10 +578,10 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: return QString();
}
};
- QVariant result;
- if (!QQml_valueTypeProvider()->createValueType(
- property->propType().id(),
- compilationUnit->bindingValueAsString(binding), result)) {
+ const QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding),
+ property->propType());
+ if (!result.isValid()) {
return warnOrError(tr("Invalid property assignment: %1 expected")
.arg(typeName()));
}
@@ -596,12 +592,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -611,12 +607,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
@@ -630,15 +626,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
} else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
break;
} else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ && bindingType == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ } else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
break;
}
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType().id());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType(property->propType()).name())));
- }
+ return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
}
break;
}
@@ -649,17 +643,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
Returns true if from can be assigned to a (QObject) property of type
to.
*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
+bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const
{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
+ QQmlPropertyCache::ConstPtr toMo = QQmlMetaType::rawPropertyCacheForType(to);
- if (toMo == nullptr) {
+ if (toMo.isNull()) {
// if we have an inline component from the current file,
// it is not properly registered at this point, as registration
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum : compilationUnit->inlineComponentData) {
- if (icDatum.typeIds.id.id() == to) {
+ if (icDatum.qmlType.typeId() == to) {
toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}
@@ -688,26 +682,25 @@ QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) co
return errors;
}
-QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
{
QQmlError noError;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
bool isValueSource = false;
bool isPropertyInterceptor = false;
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();
+ QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
+ const QMetaObject *mo = cache ? cache->firstCppMetaObject() : nullptr;
QQmlType qmlType;
while (mo && !qmlType.isValid()) {
qmlType = QQmlMetaType::qmlType(mo);
mo = mo->superClass();
}
- Q_ASSERT(qmlType.isValid());
isValueSource = qmlType.propertyValueSourceCast() != -1;
isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
@@ -720,7 +713,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
return noError;
}
- const int propType = property->propType().id();
+ const QMetaType propType = property->propType();
const auto rhsType = [&]() {
return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
->inheritedTypeNameIndex);
@@ -730,19 +723,21 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::fromType<QVariant>()
+ || propType == QMetaType::fromType<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = QQmlMetaType::listType(propType);
+ const QMetaType listType = QQmlMetaType::listValueType(property->propType());
if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
}
}
return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
+ && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
auto typeName = QString::fromUtf8(QMetaType(propType).name());
@@ -750,7 +745,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
.arg(rhsType())
.arg(propertyName)
.arg(typeName));
- } else if (propType == qMetaTypeId<QQmlScriptString>()) {
+ } else if (propType == QMetaType::fromType<QQmlScriptString>()) {
return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else if (QQmlMetaType::isValueType(property->propType())) {
return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object")
@@ -760,15 +755,17 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
// Not passing a version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType);
+ QQmlPropertyCache::ConstPtr propertyMetaObject
+ = QQmlMetaType::rawPropertyCacheForType(propType);
if (!propertyMetaObject) {
// if we have an inline component from the current file,
// it is not properly registered at this point, as registration
// only occurs after the whole file has been validated
// Therefore we need to check the ICs here
for (const auto& icDatum: compilationUnit->inlineComponentData) {
- if (icDatum.typeIds.id == property->propType()) {
- propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ if (icDatum.qmlType.typeId() == property->propType()) {
+ propertyMetaObject
+ = compilationUnit->propertyCaches.at(icDatum.objectIndex);
break;
}
}
@@ -778,7 +775,7 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
// Will be true if the assigned type inherits propertyMetaObject
// Determine isAssignable value
bool isAssignable = false;
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();