6#include <private/qqmlcustomparser_p.h>
7#include <private/qqmlglobal_p.h>
8#include <private/qqmlirbuilder_p.h>
9#include <private/qqmlpropertycachecreator_p.h>
10#include <private/qqmlpropertyresolver_p.h>
11#include <private/qqmlstringconverters_p.h>
12#include <private/qqmlsignalnames_p.h>
14#include <QtCore/qdatetime.h>
20 switch (metaType.
id()) {
21#define HANDLE_PRIMITIVE(Type, id, T) \
24#undef HANDLE_PRIMITIVE
32 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
33 : enginePrivate(enginePrivate)
34 , compilationUnit(compilationUnit)
36 , qmlUnit(compilationUnit->unitData())
37 , propertyCaches(compilationUnit->propertyCaches)
38 , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
40 bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
45 return validateObject(0,
nullptr);
66QVector<QQmlError> QQmlPropertyValidator::validateObject(
70 for (
auto it =
obj->inlineComponentsBegin();
it !=
obj->inlineComponentsEnd(); ++
it) {
71 const auto errors = validateObject(
it->objectIndex,
nullptr);
72 if (!errors.isEmpty())
81 return validateObject(componentBinding->value.objectIndex, componentBinding);
86 return QVector<QQmlError>();
89 if (
auto typeRef = resolvedType(
obj->inheritedTypeNameIndex)) {
94 populatingValueTypeGroupProperty =
false;
96 const auto type = typeRef->type();
98 customParser =
type.customParser();
101 QList<const QV4::CompiledData::Binding*> customBindings;
114 if (populatingValueTypeGroupProperty) {
115 return recordError(binding->
location,
tr(
"Property assignment expected"));
118 GroupPropertyVector::const_iterator
pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->
propertyNameIndex,
BindingFinder());
119 groupProperties.insert(
pos, binding);
126 if (
obj->indexOfDefaultPropertyOrAlias != -1) {
128 defaultPropertyName =
cache->defaultPropertyName();
129 defaultProperty =
cache->defaultProperty();
131 defaultPropertyName = propertyCache->defaultPropertyName();
132 defaultProperty = propertyCache->defaultProperty();
137 binding =
obj->bindingTable();
141 const QV4::CompiledData::Binding::Flags bindingFlags = binding->
flags();
146 customBindings << binding;
151 customBindings << binding;
156 bool bindingToDefaultProperty =
false;
157 bool isGroupProperty = instantiatingBinding
160 bool notInRevision =
false;
162 if (!
name.isEmpty()) {
165 pd = propertyResolver.signal(
name, ¬InRevision);
167 pd = propertyResolver.property(
name, ¬InRevision,
173 if (
auto *objectType = resolvedType(
obj->inheritedTypeNameIndex)) {
174 const auto type = objectType->type();
175 if (
type.isValid()) {
176 const auto version = objectType->version();
177 return recordError(binding->
location,
178 tr(
"\"%1.%2\" is not available in %3 %4.%5.")
180 .arg(version.majorVersion())
181 .arg(version.minorVersion()));
189 return recordError(binding->
location,
tr(
"Cannot assign a value directly to a grouped property"));
191 pd = defaultProperty;
192 name = defaultPropertyName;
193 bindingToDefaultProperty =
true;
197 collectedBindingPropertyData[
i] = pd;
204 &
type,
nullptr, &typeNamespace);
206 return recordError(binding->
location,
tr(
"Invalid use of namespace"));
207 return recordError(binding->
location,
tr(
"Invalid attached object assignment"));
212 const bool populatingValueTypeGroupProperty
216 const QVector<QQmlError> subObjectValidatorErrors
217 = validateObject(binding->
value.objectIndex, binding,
218 populatingValueTypeGroupProperty);
219 if (!subObjectValidatorErrors.isEmpty())
220 return subObjectValidatorErrors;
235 binding->
location,
tr(
"%1 properties cannot be used here")
246 GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->
propertyNameIndex,
BindingFinder());
247 const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->
propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
256 return recordError(binding->
valueLocation,
tr(
"Cannot assign a value directly to a grouped property"));
257 return recordError(binding->
valueLocation,
tr(
"Invalid property assignment: \"%1\" is a read-only property").
arg(
name));
262 if (pd->
propType() == QMetaType::fromType<QQmlScriptString>())
263 error =
tr(
"Cannot assign multiple values to a script property");
265 error =
tr(
"Cannot assign multiple values to a singular property");
269 if (!bindingToDefaultProperty
272 && assigningToGroupProperty) {
274 if (loc < (*assignedGroupProperty)->valueLocation)
275 loc = (*assignedGroupProperty)->valueLocation;
278 return recordError(loc,
tr(
"Property has already been assigned a value"));
279 return recordError(loc,
tr(
"Cannot assign a value directly to a grouped property"));
283 QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
285 return recordError(bindingError);
287 QQmlError bindingError = validateObjectBinding(pd,
name, binding);
289 return recordError(bindingError);
294 return recordError(binding->
location,
tr(
"Invalid property assignment: \"%1\" is a read-only property").
arg(
name));
297 return recordError(binding->
location,
tr(
"Invalid grouped property access"));
304 tr(
"Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
310 auto mo =
type.metaObject();
312 return recordError(binding->
location,
313 tr(
"Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
318 return recordError(binding->
location,
319 tr(
"Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
329 customBindings << binding;
332 if (bindingToDefaultProperty) {
333 return recordError(binding->
location,
tr(
"Cannot assign to non-existent default property"));
335 return recordError(binding->
location,
tr(
"Cannot assign to non-existent property \"%1\"").
arg(
name));
340 if (
obj->idNameIndex) {
341 if (populatingValueTypeGroupProperty)
342 return recordError(
obj->locationOfIdProperty,
tr(
"Invalid use of id property with a value type"));
344 bool notInRevision =
false;
345 collectedBindingPropertyData << propertyResolver.property(
QStringLiteral(
"id"), ¬InRevision);
348 if (customParser && !customBindings.isEmpty()) {
350 customParser->validator =
this;
351 customParser->engine = enginePrivate;
352 customParser->imports = imports;
355 QQmlRefPointer<QV4::CompiledData::CompilationUnit>(compilationUnit)),
357 customParser->validator =
nullptr;
358 customParser->engine =
nullptr;
360 QVector<QQmlError> parserErrors = customParser->
errors();
361 if (!parserErrors.isEmpty())
365 (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
367 QVector<QQmlError> noError;
371QQmlError QQmlPropertyValidator::validateLiteralBinding(
393 if (
p.isFlagType()) {
394 p.enumerator().keysToValue(
value.toUtf8().constData(), &
ok);
396 p.enumerator().keyToValue(
value.toUtf8().constData(), &
ok);
409 const auto isStringBinding = [&]() ->
bool {
415 switch (
property->propType().id()) {
418 case QMetaType::QString: {
420 return warnOrError(
tr(
"Invalid property assignment: string expected"));
424 case QMetaType::QStringList: {
426 return warnOrError(
tr(
"Invalid property assignment: string or string list expected"));
430 case QMetaType::QByteArray: {
432 return warnOrError(
tr(
"Invalid property assignment: byte array expected"));
435 case QMetaType::QUrl: {
437 return warnOrError(
tr(
"Invalid property assignment: url expected"));
440 case QMetaType::UInt: {
446 return warnOrError(
tr(
"Invalid property assignment: unsigned int expected"));
449 case QMetaType::Int: {
452 if (
double(
int(
d)) ==
d)
455 return warnOrError(
tr(
"Invalid property assignment: int expected"));
458 case QMetaType::Float: {
460 return warnOrError(
tr(
"Invalid property assignment: number expected"));
464 case QMetaType::Double: {
466 return warnOrError(
tr(
"Invalid property assignment: number expected"));
470 case QMetaType::QColor: {
472 if (isStringBinding())
475 return warnOrError(
tr(
"Invalid property assignment: color expected"));
479#if QT_CONFIG(datestring)
480 case QMetaType::QDate: {
482 if (isStringBinding())
485 return warnOrError(
tr(
"Invalid property assignment: date expected"));
489 case QMetaType::QTime: {
491 if (isStringBinding())
494 return warnOrError(
tr(
"Invalid property assignment: time expected"));
498 case QMetaType::QDateTime: {
500 if (isStringBinding())
503 return warnOrError(
tr(
"Invalid property assignment: datetime expected"));
508 case QMetaType::QPoint: {
510 if (isStringBinding())
513 return warnOrError(
tr(
"Invalid property assignment: point expected"));
517 case QMetaType::QPointF: {
519 if (isStringBinding())
522 return warnOrError(
tr(
"Invalid property assignment: point expected"));
526 case QMetaType::QSize: {
528 if (isStringBinding())
531 return warnOrError(
tr(
"Invalid property assignment: size expected"));
535 case QMetaType::QSizeF: {
537 if (isStringBinding())
540 return warnOrError(
tr(
"Invalid property assignment: size expected"));
544 case QMetaType::QRect: {
546 if (isStringBinding())
549 return warnOrError(
tr(
"Invalid property assignment: rect expected"));
553 case QMetaType::QRectF: {
555 if (isStringBinding())
558 return warnOrError(
tr(
"Invalid property assignment: point expected"));
562 case QMetaType::Bool: {
564 return warnOrError(
tr(
"Invalid property assignment: boolean expected"));
568 case QMetaType::QVector2D:
569 case QMetaType::QVector3D:
570 case QMetaType::QVector4D:
571 case QMetaType::QQuaternion: {
573 switch (
property->propType().id()) {
585 return warnOrError(
tr(
"Invalid property assignment: %1 expected")
590 case QMetaType::QRegularExpression:
591 return warnOrError(
tr(
"Invalid property assignment: regular expression expected; use /pattern/ syntax"));
596 return warnOrError(
tr(
"Invalid property assignment: number or array of numbers expected"));
603 if (
double(
int(
n)) !=
n)
607 return warnOrError(
tr(
"Invalid property assignment: int or array of ints expected"));
611 return warnOrError(
tr(
"Invalid property assignment: bool or array of bools expected"));
616 return warnOrError(
tr(
"Invalid property assignment: url or array of urls expected"));
621 return warnOrError(
tr(
"Invalid property assignment: string or array of strings expected"));
624 }
else if (
property->propType() == QMetaType::fromType<QJSValue>()) {
626 }
else if (
property->propType() == QMetaType::fromType<QQmlScriptString>()) {
655 for (
const auto& icDatum : compilationUnit->inlineComponentData) {
656 if (icDatum.qmlType.typeId() == to) {
666 fromMo = fromMo->parent();
673 QVector<QQmlError> errors;
678QVector<QQmlError> QQmlPropertyValidator::recordError(
const QQmlError &
error)
const
680 QVector<QQmlError> errors;
681 errors.append(
error);
692 bool isValueSource =
false;
693 bool isPropertyInterceptor =
false;
702 mo =
mo->superClass();
709 if (!isValueSource && !isPropertyInterceptor) {
716 const QMetaType propType =
property->propType();
717 const auto rhsType = [&]() {
718 return stringAt(compilationUnit->
objectAt(binding->
value.objectIndex)
726 }
else if (propType == QMetaType::fromType<QVariant>()
727 || propType == QMetaType::fromType<QJSValue>()) {
734 if (!canCoerce(listType,
source)) {
748 }
else if (propType == QMetaType::fromType<QQmlScriptString>()) {
752 .
arg(rhsType()).
arg(propertyName));
760 if (!propertyMetaObject) {
765 for (
const auto& icDatum: compilationUnit->inlineComponentData) {
766 if (icDatum.qmlType.typeId() ==
property->propType()) {
774 if (propertyMetaObject) {
777 bool isAssignable =
false;
779 while (
c && !isAssignable) {
780 isAssignable |=
c == propertyMetaObject;
785 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.")
The QQmlCustomParser class allows you to add new arbitrary types to QML.
@ AcceptsAttachedProperties
QVector< QQmlError > errors() const
virtual void verifyBindings(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &, const QList< const QV4::CompiledData::Binding * > &)=0
QV4::ExecutionEngine * v4engine() const
The QQmlError class encapsulates a QML error.
bool isValid() const
Returns true if this error is valid, otherwise false.
The QQmlImports class encapsulates one QML document's import statements.
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return, QTypeRevision *version_return, QQmlImportNamespace **ns_return, QList< QQmlError > *errors=nullptr, QQmlType::RegistrationType registrationType=QQmlType::AnyRegistrationType, bool *typeRecursionDetected=nullptr) const
QQmlPropertyCache::ConstPtr at(int index) const
QMetaType propType() const
QVector< QQmlError > validate()
QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports *imports, const QQmlRefPointer< QV4::CompiledData::CompilationUnit > &compilationUnit)
static bool isHandlerName(QStringView signalName)
static QQmlTypeLoader * get(Engine *engine)
int propertyValueSourceCast() const
int propertyValueInterceptorCast() const
static QVariant createValueType(const QJSValue &, QMetaType)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
Q_QML_EXPORT QPointF pointFFromString(const QString &, bool *ok=nullptr)
Q_QML_EXPORT unsigned rgbaFromString(const QString &, bool *ok=nullptr)
Q_QML_EXPORT QSizeF sizeFFromString(const QString &, bool *ok=nullptr)
Q_QML_EXPORT QRectF rectFFromString(const QString &, bool *ok=nullptr)
Combined button and popup list for selecting options.
QVector< const QQmlPropertyData * > BindingPropertyData
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLsizei GLsizei GLchar * source
QT_BEGIN_NAMESPACE QQmlError qQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
QVarLengthArray< const QV4::CompiledData::Binding *, 8 > GroupPropertyVector
static QT_BEGIN_NAMESPACE bool isPrimitiveType(QMetaType metaType)
#define HANDLE_PRIMITIVE(Type, id, T)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const
bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const
bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const
quint32_le propertyNameIndex
bool isNumberBinding() const
bool evaluatesToString() const
bool isAttachedProperty() const
union QV4::CompiledData::Binding::@540 value
bool hasFlag(Flag flag) const
bool isGroupProperty() const
@ InitializerForReadOnlyDeclaration
@ IsSignalHandlerExpression
double bindingValueAsNumber(const CompiledData::Binding *binding) const
const CompiledObject * objectAt(int index) const
QQmlPropertyCacheVector propertyCaches
QString bindingValueAsString(const CompiledData::Binding *binding) const
quint32_le inheritedTypeNameIndex
QQmlRefPointer< ExecutableCompilationUnit > executableCompilationUnit(QQmlRefPointer< QV4::CompiledData::CompilationUnit > &&unit)