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(name, ¬InRevision, checkRevision);
180 pd = propertyResolver.property(name, ¬InRevision, checkRevision);
184 QString typeName = stringAt(obj->inheritedTypeNameIndex);
185 if (
auto *objectType = resolvedType(obj->inheritedTypeNameIndex)) {
186 const auto type = objectType->type();
187 if (type.isValid()) {
188 const auto version = objectType->version();
189 return recordError(binding->location,
190 tr(
"\"%1.%2\" is not available in %3 %4.%5.")
191 .arg(typeName, name, type.module(),
192 QString::number(version.majorVersion()),
193 QString::number(version.minorVersion())));
196 return recordError(binding->location,
197 tr(
"\"%1.%2\" is not available due to component versioning.")
198 .arg(typeName, name));
202 if (isGroupedProperty)
203 return recordError(binding->location, tr(
"Cannot assign a value directly to a grouped property"));
205 pd = defaultProperty;
206 name = defaultPropertyName;
207 bindingToDefaultProperty =
true;
211 collectedBindingPropertyData[i] = pd;
213 if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
215 QQmlImportNamespace *typeNamespace =
nullptr;
216 imports->resolveType(
217 m_typeLoader, stringAt(binding->propertyNameIndex),
218 &type,
nullptr, &typeNamespace);
220 return recordError(binding->location, tr(
"Invalid use of namespace"));
221 return recordError(binding->location, tr(
"Invalid attached object assignment"));
224 if (bindingType >= QV4::CompiledData::Binding::Type_Object
225 && (pd || binding->isAttachedProperty() || binding->isGroupedProperty())) {
226 const bool populatingValueTypeGroupedProperty
228 && QQmlMetaType::metaObjectForValueType(pd->propType())
229 && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
232 const QList<QQmlError> subObjectValidatorErrors = validateObject(
233 binding->value.objectIndex, binding, populatingValueTypeGroupedProperty,
234 QQmlPropertyResolver::IgnoreRevision);
236 if (!subObjectValidatorErrors.isEmpty())
237 return subObjectValidatorErrors;
241 if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
242 | QV4::CompiledData::Binding::IsSignalHandlerObject
243 | QV4::CompiledData::Binding::IsPropertyObserver)) {
247 if ((pd && bindingType == QV4::CompiledData::Binding::Type_AttachedProperty)
248 || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupedProperty)) {
249 if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
250 || instantiatingBinding->isGroupedProperty())) {
252 binding->location, tr(
"%1 properties cannot be used here")
253 .arg(bindingType == QV4::CompiledData::Binding::Type_AttachedProperty
254 ? QStringLiteral(
"Attached")
255 : QStringLiteral(
"Group")));
258 }
else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
263 GroupedPropertyVector::const_iterator assignedGroupedProperty = std::lower_bound(groupedProperties.constBegin(), groupedProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
264 const bool assigningToGroupedProperty = assignedGroupedProperty != groupedProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupedProperty)->propertyNameIndex);
266 if (!pd->isWritable()
268 && !binding->isGroupedProperty()
269 && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
272 if (assigningToGroupedProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
273 return recordError(binding->valueLocation, tr(
"Cannot assign a value directly to a grouped property"));
274 return recordError(binding->valueLocation, tr(
"Invalid property assignment: \"%1\" is a read-only property").arg(name));
277 if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
279 if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
280 error = tr(
"Cannot assign multiple values to a script property");
282 error = tr(
"Cannot assign multiple values to a singular property");
283 return recordError(binding->valueLocation, error);
286 if (!bindingToDefaultProperty
287 && !binding->isGroupedProperty()
288 && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
289 && assigningToGroupedProperty) {
290 QV4::CompiledData::Location loc = binding->valueLocation;
291 if (loc < (*assignedGroupedProperty)->valueLocation)
292 loc = (*assignedGroupedProperty)->valueLocation;
294 if (pd && QQmlMetaType::isValueType(pd->propType()))
295 return recordError(loc, tr(
"Property has already been assigned a value"));
296 return recordError(loc, tr(
"Cannot assign a value directly to a grouped property"));
299 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
300 QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
301 if (bindingError.isValid())
302 return recordError(bindingError);
303 }
else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
304 QQmlError bindingError = validateObjectBinding(pd, name, binding);
305 if (bindingError.isValid())
306 return recordError(bindingError);
307 }
else if (binding->isGroupedProperty()) {
308 if (QQmlMetaType::isValueType(pd->propType())) {
309 if (QQmlMetaType::metaObjectForValueType(pd->propType())) {
310 if (!pd->isWritable()) {
311 return recordError(binding->location, tr(
"Invalid property assignment: \"%1\" is a read-only property").arg(name));
314 return recordError(binding->location, tr(
"Invalid grouped property access"));
317 const QMetaType type = pd->propType();
318 if (isPrimitiveType(type)) {
321 tr(
"Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
322 .arg(name, QString::fromUtf8(type.name()))
326 if (!QQmlMetaType::propertyCacheForType(type)) {
327 auto mo = type.metaObject();
329 return recordError(binding->location,
330 tr(
"Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
331 .arg(name, QString::fromUtf8(type.name()))
334 if (QMetaObjectPrivate::get(mo)->flags & DynamicMetaObject) {
335 return recordError(binding->location,
336 tr(
"Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
337 .arg(name, QString::fromUtf8(type.name()))
346 customBindings << binding;
349 if (bindingToDefaultProperty) {
350 return recordError(binding->location, tr(
"Cannot assign to non-existent default property"));
352 return recordError(binding->location, tr(
"Cannot assign to non-existent property \"%1\"").arg(name));
357 if (obj->idNameIndex) {
358 if (populatingValueTypeGroupedProperty)
359 return recordError(obj->locationOfIdProperty, tr(
"Invalid use of id property with a value type"));
361 bool notInRevision =
false;
362 collectedBindingPropertyData
363 << propertyResolver.property(QStringLiteral(
"id"), ¬InRevision, checkRevision);
366 if (customParser && !customBindings.isEmpty()) {
367 customParser->clearErrors();
368 customParser->validator =
this;
369 customParser->imports = imports;
370 customParser->verifyBindings(compilationUnit, customBindings);
371 customParser->validator =
nullptr;
372 customParser->imports = (QQmlImports*)
nullptr;
373 QList<QQmlError> parserErrors = customParser->errors();
374 if (!parserErrors.isEmpty())
378 (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
380 QList<QQmlError> noError;
384QQmlError QQmlPropertyValidator::validateLiteralBinding(
385 const QQmlPropertyCache::ConstPtr &propertyCache,
const QQmlPropertyData *property,
386 const QV4::CompiledData::Binding *binding)
const
388 if (property->isQList()) {
389 return qQmlCompileError(binding->valueLocation, tr(
"Cannot assign primitives to lists"));
394 if (property->isEnum()) {
395 if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
400 if (property->isAlias() && binding->isNumberBinding())
403 QString value = compilationUnit->bindingValueAsString(binding);
404 QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
406 if (p.isFlagType()) {
407 p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
409 p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
412 return qQmlCompileError(binding->valueLocation, tr(
"Invalid property assignment: unknown enumeration"));
417 auto warnOrError = [&](
const QString &error) {
418 return qQmlCompileError(binding->valueLocation, error);
421 const QV4::CompiledData::Binding::Type bindingType = binding->type();
422 const auto isStringBinding = [&]() ->
bool {
424 Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
425 return bindingType == QV4::CompiledData::Binding::Type_String;
428 switch (property->propType().id()) {
429 case QMetaType::QVariant:
431 case QMetaType::QString: {
432 if (!binding->evaluatesToString()) {
433 return warnOrError(tr(
"Invalid property assignment: string expected"));
437 case QMetaType::QStringList: {
438 if (!binding->evaluatesToString()) {
439 return warnOrError(tr(
"Invalid property assignment: string or string list expected"));
443 case QMetaType::QByteArray: {
444 if (bindingType != QV4::CompiledData::Binding::Type_String)
445 return warnOrError(tr(
"Invalid property assignment: byte array expected"));
448 case QMetaType::QUrl: {
449 if (bindingType != QV4::CompiledData::Binding::Type_String)
450 return warnOrError(tr(
"Invalid property assignment: url expected"));
453 case QMetaType::UInt: {
454 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
455 double d = compilationUnit->bindingValueAsNumber(binding);
456 if (
double(uint(d)) == d)
459 return warnOrError(tr(
"Invalid property assignment: unsigned int expected"));
462 case QMetaType::Int: {
463 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
464 double d = compilationUnit->bindingValueAsNumber(binding);
465 if (
double(
int(d)) == d)
468 return warnOrError(tr(
"Invalid property assignment: int expected"));
471 case QMetaType::LongLong:
472 case QMetaType::ULongLong:
473 case QMetaType::Long:
474 case QMetaType::ULong:
475 case QMetaType::Float:
476 case QMetaType::Double: {
477 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
478 return warnOrError(tr(
"Invalid property assignment: number expected"));
482 case QMetaType::QColor: {
484 if (isStringBinding())
485 QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
487 return warnOrError(tr(
"Invalid property assignment: color expected"));
491#if QT_CONFIG(datestring)
492 case QMetaType::QDate: {
494 if (isStringBinding())
495 QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
497 return warnOrError(tr(
"Invalid property assignment: date expected"));
501 case QMetaType::QTime: {
503 if (isStringBinding())
504 QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
506 return warnOrError(tr(
"Invalid property assignment: time expected"));
510 case QMetaType::QDateTime: {
512 if (isStringBinding())
513 QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
515 return warnOrError(tr(
"Invalid property assignment: datetime expected"));
520 case QMetaType::QPoint: {
522 if (isStringBinding())
523 QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
525 return warnOrError(tr(
"Invalid property assignment: point expected"));
529 case QMetaType::QPointF: {
531 if (isStringBinding())
532 QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
534 return warnOrError(tr(
"Invalid property assignment: point expected"));
538 case QMetaType::QSize: {
540 if (isStringBinding())
541 QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
543 return warnOrError(tr(
"Invalid property assignment: size expected"));
547 case QMetaType::QSizeF: {
549 if (isStringBinding())
550 QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
552 return warnOrError(tr(
"Invalid property assignment: size expected"));
556 case QMetaType::QRect: {
558 if (isStringBinding())
559 QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
561 return warnOrError(tr(
"Invalid property assignment: rect expected"));
565 case QMetaType::QRectF: {
567 if (isStringBinding())
568 QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
570 return warnOrError(tr(
"Invalid property assignment: point expected"));
574 case QMetaType::Bool: {
575 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
576 return warnOrError(tr(
"Invalid property assignment: boolean expected"));
580 case QMetaType::QVector2D:
581 case QMetaType::QVector3D:
582 case QMetaType::QVector4D:
583 case QMetaType::QQuaternion: {
584 auto typeName = [&]() {
585 switch (property->propType().id()) {
586 case QMetaType::QVector2D:
return QStringLiteral(
"2D vector");
587 case QMetaType::QVector3D:
return QStringLiteral(
"3D vector");
588 case QMetaType::QVector4D:
return QStringLiteral(
"4D vector");
589 case QMetaType::QQuaternion:
return QStringLiteral(
"quaternion");
590 default:
return QString();
593 const QVariant result = QQmlValueTypeProvider::createValueType(
594 compilationUnit->bindingValueAsString(binding),
595 property->propType());
596 if (!result.isValid()) {
597 return warnOrError(tr(
"Invalid property assignment: %1 expected")
602 case QMetaType::QRegularExpression:
603 return warnOrError(tr(
"Invalid property assignment: regular expression expected; use /pattern/ syntax"));
606 if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
607 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
608 return warnOrError(tr(
"Invalid property assignment: number or array of numbers expected"));
611 }
else if (property->propType() == QMetaType::fromType<QList<
int> >()) {
612 bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
614 double n = compilationUnit->bindingValueAsNumber(binding);
615 if (
double(
int(n)) != n)
619 return warnOrError(tr(
"Invalid property assignment: int or array of ints expected"));
621 }
else if (property->propType() == QMetaType::fromType<QList<
bool> >()) {
622 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
623 return warnOrError(tr(
"Invalid property assignment: bool or array of bools expected"));
626 }
else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
627 if (bindingType != QV4::CompiledData::Binding::Type_String) {
628 return warnOrError(tr(
"Invalid property assignment: url or array of urls expected"));
631 }
else if (property->propType() == QMetaType::fromType<QList<QString> >()) {
632 if (!binding->evaluatesToString()) {
633 return warnOrError(tr(
"Invalid property assignment: string or array of strings expected"));
636 }
else if (property->propType() == QMetaType::fromType<QJSValue>()) {
638 }
else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
640 }
else if (property->isQObject()
641 && bindingType == QV4::CompiledData::Binding::Type_Null) {
643 }
else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
647 return warnOrError(tr(
"Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
655
656
657
658bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo)
const
660 if (QQmlMetaType::canConvert(fromMo, to))
667 for (
const auto &icDatum : std::as_const(compilationUnit->inlineComponentData)) {
668 if (icDatum.qmlType.typeId() != to)
671 const auto toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
672 for (QQmlPropertyCache::ConstPtr parent = fromMo; parent; parent = parent->parent()) {
682QList<QQmlError> QQmlPropertyValidator::recordError(
const QV4::CompiledData::Location &location,
const QString &description)
const
684 QList<QQmlError> errors;
685 errors.append(qQmlCompileError(location, description));
689QList<QQmlError> QQmlPropertyValidator::recordError(
const QQmlError &error)
const
691 QList<QQmlError> errors;
692 errors.append(error);
696QQmlError QQmlPropertyValidator::validateObjectBinding(
const QQmlPropertyData *property,
const QString &propertyName,
const QV4::CompiledData::Binding *binding)
const
700 if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
701 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
703 bool isValueSource =
false;
704 bool isPropertyInterceptor =
false;
706 const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
707 if (
auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
708 QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
709 const QMetaObject *mo = cache ? cache->firstCppMetaObject() :
nullptr;
711 while (mo && !qmlType.isValid()) {
712 qmlType = QQmlMetaType::qmlType(mo);
713 mo = mo->superClass();
716 isValueSource = qmlType.propertyValueSourceCast() != -1;
717 isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
720 if (!isValueSource && !isPropertyInterceptor) {
721 return qQmlCompileError(
722 binding->valueLocation,
723 tr(
"\"%1\" cannot operate on \"%2\"")
724 .arg(stringAt(targetObject->inheritedTypeNameIndex), propertyName));
730 const QMetaType propType = property->propType();
731 const auto rhsType = [&]() {
732 return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
733 ->inheritedTypeNameIndex);
736 if (QQmlMetaType::isInterface(propType)) {
740 }
else if (propType == QMetaType::fromType<QVariant>()
741 || propType == QMetaType::fromType<QJSValue>()) {
744 }
else if (property->isQList()) {
745 const QMetaType listType = QQmlMetaType::listValueType(property->propType());
746 if (!QQmlMetaType::isInterface(listType)) {
747 QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
749 if (
const int wrapper = compilationUnit->implicitComponentForObject(
750 binding->value.objectIndex); wrapper != -1) {
752 source = propertyCaches.at(wrapper);
755 if (!canCoerce(listType, source)) {
756 const QString expectedTypeName = QString::fromUtf8(listType.name()).remove(QLatin1Char(
'*'));
757 return qQmlCompileError(binding->valueLocation,
758 tr(
"Cannot assign object of type \"%1\" to list property \"%2\"; expected \"%3\"")
759 .arg(source->className(), propertyName, expectedTypeName));
763 }
else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
764 && property->isFunction()) {
766 }
else if (isPrimitiveType(propType)) {
767 auto typeName = QString::fromUtf8(QMetaType(propType).name());
768 return qQmlCompileError(
770 tr(
"Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
771 .arg(rhsType(), propertyName, typeName));
772 }
else if (propType == QMetaType::fromType<QQmlScriptString>()) {
773 return qQmlCompileError(binding->valueLocation, tr(
"Invalid property assignment: script expected"));
774 }
else if (!QQmlMetaType::isValueType(property->propType())) {
775 QQmlPropertyCache::ConstPtr propertyMetaObject;
781 for (
const auto &icDatum: std::as_const(compilationUnit->inlineComponentData)) {
782 if (icDatum.qmlType.typeId() == property->propType()) {
783 propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
788 if (!propertyMetaObject) {
793 propertyMetaObject = QQmlMetaType::rawPropertyCacheForType(propType);
796 if (propertyMetaObject) {
799 bool isAssignable =
false;
800 QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
802 if (
const int wrapper = compilationUnit->implicitComponentForObject(
803 binding->value.objectIndex); wrapper != -1) {
805 source = propertyCaches.at(wrapper);
808 const auto inheritsFrom = [&](
const QQmlPropertyCache::ConstPtr &target) {
809 for (QQmlPropertyCache::ConstPtr c = source; c; c = c->parent()) {
816 isAssignable = inheritsFrom(propertyMetaObject);
818 if (!isAssignable && propertyMetaObject->isComposite()) {
821 const auto candidates = QQmlMetaType::rawCompositePropertyCachesForType(propType);
822 for (
const auto &candidate : candidates) {
823 if (inheritsFrom(candidate)) {
831 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.")
832 .arg(rhsType()).arg(QLatin1String(property->propType().name())));
835 return qQmlCompileError(binding->valueLocation, tr(
"Cannot assign to property of unknown type \"%1\".")
836 .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