8#include <private/qqmlcustomparser_p.h>
9#include <private/qqmlglobal_p.h>
10#include <private/qqmlirbuilder_p.h>
11#include <private/qqmlpropertycachecreator_p.h>
12#include <private/qqmlpropertyresolver_p.h>
13#include <private/qqmlstringconverters_p.h>
14#include <private/qqmlsignalnames_p.h>
16#include <QtCore/qdatetime.h>
22 switch (metaType.id()) {
23#define HANDLE_PRIMITIVE(Type, id, T)
25QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
26#undef HANDLE_PRIMITIVE
33QQmlPropertyValidator::QQmlPropertyValidator(
34 QQmlTypeLoader *typeLoader,
const QQmlImports *imports,
35 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
36 : m_typeLoader(typeLoader)
37 , compilationUnit(compilationUnit)
39 , qmlUnit(compilationUnit->unitData())
40 , propertyCaches(compilationUnit->propertyCaches)
41 , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
43 bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
46QList<QQmlError> QQmlPropertyValidator::validate()
48 return validateObject(0,
nullptr);
55 bool operator()(quint32 name,
const QV4::CompiledData::Binding *binding)
const
57 return name < binding->propertyNameIndex;
59 bool operator()(
const QV4::CompiledData::Binding *binding, quint32 name)
const
61 return binding->propertyNameIndex < name;
63 bool operator()(
const QV4::CompiledData::Binding *lhs,
const QV4::CompiledData::Binding *rhs)
const
65 return lhs->propertyNameIndex < rhs->propertyNameIndex;
69QList<QQmlError> QQmlPropertyValidator::validateObject(
70 int objectIndex,
const QV4::CompiledData::Binding *instantiatingBinding,
71 bool populatingValueTypeGroupedProperty,
72 QQmlPropertyResolver::RevisionCheck checkRevision)
const
76 if (objectIndex >= compilationUnit->objectCount()) {
77 return validateObject(
78 compilationUnit->resolvedIndex(objectIndex), instantiatingBinding,
79 populatingValueTypeGroupedProperty, checkRevision);
82 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
83 for (
auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
84 const auto errors = validateObject(it->objectIndex,
nullptr);
85 if (!errors.isEmpty())
89 if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
90 && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
91 Q_ASSERT(obj->nBindings == 1);
92 const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
93 Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
94 return validateObject(componentBinding->value.objectIndex, componentBinding);
97 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches.at(objectIndex);
99 return QList<QQmlError>();
101 QQmlCustomParser *customParser =
nullptr;
102 if (
auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
107 populatingValueTypeGroupedProperty =
false;
109 const auto type = typeRef->type();
111 customParser = type.customParser();
114 QList<
const QV4::CompiledData::Binding*> customBindings;
119 const QV4::CompiledData::Binding *binding = obj->bindingTable();
120 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
121 if (!binding->isGroupedProperty())
124 if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
127 if (populatingValueTypeGroupedProperty) {
128 return recordError(binding->location, tr(
"Property assignment expected"));
131 GroupedPropertyVector::const_iterator pos = std::lower_bound(groupedProperties.constBegin(), groupedProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
132 groupedProperties.insert(pos, binding);
135 QQmlPropertyResolver propertyResolver(propertyCache);
137 QString defaultPropertyName;
138 const QQmlPropertyData *defaultProperty =
nullptr;
139 if (obj->indexOfDefaultPropertyOrAlias != -1) {
140 const QQmlPropertyCache *cache = propertyCache->parent().data();
141 defaultPropertyName = cache->defaultPropertyName();
142 defaultProperty = cache->defaultProperty();
144 defaultPropertyName = propertyCache->defaultPropertyName();
145 defaultProperty = propertyCache->defaultProperty();
148 QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
150 binding = obj->bindingTable();
151 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
152 QString name = stringAt(binding->propertyNameIndex);
153 const QV4::CompiledData::Binding::Type bindingType = binding->type();
154 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
157 if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
158 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
159 customBindings << binding;
162 }
else if (QQmlSignalNames::isHandlerName(name)
163 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
164 customBindings << binding;
169 bool bindingToDefaultProperty =
false;
170 bool isGroupedProperty = instantiatingBinding
171 && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupedProperty;
173 bool notInRevision =
false;
174 const QQmlPropertyData *pd =
nullptr;
175 if (!name.isEmpty()) {
176 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
177 || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
178 pd = propertyResolver.signal(
179 *QQmlSignalNames::anyHandlerNameToSignalName(name), ¬InRevision,
181 }
else if (bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) {
182 pd = propertyResolver.property(
183 *QQmlSignalNames::changedHandlerNameToPropertyName(name), ¬InRevision,
186 pd = propertyResolver.property(name, ¬InRevision, checkRevision);
190 QString typeName = stringAt(obj->inheritedTypeNameIndex);
191 if (
auto *objectType = resolvedType(obj->inheritedTypeNameIndex)) {
192 const auto type = objectType->type();
193 if (type.isValid()) {
194 const auto version = objectType->version();
195 return recordError(binding->location,
196 tr(
"\"%1.%2\" is not available in %3 %4.%5.")
197 .arg(typeName, name, type.module(),
198 QString::number(version.majorVersion()),
199 QString::number(version.minorVersion())));
202 return recordError(binding->location,
203 tr(
"\"%1.%2\" is not available due to component versioning.")
204 .arg(typeName, name));
208 if (isGroupedProperty)
209 return recordError(binding->location, tr(
"Cannot assign a value directly to a grouped property"));
211 pd = defaultProperty;
212 name = defaultPropertyName;
213 bindingToDefaultProperty =
true;
217 collectedBindingPropertyData[i] = pd;
219 if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
221 QQmlImportNamespace *typeNamespace =
nullptr;
222 imports->resolveType(
223 m_typeLoader, stringAt(binding->propertyNameIndex),
224 &type,
nullptr, &typeNamespace);
226 return recordError(binding->location, tr(
"Invalid use of namespace"));
227 return recordError(binding->location, tr(
"Invalid attached object assignment"));
230 if (bindingType >= QV4::CompiledData::Binding::Type_Object
231 && (pd || binding->isAttachedProperty() || binding->isGroupedProperty())) {
232 const bool populatingValueTypeGroupedProperty
234 && QQmlMetaType::metaObjectForValueType(pd->propType())
235 && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
238 const QList<QQmlError> subObjectValidatorErrors = validateObject(
239 binding->value.objectIndex, binding, populatingValueTypeGroupedProperty,
240 QQmlPropertyResolver::IgnoreRevision);
242 if (!subObjectValidatorErrors.isEmpty())
243 return subObjectValidatorErrors;
247 if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
248 | QV4::CompiledData::Binding::IsSignalHandlerObject
249 | QV4::CompiledData::Binding::IsPropertyObserver)) {
253 if ((pd && bindingType == QV4::CompiledData::Binding::Type_AttachedProperty)
254 || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupedProperty)) {
255 if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
256 || instantiatingBinding->isGroupedProperty())) {
258 binding->location, tr(
"%1 properties cannot be used here")
259 .arg(bindingType == QV4::CompiledData::Binding::Type_AttachedProperty
260 ? QStringLiteral(
"Attached")
261 : QStringLiteral(
"Group")));
264 }
else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
269 GroupedPropertyVector::const_iterator assignedGroupedProperty = std::lower_bound(groupedProperties.constBegin(), groupedProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
270 const bool assigningToGroupedProperty = assignedGroupedProperty != groupedProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupedProperty)->propertyNameIndex);
272 if (!pd->isWritable()
274 && !binding->isGroupedProperty()
275 && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
278 if (assigningToGroupedProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
279 return recordError(binding->valueLocation, tr(
"Cannot assign a value directly to a grouped property"));
280 return recordError(binding->valueLocation, tr(
"Invalid property assignment: \"%1\" is a read-only property").arg(name));
283 if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
285 if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
286 error = tr(
"Cannot assign multiple values to a script property");
288 error = tr(
"Cannot assign multiple values to a singular property");
289 return recordError(binding->valueLocation, error);
292 if (!bindingToDefaultProperty
293 && !binding->isGroupedProperty()
294 && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
295 && assigningToGroupedProperty) {
296 QV4::CompiledData::Location loc = binding->valueLocation;
297 if (loc < (*assignedGroupedProperty)->valueLocation)
298 loc = (*assignedGroupedProperty)->valueLocation;
300 if (pd && QQmlMetaType::isValueType(pd->propType()))
301 return recordError(loc, tr(
"Property has already been assigned a value"));
302 return recordError(loc, tr(
"Cannot assign a value directly to a grouped property"));
305 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
306 QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
307 if (bindingError.isValid())
308 return recordError(bindingError);
309 }
else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
310 QQmlError bindingError = validateObjectBinding(pd, name, binding);
311 if (bindingError.isValid())
312 return recordError(bindingError);
313 }
else if (binding->isGroupedProperty()) {
314 if (QQmlMetaType::isValueType(pd->propType())) {
315 if (QQmlMetaType::metaObjectForValueType(pd->propType())) {
316 if (!pd->isWritable()) {
317 return recordError(binding->location, tr(
"Invalid property assignment: \"%1\" is a read-only property").arg(name));
320 return recordError(binding->location, tr(
"Invalid grouped property access"));
323 const QMetaType type = pd->propType();
324 if (isPrimitiveType(type)) {
327 tr(
"Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
328 .arg(name, QString::fromUtf8(type.name()))
332 if (!QQmlMetaType::propertyCacheForType(type)) {
333 auto mo = type.metaObject();
335 return recordError(binding->location,
336 tr(
"Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
337 .arg(name, QString::fromUtf8(type.name()))
340 if (QMetaObjectPrivate::get(mo)->flags & DynamicMetaObject) {
341 return recordError(binding->location,
342 tr(
"Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
343 .arg(name, QString::fromUtf8(type.name()))
352 customBindings << binding;
355 if (bindingToDefaultProperty) {
356 return recordError(binding->location, tr(
"Cannot assign to non-existent default property"));
358 return recordError(binding->location, tr(
"Cannot assign to non-existent property \"%1\"").arg(name));
363 if (obj->idNameIndex) {
364 if (populatingValueTypeGroupedProperty)
365 return recordError(obj->locationOfIdProperty, tr(
"Invalid use of id property with a value type"));
367 bool notInRevision =
false;
368 collectedBindingPropertyData
369 << propertyResolver.property(QStringLiteral(
"id"), ¬InRevision, checkRevision);
372 if (customParser && !customBindings.isEmpty()) {
373 customParser->clearErrors();
374 customParser->validator =
this;
375 customParser->imports = imports;
376 customParser->verifyBindings(compilationUnit, customBindings);
377 customParser->validator =
nullptr;
378 customParser->imports = (QQmlImports*)
nullptr;
379 QList<QQmlError> parserErrors = customParser->errors();
380 if (!parserErrors.isEmpty())
384 (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
386 QList<QQmlError> noError;
390QQmlError QQmlPropertyValidator::validateLiteralBinding(
391 const QQmlPropertyCache::ConstPtr &propertyCache,
const QQmlPropertyData *property,
392 const QV4::CompiledData::Binding *binding)
const
394 if (property->isQList()) {
395 return qQmlCompileError(binding->valueLocation, tr(
"Cannot assign primitives to lists"));
400 if (property->isEnum()) {
401 if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
406 if (property->isAlias() && binding->isNumberBinding())
409 QString value = compilationUnit->bindingValueAsString(binding);
410 QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
412 if (p.isFlagType()) {
413 p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
415 p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
418 return qQmlCompileError(binding->valueLocation, tr(
"Invalid property assignment: unknown enumeration"));
423 auto warnOrError = [&](
const QString &error) {
424 return qQmlCompileError(binding->valueLocation, error);
427 const QV4::CompiledData::Binding::Type bindingType = binding->type();
428 const auto isStringBinding = [&]() ->
bool {
430 Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
431 return bindingType == QV4::CompiledData::Binding::Type_String;
434 switch (property->propType().id()) {
435 case QMetaType::QVariant:
437 case QMetaType::QString: {
438 if (!binding->evaluatesToString()) {
439 return warnOrError(tr(
"Invalid property assignment: string expected"));
443 case QMetaType::QStringList: {
444 if (!binding->evaluatesToString()) {
445 return warnOrError(tr(
"Invalid property assignment: string or string list expected"));
449 case QMetaType::QByteArray: {
450 if (bindingType != QV4::CompiledData::Binding::Type_String)
451 return warnOrError(tr(
"Invalid property assignment: byte array expected"));
454 case QMetaType::QUrl: {
455 if (bindingType != QV4::CompiledData::Binding::Type_String)
456 return warnOrError(tr(
"Invalid property assignment: url expected"));
459 case QMetaType::UInt: {
460 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
461 double d = compilationUnit->bindingValueAsNumber(binding);
462 if (
double(uint(d)) == d)
465 return warnOrError(tr(
"Invalid property assignment: unsigned int expected"));
468 case QMetaType::Int: {
469 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
470 double d = compilationUnit->bindingValueAsNumber(binding);
471 if (
double(
int(d)) == d)
474 return warnOrError(tr(
"Invalid property assignment: int expected"));
477 case QMetaType::LongLong:
478 case QMetaType::ULongLong:
479 case QMetaType::Long:
480 case QMetaType::ULong:
481 case QMetaType::Float:
482 case QMetaType::Double: {
483 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
484 return warnOrError(tr(
"Invalid property assignment: number expected"));
488 case QMetaType::QColor: {
490 if (isStringBinding())
491 QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
493 return warnOrError(tr(
"Invalid property assignment: color expected"));
497#if QT_CONFIG(datestring)
498 case QMetaType::QDate: {
500 if (isStringBinding())
501 QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
503 return warnOrError(tr(
"Invalid property assignment: date expected"));
507 case QMetaType::QTime: {
509 if (isStringBinding())
510 QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
512 return warnOrError(tr(
"Invalid property assignment: time expected"));
516 case QMetaType::QDateTime: {
518 if (isStringBinding())
519 QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
521 return warnOrError(tr(
"Invalid property assignment: datetime expected"));
526 case QMetaType::QPoint: {
528 if (isStringBinding())
529 QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
531 return warnOrError(tr(
"Invalid property assignment: point expected"));
535 case QMetaType::QPointF: {
537 if (isStringBinding())
538 QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
540 return warnOrError(tr(
"Invalid property assignment: point expected"));
544 case QMetaType::QSize: {
546 if (isStringBinding())
547 QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
549 return warnOrError(tr(
"Invalid property assignment: size expected"));
553 case QMetaType::QSizeF: {
555 if (isStringBinding())
556 QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
558 return warnOrError(tr(
"Invalid property assignment: size expected"));
562 case QMetaType::QRect: {
564 if (isStringBinding())
565 QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
567 return warnOrError(tr(
"Invalid property assignment: rect expected"));
571 case QMetaType::QRectF: {
573 if (isStringBinding())
574 QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
576 return warnOrError(tr(
"Invalid property assignment: point expected"));
580 case QMetaType::Bool: {
581 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
582 return warnOrError(tr(
"Invalid property assignment: boolean expected"));
586 case QMetaType::QVector2D:
587 case QMetaType::QVector3D:
588 case QMetaType::QVector4D:
589 case QMetaType::QQuaternion: {
590 auto typeName = [&]() {
591 switch (property->propType().id()) {
592 case QMetaType::QVector2D:
return QStringLiteral(
"2D vector");
593 case QMetaType::QVector3D:
return QStringLiteral(
"3D vector");
594 case QMetaType::QVector4D:
return QStringLiteral(
"4D vector");
595 case QMetaType::QQuaternion:
return QStringLiteral(
"quaternion");
596 default:
return QString();
599 const QVariant result = QQmlValueTypeProvider::createValueType(
600 compilationUnit->bindingValueAsString(binding),
601 property->propType());
602 if (!result.isValid()) {
603 return warnOrError(tr(
"Invalid property assignment: %1 expected")
608 case QMetaType::QRegularExpression:
609 return warnOrError(tr(
"Invalid property assignment: regular expression expected; use /pattern/ syntax"));
612 if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
613 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
614 return warnOrError(tr(
"Invalid property assignment: number or array of numbers expected"));
617 }
else if (property->propType() == QMetaType::fromType<QList<
int> >()) {
618 bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
620 double n = compilationUnit->bindingValueAsNumber(binding);
621 if (
double(
int(n)) != n)
625 return warnOrError(tr(
"Invalid property assignment: int or array of ints expected"));
627 }
else if (property->propType() == QMetaType::fromType<QList<
bool> >()) {
628 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
629 return warnOrError(tr(
"Invalid property assignment: bool or array of bools expected"));
632 }
else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
633 if (bindingType != QV4::CompiledData::Binding::Type_String) {
634 return warnOrError(tr(
"Invalid property assignment: url or array of urls expected"));
637 }
else if (property->propType() == QMetaType::fromType<QList<QString> >()) {
638 if (!binding->evaluatesToString()) {
639 return warnOrError(tr(
"Invalid property assignment: string or array of strings expected"));
642 }
else if (property->propType() == QMetaType::fromType<QJSValue>()) {
644 }
else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
646 }
else if (property->isQObject()
647 && bindingType == QV4::CompiledData::Binding::Type_Null) {
649 }
else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
653 return warnOrError(tr(
"Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
661
662
663
664bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo)
const
666 if (QQmlMetaType::canConvert(fromMo, to))
673 for (
const auto &icDatum : std::as_const(compilationUnit->inlineComponentData)) {
674 if (icDatum.qmlType.typeId() != to)
677 const auto toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
678 for (QQmlPropertyCache::ConstPtr parent = fromMo; parent; parent = parent->parent()) {
688QList<QQmlError> QQmlPropertyValidator::recordError(
const QV4::CompiledData::Location &location,
const QString &description)
const
690 QList<QQmlError> errors;
691 errors.append(qQmlCompileError(location, description));
695QList<QQmlError> QQmlPropertyValidator::recordError(
const QQmlError &error)
const
697 QList<QQmlError> errors;
698 errors.append(error);
702QQmlError QQmlPropertyValidator::validateObjectBinding(
const QQmlPropertyData *property,
const QString &propertyName,
const QV4::CompiledData::Binding *binding)
const
706 if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
707 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
709 bool isValueSource =
false;
710 bool isPropertyInterceptor =
false;
712 const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
713 if (
auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
714 QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
715 const QMetaObject *mo = cache ? cache->firstCppMetaObject() :
nullptr;
717 while (mo && !qmlType.isValid()) {
718 qmlType = QQmlMetaType::qmlType(mo);
719 mo = mo->superClass();
722 isValueSource = qmlType.propertyValueSourceCast() != -1;
723 isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
726 if (!isValueSource && !isPropertyInterceptor) {
727 return qQmlCompileError(
728 binding->valueLocation,
729 tr(
"\"%1\" cannot operate on \"%2\"")
730 .arg(stringAt(targetObject->inheritedTypeNameIndex), propertyName));
736 const QMetaType propType = property->propType();
737 const auto rhsType = [&]() {
738 return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
739 ->inheritedTypeNameIndex);
742 if (QQmlMetaType::isInterface(propType)) {
746 }
else if (propType == QMetaType::fromType<QVariant>()
747 || propType == QMetaType::fromType<QJSValue>()) {
750 }
else if (property->isQList()) {
751 const QMetaType listType = QQmlMetaType::listValueType(property->propType());
752 if (!QQmlMetaType::isInterface(listType)) {
753 QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
755 if (
const int wrapper = compilationUnit->implicitComponentForObject(
756 binding->value.objectIndex); wrapper != -1) {
758 source = propertyCaches.at(wrapper);
761 if (!canCoerce(listType, source)) {
762 const QString expectedTypeName = QString::fromUtf8(listType.name()).remove(QLatin1Char(
'*'));
763 return qQmlCompileError(binding->valueLocation,
764 tr(
"Cannot assign object of type \"%1\" to list property \"%2\"; expected \"%3\"")
765 .arg(source->className(), propertyName, expectedTypeName));
769 }
else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
770 && property->isFunction()) {
772 }
else if (isPrimitiveType(propType)) {
773 auto typeName = QString::fromUtf8(QMetaType(propType).name());
774 return qQmlCompileError(
776 tr(
"Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
777 .arg(rhsType(), propertyName, typeName));
778 }
else if (propType == QMetaType::fromType<QQmlScriptString>()) {
779 return qQmlCompileError(binding->valueLocation, tr(
"Invalid property assignment: script expected"));
780 }
else if (!QQmlMetaType::isValueType(property->propType())) {
781 QQmlPropertyCache::ConstPtr propertyMetaObject;
787 for (
const auto &icDatum: std::as_const(compilationUnit->inlineComponentData)) {
788 if (icDatum.qmlType.typeId() == property->propType()) {
789 propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
794 if (!propertyMetaObject) {
799 propertyMetaObject = QQmlMetaType::rawPropertyCacheForType(propType);
802 if (propertyMetaObject) {
805 bool isAssignable =
false;
806 QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
808 if (
const int wrapper = compilationUnit->implicitComponentForObject(
809 binding->value.objectIndex); wrapper != -1) {
811 source = propertyCaches.at(wrapper);
814 const auto inheritsFrom = [&](
const QQmlPropertyCache::ConstPtr &target) {
815 for (QQmlPropertyCache::ConstPtr c = source; c; c = c->parent()) {
822 isAssignable = inheritsFrom(propertyMetaObject);
824 if (!isAssignable && propertyMetaObject->isComposite()) {
827 const auto candidates = QQmlMetaType::rawCompositePropertyCachesForType(propType);
828 for (
const auto &candidate : candidates) {
829 if (inheritsFrom(candidate)) {
837 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.")
838 .arg(rhsType()).arg(QLatin1String(property->propType().name())));
841 return qQmlCompileError(binding->valueLocation, tr(
"Cannot assign to property of unknown type \"%1\".")
842 .arg(QLatin1String(property->propType().name())));
Combined button and popup list for selecting options.
QVarLengthArray< const QV4::CompiledData::Binding *, 8 > GroupedPropertyVector
static QT_BEGIN_NAMESPACE bool isPrimitiveType(QMetaType metaType)
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