Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlpropertyvalidator.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
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
13#include <QtCore/qdatetime.h>
14
16
17static bool isPrimitiveType(QMetaType metaType)
18{
19 switch (metaType.id()) {
20#define HANDLE_PRIMITIVE(Type, id, T) \
21 case QMetaType::Type:
23#undef HANDLE_PRIMITIVE
24 return true;
25 default:
26 return false;
27 }
28}
29
31 QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
33 : enginePrivate(enginePrivate)
34 , compilationUnit(compilationUnit)
35 , imports(imports)
36 , qmlUnit(compilationUnit->unitData())
37 , propertyCaches(compilationUnit->propertyCaches)
38 , bindingPropertyDataPerObject(&compilationUnit->bindingPropertyDataPerObject)
39{
40 bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
41}
42
44{
45 return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
46}
47
49
51{
53 {
54 return name < binding->propertyNameIndex;
55 }
57 {
58 return binding->propertyNameIndex < name;
59 }
61 {
62 return lhs->propertyNameIndex < rhs->propertyNameIndex;
63 }
64};
65
66QVector<QQmlError> QQmlPropertyValidator::validateObject(
67 int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
68{
69 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
70 for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
71 const auto errors = validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr);
72 if (!errors.isEmpty())
73 return errors;
74 }
75
78 Q_ASSERT(obj->nBindings == 1);
79 const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
81 return validateObject(componentBinding->value.objectIndex, componentBinding);
82 }
83
84 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches.at(objectIndex);
85 if (!propertyCache)
86 return QVector<QQmlError>();
87
88 QQmlCustomParser *customParser = nullptr;
89 if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
90 const auto type = typeRef->type();
91 if (type.isValid())
92 customParser = type.customParser();
93 }
94
96
97 // Collect group properties first for sanity checking
98 // vector values are sorted by property name string index.
99 GroupPropertyVector groupProperties;
100 const QV4::CompiledData::Binding *binding = obj->bindingTable();
101 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
102 if (!binding->isGroupProperty())
103 continue;
104
106 continue;
107
108 if (populatingValueTypeGroupProperty) {
109 return recordError(binding->location, tr("Property assignment expected"));
110 }
111
112 GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
113 groupProperties.insert(pos, binding);
114 }
115
116 QQmlPropertyResolver propertyResolver(propertyCache);
117
118 QString defaultPropertyName;
119 const QQmlPropertyData *defaultProperty = nullptr;
120 if (obj->indexOfDefaultPropertyOrAlias != -1) {
121 const QQmlPropertyCache *cache = propertyCache->parent().data();
122 defaultPropertyName = cache->defaultPropertyName();
123 defaultProperty = cache->defaultProperty();
124 } else {
125 defaultPropertyName = propertyCache->defaultPropertyName();
126 defaultProperty = propertyCache->defaultProperty();
127 }
128
129 QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
130
131 binding = obj->bindingTable();
132 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
133 QString name = stringAt(binding->propertyNameIndex);
134 const QV4::CompiledData::Binding::Type bindingType = binding->type();
135 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
136
137 if (customParser) {
140 customBindings << binding;
141 continue;
142 }
144 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
145 customBindings << binding;
146 continue;
147 }
148 }
149
150 bool bindingToDefaultProperty = false;
151 bool isGroupProperty = instantiatingBinding
152 && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
153
154 bool notInRevision = false;
155 const QQmlPropertyData *pd = nullptr;
156 if (!name.isEmpty()) {
159 pd = propertyResolver.signal(name, &notInRevision);
160 } else {
161 pd = propertyResolver.property(name, &notInRevision,
163 }
164
165 if (notInRevision) {
166 QString typeName = stringAt(obj->inheritedTypeNameIndex);
167 if (auto *objectType = resolvedType(obj->inheritedTypeNameIndex)) {
168 const auto type = objectType->type();
169 if (type.isValid()) {
170 const auto version = objectType->version();
171 return recordError(binding->location,
172 tr("\"%1.%2\" is not available in %3 %4.%5.")
173 .arg(typeName).arg(name).arg(type.module())
174 .arg(version.majorVersion())
175 .arg(version.minorVersion()));
176 }
177 } else {
178 return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
179 }
180 }
181 } else {
182 if (isGroupProperty)
183 return recordError(binding->location, tr("Cannot assign a value directly to a grouped property"));
184
185 pd = defaultProperty;
186 name = defaultPropertyName;
187 bindingToDefaultProperty = true;
188 }
189
190 if (pd)
191 collectedBindingPropertyData[i] = pd;
192
193 if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
195 QQmlImportNamespace *typeNamespace = nullptr;
196 imports->resolveType(
197 stringAt(binding->propertyNameIndex), &type, nullptr, &typeNamespace);
198 if (typeNamespace)
199 return recordError(binding->location, tr("Invalid use of namespace"));
200 return recordError(binding->location, tr("Invalid attached object assignment"));
201 }
202
204 && (pd || binding->isAttachedProperty() || binding->isGroupProperty())) {
205 const bool populatingValueTypeGroupProperty
206 = pd
209 const QVector<QQmlError> subObjectValidatorErrors
210 = validateObject(binding->value.objectIndex, binding,
211 populatingValueTypeGroupProperty);
212 if (!subObjectValidatorErrors.isEmpty())
213 return subObjectValidatorErrors;
214 }
215
216 // Signal handlers were resolved and checked earlier in the signal handler conversion pass.
220 continue;
221 }
222
224 || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupProperty)) {
225 if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
226 || instantiatingBinding->isGroupProperty())) {
227 return recordError(
228 binding->location, tr("%1 properties cannot be used here")
230 ? QStringLiteral("Attached")
231 : QStringLiteral("Group")));
232 }
233 continue;
234 } else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
235 continue;
236 }
237
238 if (pd) {
239 GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder());
240 const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex);
241
242 if (!pd->isWritable()
243 && !pd->isQList()
244 && !binding->isGroupProperty()
246 ) {
247
248 if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
249 return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
250 return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
251 }
252
253 if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
255 if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
256 error = tr( "Cannot assign multiple values to a script property");
257 else
258 error = tr( "Cannot assign multiple values to a singular property");
259 return recordError(binding->valueLocation, error);
260 }
261
262 if (!bindingToDefaultProperty
263 && !binding->isGroupProperty()
265 && assigningToGroupProperty) {
267 if (loc < (*assignedGroupProperty)->valueLocation)
268 loc = (*assignedGroupProperty)->valueLocation;
269
270 if (pd && QQmlMetaType::isValueType(pd->propType()))
271 return recordError(loc, tr("Property has already been assigned a value"));
272 return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
273 }
274
275 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
276 QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
277 if (bindingError.isValid())
278 return recordError(bindingError);
279 } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
280 QQmlError bindingError = validateObjectBinding(pd, name, binding);
281 if (bindingError.isValid())
282 return recordError(bindingError);
283 } else if (binding->isGroupProperty()) {
286 if (!pd->isWritable()) {
287 return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
288 }
289 } else {
290 return recordError(binding->location, tr("Invalid grouped property access"));
291 }
292 } else {
293 const QMetaType type = pd->propType();
294 if (isPrimitiveType(type)) {
295 return recordError(
296 binding->location,
297 tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
298 .arg(name)
299 .arg(QString::fromUtf8(type.name()))
300 );
301 }
302
304 return recordError(binding->location,
305 tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
306 .arg(name)
307 .arg(QString::fromUtf8(type.name()))
308 );
309 }
310 }
311 }
312 } else {
313 if (customParser) {
314 customBindings << binding;
315 continue;
316 }
317 if (bindingToDefaultProperty) {
318 return recordError(binding->location, tr("Cannot assign to non-existent default property"));
319 } else {
320 return recordError(binding->location, tr("Cannot assign to non-existent property \"%1\"").arg(name));
321 }
322 }
323 }
324
325 if (obj->idNameIndex) {
326 if (populatingValueTypeGroupProperty)
327 return recordError(obj->locationOfIdProperty, tr("Invalid use of id property with a value type"));
328
329 bool notInRevision = false;
330 collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), &notInRevision);
331 }
332
333 if (customParser && !customBindings.isEmpty()) {
334 customParser->clearErrors();
335 customParser->validator = this;
336 customParser->engine = enginePrivate;
337 customParser->imports = imports;
338 customParser->verifyBindings(compilationUnit, customBindings);
339 customParser->validator = nullptr;
340 customParser->engine = nullptr;
341 customParser->imports = (QQmlImports*)nullptr;
342 QVector<QQmlError> parserErrors = customParser->errors();
343 if (!parserErrors.isEmpty())
344 return parserErrors;
345 }
346
347 (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
348
349 QVector<QQmlError> noError;
350 return noError;
351}
352
353QQmlError QQmlPropertyValidator::validateLiteralBinding(
354 const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
355 const QV4::CompiledData::Binding *binding) const
356{
357 if (property->isQList()) {
358 return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
359 }
360
361 QQmlError noError;
362
363 if (property->isEnum()) {
365 return noError;
366
367 QString value = compilationUnit->bindingValueAsString(binding);
368 QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
369 bool ok;
370 if (p.isFlagType()) {
371 p.enumerator().keysToValue(value.toUtf8().constData(), &ok);
372 } else
373 p.enumerator().keyToValue(value.toUtf8().constData(), &ok);
374
375 if (!ok) {
376 return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration"));
377 }
378 return noError;
379 }
380
381 auto warnOrError = [&](const QString &error) {
382 return qQmlCompileError(binding->valueLocation, error);
383 };
384
385 const QV4::CompiledData::Binding::Type bindingType = binding->type();
386 const auto isStringBinding = [&]() -> bool {
387 // validateLiteralBinding is not supposed to be used on scripts
389 return bindingType == QV4::CompiledData::Binding::Type_String;
390 };
391
392 switch (property->propType().id()) {
394 break;
395 case QMetaType::QString: {
396 if (!binding->evaluatesToString()) {
397 return warnOrError(tr("Invalid property assignment: string expected"));
398 }
399 }
400 break;
401 case QMetaType::QStringList: {
402 if (!binding->evaluatesToString()) {
403 return warnOrError(tr("Invalid property assignment: string or string list expected"));
404 }
405 }
406 break;
407 case QMetaType::QByteArray: {
409 return warnOrError(tr("Invalid property assignment: byte array expected"));
410 }
411 break;
412 case QMetaType::QUrl: {
414 return warnOrError(tr("Invalid property assignment: url expected"));
415 }
416 break;
417 case QMetaType::UInt: {
418 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
419 double d = compilationUnit->bindingValueAsNumber(binding);
420 if (double(uint(d)) == d)
421 return noError;
422 }
423 return warnOrError(tr("Invalid property assignment: unsigned int expected"));
424 }
425 break;
426 case QMetaType::Int: {
427 if (bindingType == QV4::CompiledData::Binding::Type_Number) {
428 double d = compilationUnit->bindingValueAsNumber(binding);
429 if (double(int(d)) == d)
430 return noError;
431 }
432 return warnOrError(tr("Invalid property assignment: int expected"));
433 }
434 break;
435 case QMetaType::Float: {
436 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
437 return warnOrError(tr("Invalid property assignment: number expected"));
438 }
439 }
440 break;
441 case QMetaType::Double: {
442 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
443 return warnOrError(tr("Invalid property assignment: number expected"));
444 }
445 }
446 break;
447 case QMetaType::QColor: {
448 bool ok = false;
449 if (isStringBinding())
451 if (!ok) {
452 return warnOrError(tr("Invalid property assignment: color expected"));
453 }
454 }
455 break;
456#if QT_CONFIG(datestring)
457 case QMetaType::QDate: {
458 bool ok = false;
459 if (isStringBinding())
460 QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
461 if (!ok) {
462 return warnOrError(tr("Invalid property assignment: date expected"));
463 }
464 }
465 break;
466 case QMetaType::QTime: {
467 bool ok = false;
468 if (isStringBinding())
469 QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
470 if (!ok) {
471 return warnOrError(tr("Invalid property assignment: time expected"));
472 }
473 }
474 break;
475 case QMetaType::QDateTime: {
476 bool ok = false;
477 if (isStringBinding())
478 QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
479 if (!ok) {
480 return warnOrError(tr("Invalid property assignment: datetime expected"));
481 }
482 }
483 break;
484#endif // datestring
485 case QMetaType::QPoint: {
486 bool ok = false;
487 if (isStringBinding())
489 if (!ok) {
490 return warnOrError(tr("Invalid property assignment: point expected"));
491 }
492 }
493 break;
494 case QMetaType::QPointF: {
495 bool ok = false;
496 if (isStringBinding())
498 if (!ok) {
499 return warnOrError(tr("Invalid property assignment: point expected"));
500 }
501 }
502 break;
503 case QMetaType::QSize: {
504 bool ok = false;
505 if (isStringBinding())
507 if (!ok) {
508 return warnOrError(tr("Invalid property assignment: size expected"));
509 }
510 }
511 break;
512 case QMetaType::QSizeF: {
513 bool ok = false;
514 if (isStringBinding())
516 if (!ok) {
517 return warnOrError(tr("Invalid property assignment: size expected"));
518 }
519 }
520 break;
521 case QMetaType::QRect: {
522 bool ok = false;
523 if (isStringBinding())
525 if (!ok) {
526 return warnOrError(tr("Invalid property assignment: rect expected"));
527 }
528 }
529 break;
530 case QMetaType::QRectF: {
531 bool ok = false;
532 if (isStringBinding())
534 if (!ok) {
535 return warnOrError(tr("Invalid property assignment: point expected"));
536 }
537 }
538 break;
539 case QMetaType::Bool: {
540 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
541 return warnOrError(tr("Invalid property assignment: boolean expected"));
542 }
543 }
544 break;
545 case QMetaType::QVector2D:
546 case QMetaType::QVector3D:
547 case QMetaType::QVector4D:
548 case QMetaType::QQuaternion: {
549 auto typeName = [&]() {
550 switch (property->propType().id()) {
551 case QMetaType::QVector2D: return QStringLiteral("2D vector");
552 case QMetaType::QVector3D: return QStringLiteral("3D vector");
553 case QMetaType::QVector4D: return QStringLiteral("4D vector");
554 case QMetaType::QQuaternion: return QStringLiteral("quaternion");
555 default: return QString();
556 }
557 };
559 compilationUnit->bindingValueAsString(binding),
560 property->propType());
561 if (!result.isValid()) {
562 return warnOrError(tr("Invalid property assignment: %1 expected")
563 .arg(typeName()));
564 }
565 }
566 break;
567 case QMetaType::QRegularExpression:
568 return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
569 default: {
570 // generate single literal value assignment to a list property if required
571 if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
572 if (bindingType != QV4::CompiledData::Binding::Type_Number) {
573 return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
574 }
575 break;
576 } else if (property->propType() == QMetaType::fromType<QList<int> >()) {
577 bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
578 if (ok) {
579 double n = compilationUnit->bindingValueAsNumber(binding);
580 if (double(int(n)) != n)
581 ok = false;
582 }
583 if (!ok)
584 return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
585 break;
586 } else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
587 if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
588 return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
589 }
590 break;
591 } else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
592 if (bindingType != QV4::CompiledData::Binding::Type_String) {
593 return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
594 }
595 break;
596 } else if (property->propType() == QMetaType::fromType<QList<QString> >()) {
597 if (!binding->evaluatesToString()) {
598 return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
599 }
600 break;
601 } else if (property->propType() == QMetaType::fromType<QJSValue>()) {
602 break;
603 } else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
604 break;
605 } else if (property->isQObject()
606 && bindingType == QV4::CompiledData::Binding::Type_Null) {
607 break;
608 } else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
609 break;
610 }
611
612 return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(property->propType().name())));
613 }
614 break;
615 }
616 return noError;
617}
618
623bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const
624{
626
627 if (toMo.isNull()) {
628 // if we have an inline component from the current file,
629 // it is not properly registered at this point, as registration
630 // only occurs after the whole file has been validated
631 // Therefore we need to check the ICs here
632 for (const auto& icDatum : compilationUnit->inlineComponentData) {
633 if (icDatum.qmlType.typeId() == to) {
634 toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
635 break;
636 }
637 }
638 }
639
640 while (fromMo) {
641 if (fromMo == toMo)
642 return true;
643 fromMo = fromMo->parent();
644 }
645 return false;
646}
647
648QVector<QQmlError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
649{
650 QVector<QQmlError> errors;
651 errors.append(qQmlCompileError(location, description));
652 return errors;
653}
654
655QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) const
656{
657 QVector<QQmlError> errors;
658 errors.append(error);
659 return errors;
660}
661
662QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
663{
664 QQmlError noError;
665
668
669 bool isValueSource = false;
670 bool isPropertyInterceptor = false;
671
672 const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
673 if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
674 QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
675 const QMetaObject *mo = cache ? cache->firstCppMetaObject() : nullptr;
676 QQmlType qmlType;
677 while (mo && !qmlType.isValid()) {
678 qmlType = QQmlMetaType::qmlType(mo);
679 mo = mo->superClass();
680 }
681
682 isValueSource = qmlType.propertyValueSourceCast() != -1;
683 isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
684 }
685
686 if (!isValueSource && !isPropertyInterceptor) {
687 return qQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName));
688 }
689
690 return noError;
691 }
692
693 const QMetaType propType = property->propType();
694 const auto rhsType = [&]() {
695 return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
697 };
698
699 if (QQmlMetaType::isInterface(propType)) {
700 // Can only check at instantiation time if the created sub-object successfully casts to the
701 // target interface.
702 return noError;
703 } else if (propType == QMetaType::fromType<QVariant>()
704 || propType == QMetaType::fromType<QJSValue>()) {
705 // We can convert everything to QVariant :)
706 return noError;
707 } else if (property->isQList()) {
708 const QMetaType listType = QQmlMetaType::listValueType(property->propType());
709 if (!QQmlMetaType::isInterface(listType)) {
710 QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
711 if (!canCoerce(listType, source)) {
712 return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
713 }
714 }
715 return noError;
717 && property->isFunction()) {
718 return noError;
719 } else if (isPrimitiveType(propType)) {
720 auto typeName = QString::fromUtf8(QMetaType(propType).name());
721 return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
722 .arg(rhsType())
723 .arg(propertyName)
724 .arg(typeName));
725 } else if (propType == QMetaType::fromType<QQmlScriptString>()) {
726 return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
727 } else if (QQmlMetaType::isValueType(property->propType())) {
728 return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object")
729 .arg(rhsType()).arg(propertyName));
730 } else {
731 // We want to use the raw metaObject here as the raw metaobject is the
732 // actual property type before we applied any extensions that might
733 // effect the properties on the type, but don't effect assignability
734 // Not passing a version ensures that we get the raw metaObject.
735 QQmlPropertyCache::ConstPtr propertyMetaObject
737 if (!propertyMetaObject) {
738 // if we have an inline component from the current file,
739 // it is not properly registered at this point, as registration
740 // only occurs after the whole file has been validated
741 // Therefore we need to check the ICs here
742 for (const auto& icDatum: compilationUnit->inlineComponentData) {
743 if (icDatum.qmlType.typeId() == property->propType()) {
744 propertyMetaObject = compilationUnit->propertyCaches.at(icDatum.objectIndex);
745 break;
746 }
747 }
748 }
749
750 if (propertyMetaObject) {
751 // Will be true if the assigned type inherits propertyMetaObject
752 // Determine isAssignable value
753 bool isAssignable = false;
754 QQmlPropertyCache::ConstPtr c = propertyCaches.at(binding->value.objectIndex);
755 while (c && !isAssignable) {
756 isAssignable |= c == propertyMetaObject;
757 c = c->parent();
758 }
759
760 if (!isAssignable) {
761 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.")
762 .arg(rhsType()).arg(QLatin1String(property->propType().name())));
763 }
764 } else {
765 return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
766 .arg(QLatin1String(property->propType().name())));
767 }
768
769 }
770 return noError;
771}
772
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:320
static constexpr QMetaType fromType()
Definition qmetatype.h:2612
int id(int=0) const
Definition qmetatype.h:454
friend class QVariant
Definition qmetatype.h:775
The QQmlCustomParser class allows you to add new arbitrary types to QML.
QVector< QQmlError > errors() const
virtual void verifyBindings(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &, const QList< const QV4::CompiledData::Binding * > &)=0
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
bool isValid() const
Returns true if this error is valid, otherwise false.
The QQmlImports class encapsulates one QML document's import statements.
bool resolveType(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
static QMetaType listValueType(QMetaType type)
static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(QMetaType metaType)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static bool isInterface(QMetaType type)
See qmlRegisterInterface() for information about when this will return true.
static QQmlType qmlType(const QString &qualifiedName, QTypeRevision version)
Returns the type (if any) of URI-qualified named qualifiedName and version specified by version_major...
static bool isValueType(QMetaType type)
static QQmlPropertyCache::ConstPtr propertyCacheForType(QMetaType metaType)
QQmlPropertyCache::ConstPtr at(int index) const
QMetaType propType() const
QVector< QQmlError > validate()
QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports *imports, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit)
T * data() const
bool isNull() const
int propertyValueSourceCast() const
Definition qqmltype.cpp:706
int propertyValueInterceptorCast() const
Definition qqmltype.cpp:713
bool canConstructValueType() const
Definition qqmltype.cpp:536
bool isValid() const
Definition qqmltype_p.h:58
static QVariant createValueType(const QJSValue &, QMetaType)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
const CompiledObject * objectAt(int index) const
QString bindingValueAsString(const CompiledData::Binding *binding) const
void insert(qsizetype i, T &&t)
typename Base::const_iterator const_iterator
const_iterator constEnd() const
auto constBegin() const -> const_iterator
\inmodule QtCore
Definition qvariant.h:64
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
auto mo
[7]
Q_QML_PRIVATE_EXPORT QPointF pointFFromString(const QString &, bool *ok=nullptr)
Q_QML_PRIVATE_EXPORT unsigned rgbaFromString(const QString &, bool *ok=nullptr)
Q_QML_PRIVATE_EXPORT QSizeF sizeFFromString(const QString &, bool *ok=nullptr)
Q_QML_PRIVATE_EXPORT QRectF rectFFromString(const QString &, bool *ok=nullptr)
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * typeName
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)
Definition qmetatype.h:67
GLint location
GLenum type
GLuint name
GLfloat n
GLsizei GLsizei GLchar * source
GLhandleARB obj
[2]
const GLubyte * c
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
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)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
unsigned int quint32
Definition qtypes.h:45
unsigned int uint
Definition qtypes.h:29
const char property[13]
Definition qwizard.cpp:101
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
\inmodule QtCore
union QV4::CompiledData::Binding::@543 value
bool hasFlag(Flag flag) const
double bindingValueAsNumber(const CompiledData::Binding *binding) const
static bool isSignalPropertyName(const QString &name)