3#ifndef QQMLPROPERTYCACHECREATOR_P_H
4#define QQMLPROPERTYCACHECREATOR_P_H
17#include <private/qqmlvaluetype_p.h>
18#include <private/qqmlengine_p.h>
19#include <private/qqmlmetaobject_p.h>
20#include <private/qqmltypedata_p.h>
21#include <private/inlinecomponentutils_p.h>
22#include <private/qqmlsourcecoordinate_p.h>
23#include <private/qqmlsignalnames_p.h>
24#include <private/qexpected_p.h>
26#include <QtCore/qloggingcategory.h>
27#include <QtCore/qscopedvaluerollback.h>
29#if QT_CONFIG(regularexpression)
30#include <QtCore/qregularexpression.h>
40 const QString &description)
43 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
44 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
45 error.setDescription(description);
52 int referencingObjectIndex,
const QV4::CompiledData::Binding *instantiatingBinding,
53 const QString &instantiatingPropertyName,
54 const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache);
69 QQmlPropertyCacheVector *propertyCaches)
const;
81 case QV4::CompiledData::CommonType::Void:
return QMetaType();
82 case QV4::CompiledData::CommonType::Var:
return QMetaType::fromType<QVariant>();
83 case QV4::CompiledData::CommonType::Int:
return QMetaType::fromType<
int>();
84 case QV4::CompiledData::CommonType::Bool:
return QMetaType::fromType<
bool>();
85 case QV4::CompiledData::CommonType::Real:
return QMetaType::fromType<qreal>();
86 case QV4::CompiledData::CommonType::String:
return QMetaType::fromType<QString>();
87 case QV4::CompiledData::CommonType::Url:
return QMetaType::fromType<QUrl>();
88 case QV4::CompiledData::CommonType::Time:
return QMetaType::fromType<QTime>();
89 case QV4::CompiledData::CommonType::Date:
return QMetaType::fromType<QDate>();
90 case QV4::CompiledData::CommonType::DateTime:
return QMetaType::fromType<QDateTime>();
91#if QT_CONFIG(regularexpression)
92 case QV4::CompiledData::CommonType::RegExp:
return QMetaType::fromType<QRegularExpression>();
94 case QV4::CompiledData::CommonType::RegExp:
return QMetaType();
96 case QV4::CompiledData::CommonType::Rect:
return QMetaType::fromType<QRectF>();
97 case QV4::CompiledData::CommonType::Point:
return QMetaType::fromType<QPointF>();
98 case QV4::CompiledData::CommonType::Size:
return QMetaType::fromType<QSizeF>();
99 case QV4::CompiledData::CommonType::Invalid:
break;
107 case QV4::CompiledData::CommonType::Void:
return QMetaType();
108 case QV4::CompiledData::CommonType::Var:
return QMetaType::fromType<QList<QVariant>>();
109 case QV4::CompiledData::CommonType::Int:
return QMetaType::fromType<QList<
int>>();
110 case QV4::CompiledData::CommonType::Bool:
return QMetaType::fromType<QList<
bool>>();
111 case QV4::CompiledData::CommonType::Real:
return QMetaType::fromType<QList<qreal>>();
112 case QV4::CompiledData::CommonType::String:
return QMetaType::fromType<QList<QString>>();
113 case QV4::CompiledData::CommonType::Url:
return QMetaType::fromType<QList<QUrl>>();
114 case QV4::CompiledData::CommonType::Time:
return QMetaType::fromType<QList<QTime>>();
115 case QV4::CompiledData::CommonType::Date:
return QMetaType::fromType<QList<QDate>>();
116 case QV4::CompiledData::CommonType::DateTime:
return QMetaType::fromType<QList<QDateTime>>();
117#if QT_CONFIG(regularexpression)
118 case QV4::CompiledData::CommonType::RegExp:
return QMetaType::fromType<QList<QRegularExpression>>();
120 case QV4::CompiledData::CommonType::RegExp:
return QMetaType();
122 case QV4::CompiledData::CommonType::Rect:
return QMetaType::fromType<QList<QRectF>>();
123 case QV4::CompiledData::CommonType::Point:
return QMetaType::fromType<QList<QPointF>>();
124 case QV4::CompiledData::CommonType::Size:
return QMetaType::fromType<QList<QSizeF>>();
125 case QV4::CompiledData::CommonType::Invalid:
break;
131 if (!metaType.isValid())
132 return QV4::CompiledData::CommonType::Void;
134 switch (metaType.id()) {
135 case QMetaType::QVariant:
136 return QV4::CompiledData::CommonType::Var;
138 return QV4::CompiledData::CommonType::Int;
139 case QMetaType::Bool:
140 return QV4::CompiledData::CommonType::Bool;
141 case QMetaType::QReal:
142 return QV4::CompiledData::CommonType::Real;
143 case QMetaType::QString:
144 return QV4::CompiledData::CommonType::String;
145 case QMetaType::QUrl:
146 return QV4::CompiledData::CommonType::Url;
147 case QMetaType::QTime:
148 return QV4::CompiledData::CommonType::Time;
149 case QMetaType::QDate:
150 return QV4::CompiledData::CommonType::Date;
151 case QMetaType::QDateTime:
152 return QV4::CompiledData::CommonType::DateTime;
153#if QT_CONFIG(regularexpression)
154 case QMetaType::QRegularExpression:
155 return QV4::CompiledData::CommonType::RegExp;
157 case QMetaType::QRectF:
158 return QV4::CompiledData::CommonType::Rect;
159 case QMetaType::QPointF:
160 return QV4::CompiledData::CommonType::Point;
161 case QMetaType::QSizeF:
162 return QV4::CompiledData::CommonType::Size;
166 return QV4::CompiledData::CommonType::Invalid;
183template <
typename ObjectContainer>
192 QQmlTypeLoader *typeLoader,
193 const ObjectContainer *objectContainer,
const QQmlImports *imports,
194 const QByteArray &typeClassName);
199
200
201
202
203
204
205
209
210
211
212
216
217
218
219
220
221
224 QByteArray dynamicClassName = QByteArray())
const;
227
228
229
230
231
232
233
234
235
238 int notifyIndex)
const;
250 QString *customTypeName =
nullptr)
const;
258 QTypeRevision revision = QTypeRevision::zero();
259 QV4::CompiledData::CommonType commonType = QV4::CompiledData::CommonType::Invalid;
262 [[
nodiscard]] q23::expected<PropertyType, QQmlError>
263 tryResolvePropertyType(
const QV4::CompiledData::Property &propertyIR)
const;
266 [[
nodiscard]]
static QQmlPropertyData::Flags
267 propertyDataFlags(
const QV4::CompiledData::Property &propertyIR,
268 const PropertyType &resolvedPropertyType);
286template <
typename ObjectContainer>
288 QQmlPropertyCacheVector *propertyCaches,
290 QQmlTypeLoader *typeLoader,
291 const ObjectContainer *objectContainer,
const QQmlImports *imports,
292 const QByteArray &typeClassName)
301 propertyCaches->resetAndResize(objectContainer->objectCount());
303 using namespace icutils;
307 for (
int i=0; i != objectContainer->objectCount(); ++i) {
309 for (
auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
310 allICs.push_back(*it);
315 std::vector<icutils::Node> nodes;
316 nodes.resize(allICs.size());
317 std::iota(nodes.begin(), nodes.end(), 0);
318 AdjacencyList adjacencyList;
319 adjacencyList.resize(nodes.size());
320 fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
322 nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
323 nodeIt = nodesSorted.rbegin();
326template <
typename ObjectContainer>
331 diag.setDescription(QLatin1String(
"Inline components form a cycle!"));
337template <
typename ObjectContainer>
345 if (nodeIt != nodesSorted.rend()) {
346 const auto &ic = allICs[nodeIt->index()];
347 QV4::ResolvedTypeReference *typeRef =
objectContainer->resolvedType(ic.nameIndex);
348 Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
349 Q_ASSERT(typeRef->typePropertyCache().isNull());
351 QByteArray icTypeName {
objectContainer->stringAt(ic.nameIndex).toUtf8() };
352 QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
353 QScopedValueRollback<
unsigned int> rootChange {
currentRoot, ic.objectIndex};
355 QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
356 if (diag.isValid()) {
357 return {diag,
false, 0};
359 typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
360 Q_ASSERT(!typeRef->typePropertyCache().isNull());
361 return { QQmlError(),
true,
int(ic.objectIndex) };
364 auto diag = buildMetaObjectRecursively(0, m_context, VMEMetaObjectIsRequired::Maybe);
365 return {diag,
false, 0};
368template <
typename ObjectContainer>
371 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &baseTypeCache,
372 QByteArray dynamicClassName)
const
374 QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
375 obj->propertyCount() + obj->aliasCount(),
376 obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
377 obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount());
378 cache->_dynamicClassName =
std::move(dynamicClassName);
380 int effectiveMethodIndex = cache->methodIndexCacheStart;
386 enum class AllowOverride { No, Yes };
387 QHash<QString, AllowOverride> seenSignals{
388 { QStringLiteral(
"destroyed"), AllowOverride::No },
389 { QStringLiteral(
"parentChanged"), AllowOverride::No },
390 { QStringLiteral(
"objectNameChanged"), AllowOverride::No }
392 const QQmlPropertyCache *parentCache = cache.data();
393 while ((parentCache = parentCache->parent().data())) {
394 if (
int pSigCount = parentCache->signalCount()) {
395 int pSigOffset = parentCache->signalOffset();
396 for (
int i = pSigOffset; i < pSigCount; ++i) {
397 const QQmlPropertyData *currPSig = parentCache->signal(i);
399 for (QQmlPropertyCache::StringCache::ConstIterator iter =
400 parentCache->stringCache.begin();
401 iter != parentCache->stringCache.end(); ++iter) {
402 if (currPSig == (*iter).second) {
403 if (currPSig->isOverridableSignal()) {
404 const qsizetype oldSize = seenSignals.size();
405 AllowOverride &entry = seenSignals[iter.key()];
406 if (seenSignals.size() != oldSize)
407 entry = AllowOverride::Yes;
409 seenSignals[iter.key()] = AllowOverride::No;
420 auto p = obj->propertiesBegin();
421 auto pend = obj->propertiesEnd();
422 for (; p != pend; ++p) {
423 auto flags = QQmlPropertyData::defaultSignalFlags();
425 const QString changedSigName =
426 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex()));
427 seenSignals[changedSigName] = AllowOverride::No;
429 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
432 auto a = obj->aliasesBegin();
433 auto aend = obj->aliasesEnd();
434 for (; a != aend; ++a) {
435 auto flags = QQmlPropertyData::defaultSignalFlags();
437 const QString changedSigName =
438 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
439 seenSignals[changedSigName] = AllowOverride::No;
441 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
444 auto e = obj->enumsBegin();
445 auto eend = obj->enumsEnd();
446 for (; e != eend; ++e) {
447 const int enumValueCount = e->enumValueCount();
448 QVector<QQmlEnumValue> values;
449 values.reserve(enumValueCount);
451 auto enumValue = e->enumValuesBegin();
452 auto end = e->enumValuesEnd();
453 for (; enumValue != end; ++enumValue)
454 values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
456 cache->appendEnum(stringAt(e->nameIndex), values);
460 auto s = obj->signalsBegin();
461 auto send = obj->signalsEnd();
462 for (; s != send; ++s) {
463 const int paramCount = s->parameterCount();
465 QList<QByteArray> names;
466 names.reserve(paramCount);
467 QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
472 auto param = s->parametersBegin();
473 auto end = s->parametersEnd();
474 for (; param != end; ++param, ++i) {
475 names.append(stringAt(param->nameIndex).toUtf8());
477 QString customTypeName;
478 QMetaType type = metaTypeForParameter(param->type, &customTypeName);
480 return q23::make_unexpected(qQmlCompileError(
482 QQmlPropertyCacheCreatorBase::tr(
"Invalid signal parameter type: %1")
483 .arg(customTypeName)));
485 paramTypes[i] = type;
489 auto flags = QQmlPropertyData::defaultSignalFlags();
491 flags.setHasArguments(
true);
493 QString signalName = stringAt(s->nameIndex);
494 const auto it = seenSignals.find(signalName);
495 if (it == seenSignals.end()) {
496 seenSignals[signalName] = AllowOverride::No;
499 QQmlError message = qQmlCompileError(
501 QQmlPropertyCacheCreatorBase::tr(
502 "Duplicate signal name: "
503 "invalid override of property change signal or superclass signal"));
505 case AllowOverride::No:
506 return q23::make_unexpected(std::move(message));
507 case AllowOverride::Yes:
509 qCWarning(invalidOverride).noquote() << message.toString();
510 *it = AllowOverride::No;
514 cache->appendSignal(signalName, flags, effectiveMethodIndex++,
515 paramCount ? paramTypes.constData() :
nullptr, names);
521 for (; function != fend; ++function) {
522 auto flags = QQmlPropertyData::defaultSlotFlags();
524 const QString slotName = stringAt(function->nameIndex);
525 const auto it = seenSignals.constFind(slotName);
526 if (it != seenSignals.constEnd()) {
528 QQmlError message = qQmlCompileError(
530 QQmlPropertyCacheCreatorBase::tr(
531 "Duplicate method name: "
532 "invalid override of property change signal or superclass signal"));
534 case AllowOverride::No:
535 return q23::make_unexpected(std::move(message));
536 case AllowOverride::Yes:
538 qCWarning(invalidOverride).noquote() << message.toString();
545 QList<QByteArray> parameterNames;
546 QVector<QMetaType> parameterTypes;
547 auto formal = function->formalsBegin();
548 auto end = function->formalsEnd();
549 for (; formal != end; ++formal) {
550 flags.setHasArguments(
true);
551 parameterNames << stringAt(formal->nameIndex).toUtf8();
552 QMetaType type = metaTypeForParameter(formal->type);
554 type = QMetaType::fromType<QVariant>();
555 parameterTypes << type;
558 QMetaType returnType = metaTypeForParameter(function->returnType);
559 if (!returnType.isValid())
560 returnType = QMetaType::fromType<QVariant>();
562 cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames,
567 int propertyIndex = cache->propertyIndexCacheStart;
568 int notifyIndex = cache->signalHandlerIndexCacheStart;
569 int objPropertyIdx = 0;
570 p = obj->propertiesBegin();
571 pend = obj->propertiesEnd();
572 for (; p != pend; ++p, ++objPropertyIdx, propertyIndex++, notifyIndex++) {
573 auto propertyDataOrError = tryCreateQQmlPropertyData(*p, propertyIndex, notifyIndex);
574 if (!propertyDataOrError.has_value()) {
575 return q23::make_unexpected(propertyDataOrError.error());
578 QString propertyName = stringAt(p->nameIndex());
579 if (!obj->hasAliasAsDefaultProperty()
580 && objPropertyIdx == obj->indexOfDefaultPropertyOrAlias)
581 cache->_defaultPropertyName = propertyName;
583 if (cache->doAppendPropertyData(propertyName, std::move(propertyDataOrError).value())
584 == QQmlPropertyCache::OverrideResult::InvalidOverride) {
585 return q23::make_unexpected(qQmlCompileError(
588 QQmlPropertyCacheCreatorBase::tr(
"Cannot override FINAL property")));
594template <
typename ObjectContainer>
597 const QV4::CompiledData::Property &propertyIR,
int coreIndex,
int notifyIndex)
const
599 const auto propertyTypeOrError = tryResolvePropertyType(propertyIR);
600 if (!propertyTypeOrError.has_value()) {
601 return q23::make_unexpected(propertyTypeOrError.error());
603 const auto propertyType = propertyTypeOrError.value();
605 QQmlPropertyData propertyData;
606 propertyData.setPropType(propertyType.metaType);
607 propertyData.setCoreIndex(coreIndex);
608 propertyData.setNotifyIndex(notifyIndex);
609 propertyData.setFlags(QQmlPropertyCacheCreator::propertyDataFlags(propertyIR, propertyType));
610 propertyData.setTypeVersion(propertyType.revision);
614template <
typename ObjectContainer>
617 auto isAddressable = [](
const QUrl &url) {
618 const QString fileName = url.fileName();
619 return !fileName.isEmpty() && fileName.front().isUpper();
623 bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always
624 || obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0
625 || obj->functionCount() != 0 || obj->enumCount() != 0
626 || obj->inlineComponentCount() != 0
627 || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
628 || (objectIndex == 0 && isAddressable(objectContainer->url())))
629 && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
631 if (!needVMEMetaObject) {
632 auto binding = obj->bindingsBegin();
633 auto end = obj->bindingsEnd();
634 for ( ; binding != end; ++binding) {
635 if (binding->type() == QV4::CompiledData::Binding::Type_Object
636 && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
641 if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
642 if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
644 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
646 QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
647 QQmlError error = baseTypeCache
648 ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
649 : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
650 "Type cannot be used for 'on' assignment"));
656 needVMEMetaObject =
true;
663 QQmlPropertyCache::ConstPtr baseTypeCache;
666 baseTypeCache = propertyCacheForObject(obj, context, &error);
672 if (needVMEMetaObject) {
673 QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
677 propertyCaches->set(objectIndex, baseTypeCache);
681 QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
682 auto binding = obj->bindingsBegin();
683 auto end = obj->bindingsEnd();
684 for (; binding != end; ++binding) {
685 switch (binding->type()) {
686 case QV4::CompiledData::Binding::Type_Object:
687 case QV4::CompiledData::Binding::Type_GroupProperty:
688 case QV4::CompiledData::Binding::Type_AttachedProperty:
697 objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
706 QQmlError error = buildMetaObjectRecursively(
707 binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
716template <
typename ObjectContainer>
719 if (context.instantiatingProperty) {
720 return context.instantiatingPropertyCache();
721 }
else if (obj->inheritedTypeNameIndex != 0) {
722 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
725 if (typeRef->isFullyDynamicType()) {
726 if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
727 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new properties."));
730 if (obj->signalCount() > 0) {
731 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new signals."));
734 if (obj->functionCount() > 0) {
735 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully Dynamic types cannot declare new functions."));
740 if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
741 return propertyCache;
742 *error = qQmlCompileError(
744 QQmlPropertyCacheCreatorBase::tr(
"Type '%1' cannot declare new members.")
745 .arg(stringAt(obj->inheritedTypeNameIndex)));
747 }
else if (
const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
748 if (binding->isAttachedProperty()) {
750 binding->propertyNameIndex);
752 QQmlType qmltype = typeRef->type();
753 if (!qmltype.isValid()) {
754 imports->resolveType(
755 typeLoader, stringAt(binding->propertyNameIndex),
756 &qmltype,
nullptr,
nullptr);
759 const QMetaObject *attachedMo = qmltype.attachedPropertiesType(typeLoader);
761 *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
"Non-existent attached object"));
764 return QQmlMetaType::propertyCache(attachedMo);
770template <
typename ObjectContainer>
773 const QQmlPropertyCache::ConstPtr &baseTypeCache)
775 const auto dynamicClassName = [
this](
int objectIndex,
const auto &baseTypeCache) -> QByteArray {
776 const auto isComponentRoot = objectIndex == 0
777 || objectIndex ==
int(currentRoot) ;
778 if (isComponentRoot && !typeClassName.isEmpty()) {
779 return typeClassName;
781 return QByteArray(QQmlMetaObject(baseTypeCache).className())
783 .append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
786 const auto cacheOrError =
787 tryDeriveCacheFrom(obj, baseTypeCache, dynamicClassName(objectIndex, baseTypeCache));
788 if (!cacheOrError.has_value()) {
789 return cacheOrError.error();
791 auto &cache = cacheOrError.value();
793 using ListPropertyAssignBehavior =
typename ObjectContainer::ListPropertyAssignBehavior;
795 case ListPropertyAssignBehavior::ReplaceIfNotDefault:
796 cache->_listPropertyAssignBehavior =
"ReplaceIfNotDefault";
798 case ListPropertyAssignBehavior::Replace:
799 cache->_listPropertyAssignBehavior =
"Replace";
801 case ListPropertyAssignBehavior::Append:
805 propertyCaches->setOwn(objectIndex, cache);
806 propertyCaches->setNeedsVMEMetaObject(objectIndex);
810template <
typename ObjectContainer>
812 const QV4::CompiledData::ParameterType ¶m, QString *customTypeName)
const
814 const quint32 typeId = param.typeNameIndexOrCommonType();
815 if (param.indexIsCommonType()) {
818 return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
819 return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
823 const QString typeName = stringAt(param.typeNameIndexOrCommonType());
825 *customTypeName = typeName;
827 bool selfReference =
false;
828 if (!imports->resolveType(
829 typeLoader, typeName, &qmltype,
nullptr,
nullptr,
nullptr,
830 QQmlType::AnyRegistrationType, &selfReference))
833 if (!qmltype.isComposite()) {
834 const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
835 if (!typeId.isValid() && qmltype.isInlineComponentType()) {
836 const QQmlType qmlType =
objectContainer->qmlTypeForComponent(qmltype.elementName());
837 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
845 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
848 return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
851template <
typename ObjectContainer>
853 const QV4::CompiledData::Property &propertyIR)
const
854 -> q23::expected<PropertyType, QQmlError>
856 PropertyType propertyType;
857 propertyType.commonType = propertyIR.commonType();
859 if (propertyType.commonType != QV4::CompiledData::CommonType::Invalid) {
861 propertyType.metaType = propertyIR.isList()
862 ? listTypeForPropertyType(propertyType.commonType)
863 : metaTypeForPropertyType(propertyType.commonType);
870 Q_ASSERT(!propertyIR.isCommonType());
872 bool selfReference =
false;
873 QList<QQmlError> errors;
874 const QString typeName = stringAt(propertyIR.commonTypeOrTypeNameIndex());
875 if (!imports->resolveType(typeLoader, typeName, &qmltype,
nullptr,
nullptr, &errors,
876 QQmlType::AnyRegistrationType, &selfReference)) {
877 Q_ASSERT(!errors.isEmpty());
878 return q23::make_unexpected(
879 qQmlCompileError(propertyIR.location, typeName + u' ' + errors[0].description()));
882 Q_ASSERT(qmltype.isValid());
884 propertyType.metaType = propertyIR.isList() ? qmltype.qListTypeId() : qmltype.typeId();
886 if (!qmltype.isComposite() && !qmltype.isInlineComponentType())
887 propertyType.revision = qmltype.version();
892template <
typename ObjectContainer>
894 const QV4::CompiledData::Property &propertyIR,
const PropertyType &resolvedPropertyType)
896 QQmlPropertyData::Flags flags;
899 if (propertyIR.isList()) {
900 flags.setType(QQmlPropertyData::Flags::QListType);
901 }
else if (resolvedPropertyType.commonType == QV4::CompiledData::CommonType::Var) {
902 flags.setType(QQmlPropertyData::Flags::VarPropertyType);
903 }
else if (resolvedPropertyType.metaType.flags().testFlag(QMetaType::PointerToQObject)) {
904 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
908 if (!propertyIR.isReadOnly()
909 && !resolvedPropertyType.metaType.flags().testFlag(QMetaType::IsQmlList))
910 flags.setIsWritable(
true);
911 if (propertyIR.isFinal())
912 flags.setIsFinal(
true);
917template <
typename ObjectContainer,
typename CompiledObject>
918int objectForId(
const ObjectContainer *objectContainer,
const CompiledObject &component,
int id)
920 for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
921 const int candidateIndex = component.namedObjectsInComponentTable()[i];
922 const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
923 if (candidate.objectId() == id)
924 return candidateIndex;
929template <
typename ObjectContainer>
936 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer);
938 const CompiledObject &component,
const QV4::CompiledData::Alias &alias,
int objectIndex,
939 int aliasIndex,
int encodedMetaPropertyIndex);
942 QQmlError propertyDataForAlias(
943 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
944 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
945 int targetPropertyIndex);
947 QQmlPropertyCacheVector *propertyCaches;
948 const ObjectContainer *objectContainer;
951template <
typename ObjectContainer>
953 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer)
955 , objectContainer(objectContainer)
959template <
typename ObjectContainer>
961 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
962 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
int targetPropertyIndex)
965 bool writable =
false;
966 bool resettable =
false;
967 bool notifiesViaBindable =
false;
969 propertyFlags->setIsAlias(
true);
971 if (alias.isAliasToLocalAlias()) {
972 const QV4::CompiledData::Alias *lastAlias = &alias;
973 QVarLengthArray<
const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
976 const int targetObjectIndex = objectForId(
977 objectContainer, component, lastAlias->targetObjectId());
978 Q_ASSERT(targetObjectIndex >= 0);
979 const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
980 Q_ASSERT(targetObject);
982 auto nextAlias = targetObject->aliasesBegin();
983 for (uint i = 0; i < lastAlias->localAliasIndex; ++i)
986 const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
987 if (seenAliases.contains(targetAlias)) {
988 return qQmlCompileError(targetAlias->location,
989 QQmlPropertyCacheCreatorBase::tr(
"Cyclic alias"));
992 seenAliases.append(targetAlias);
993 lastAlias = targetAlias;
994 }
while (lastAlias->isAliasToLocalAlias());
996 return propertyDataForAlias(
997 component, *lastAlias, type, version, propertyFlags, targetPropertyIndex);
1000 const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId());
1001 Q_ASSERT(targetObjectIndex >= 0);
1002 const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
1004 if (targetPropertyIndex == -1) {
1005 Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
1006 auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
1011 return qQmlCompileError(targetObject.location,
1012 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1015 const auto referencedType = typeRef->type();
1016 Q_ASSERT(referencedType.isValid());
1017 *type = referencedType.typeId();
1018 if (!type->isValid() && referencedType.isInlineComponentType()) {
1019 *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
1020 Q_ASSERT(type->isValid());
1023 *version = typeRef->version();
1025 propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
1027 int coreIndex = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).coreIndex();
1029 = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).valueTypeIndex();
1031 QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
1032 Q_ASSERT(targetCache);
1034 const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
1035 Q_ASSERT(targetProperty);
1037 const QMetaType targetPropType = targetProperty->propType();
1039 const auto populateWithPropertyData = [&](
const QQmlPropertyData *property) {
1040 *type = property->propType();
1041 writable = property->isWritable();
1042 resettable = property->isResettable();
1043 notifiesViaBindable = property->notifiesViaBindable();
1045 if (property->isVarProperty())
1046 propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
1048 propertyFlags->copyPropertyTypeFlags(property->flags());
1052 if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
1055 QQmlPropertyCache::ConstPtr typeCache
1056 = QQmlMetaType::propertyCacheForType(targetPropType);
1060 if (
const QV4::ResolvedTypeReference *typeRef
1061 = objectContainer->resolvedType(targetPropType)) {
1062 typeCache = typeRef->typePropertyCache();
1066 const QQmlPropertyData *typeProperty = typeCache
1067 ? typeCache->property(valueTypeIndex)
1069 if (typeProperty ==
nullptr) {
1070 return qQmlCompileError(
1071 alias.referenceLocation,
1072 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1074 populateWithPropertyData(typeProperty);
1077 populateWithPropertyData(targetProperty);
1079 if (valueTypeIndex != -1) {
1080 const QMetaObject *valueTypeMetaObject
1081 = QQmlMetaType::metaObjectForValueType(*type);
1082 const QMetaProperty valueTypeMetaProperty
1083 = valueTypeMetaObject->property(valueTypeIndex);
1084 *type = valueTypeMetaProperty.metaType();
1088 resettable = writable && valueTypeMetaProperty.isResettable();
1089 writable = writable && valueTypeMetaProperty.isWritable();
1092 propertyFlags->setIsDeepAlias(
true);
1097 propertyFlags->setIsWritable(
1098 writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
1099 propertyFlags->setIsResettable(resettable);
1100 propertyFlags->setIsBindable(notifiesViaBindable);
1104template <
typename ObjectContainer>
1106 const CompiledObject &component,
const QV4::CompiledData::Alias &alias,
int objectIndex,
1107 int aliasIndex,
int encodedMetaPropertyIndex)
1109 const CompiledObject &object = *objectContainer->objectAt(objectIndex);
1111 Q_ASSERT(object.aliasCount() > aliasIndex);
1113 QTypeRevision version = QTypeRevision::zero();
1114 QQmlPropertyData::Flags propertyFlags;
1115 QQmlError error = propertyDataForAlias(
1116 component, alias, &type, &version, &propertyFlags, encodedMetaPropertyIndex);
1117 if (error.isValid())
1120 const QString propertyName = objectContainer->stringAt(alias.nameIndex());
1122 const QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
1123 Q_ASSERT(propertyCache);
1125 const int effectiveSignalIndex
1126 = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
1127 const int effectivePropertyIndex
1128 = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
1130 if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
1131 propertyCache->_defaultPropertyName = propertyName;
1133 const auto overrideResult =
1134 propertyCache->appendAlias(propertyName, propertyFlags, effectivePropertyIndex, type,
1135 version, effectiveSignalIndex, encodedMetaPropertyIndex);
1136 if (overrideResult == QQmlPropertyCache::OverrideResult::InvalidOverride) {
1137 return qQmlCompileError(alias.location,
1139 QQmlPropertyCacheCreatorBase::tr(
"Cannot override FINAL property"));
QQmlError appendAliasToPropertyCache(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int objectIndex, int aliasIndex, int encodedMetaPropertyIndex)
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
ObjectContainer::CompiledObject CompiledObject
IncrementalResult buildMetaObjectsIncrementally()
typename ObjectContainer::CompiledObject CompiledObject
QString stringAt(int index) const
QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, QQmlTypeLoader *typeLoader, const ObjectContainer *objectContainer, const QQmlImports *imports, const QByteArray &typeClassName)
QQmlBindingInstantiationContext m_context
QQmlPendingGroupPropertyBindings * pendingGroupPropertyBindings
q23::expected< QQmlPropertyCache::Ptr, QQmlError > tryDeriveCacheFrom(const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache, QByteArray dynamicClassName=QByteArray()) const
~QQmlPropertyCacheCreator()
QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache)
QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType ¶m, QString *customTypeName=nullptr) const
typename std::remove_reference< decltype(*(std::declval< CompiledObject >().inlineComponentsBegin()))>::type InlineComponent
QQmlTypeLoader *const typeLoader
const ObjectContainer *const objectContainer
std::vector< icutils::Node >::reverse_iterator nodeIt
QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
q23::expected< QQmlPropertyData, QQmlError > tryCreateQQmlPropertyData(const QV4::CompiledData::Property &propertyIR, int coreIndex, int notifyIndex) const
QQmlError verifyNoICCycle()
const QQmlImports *const imports
std::vector< InlineComponent > allICs
QQmlPropertyCacheVector * propertyCaches
std::vector< icutils::Node > nodesSorted
QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher)
auto processUrlForClassName(const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler)
QQmlError qQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
int objectForId(const ObjectContainer *objectContainer, const CompiledObject &component, int id)
QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache)
int referencingObjectIndex
QQmlPropertyCache::ConstPtr referencingObjectPropertyCache
const QV4::CompiledData::Binding * instantiatingBinding
bool resolveInstantiatingProperty()
const QQmlPropertyData * instantiatingProperty
QQmlBindingInstantiationContext()
QQmlPropertyCache::ConstPtr instantiatingPropertyCache() const
QString instantiatingPropertyName
void resolveMissingPropertyCaches(QQmlPropertyCacheVector *propertyCaches) const
static bool canCreateClassNameTypeByUrl(const QUrl &url)
static QV4::CompiledData::CommonType propertyTypeForMetaType(QMetaType metaType)
static QByteArray createClassNameForInlineComponent(const QUrl &url)
static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type)
static QByteArray createClassNameTypeByUrl(const QUrl &url)
static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type)