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;
186 case OverrideSemantics::Status::MissingBase:
187 return tr(
"Nothing to override. Remove \"override\" keyword");
188 case OverrideSemantics::Status::OverridingFinal:
189 return tr(
"Cannot override FINAL property");
190 case OverrideSemantics::Status::OverridingNonVirtualError:
191 return tr(
"Cannot override non virtual property. Add \"virtual\" to the property of "
194 return tr(
"unknown");
199template <
typename ObjectContainer>
208 QQmlTypeLoader *typeLoader,
209 const ObjectContainer *objectContainer,
const QQmlImports *imports,
210 const QByteArray &typeClassName);
215
216
217
218
219
220
221
225
226
227
228
232
233
234
235
236
237
240 QByteArray dynamicClassName = QByteArray())
const;
243
244
245
246
247
248
249
250
251
254 int notifyIndex)
const;
266 QString *customTypeName =
nullptr)
const;
274 QTypeRevision revision = QTypeRevision::zero();
275 QV4::CompiledData::CommonType commonType = QV4::CompiledData::CommonType::Invalid;
278 [[nodiscard]] q23::expected<PropertyType, QQmlError>
279 tryResolvePropertyType(
const QV4::CompiledData::Property &propertyIR)
const;
282 [[nodiscard]]
static QQmlPropertyData::Flags
283 propertyDataFlags(
const QV4::CompiledData::Property &propertyIR,
284 const PropertyType &resolvedPropertyType);
302template <
typename ObjectContainer>
304 QQmlPropertyCacheVector *propertyCaches,
306 QQmlTypeLoader *typeLoader,
307 const ObjectContainer *objectContainer,
const QQmlImports *imports,
308 const QByteArray &typeClassName)
317 propertyCaches->resetAndResize(objectContainer->objectCount());
319 using namespace icutils;
323 for (
int i=0; i != objectContainer->objectCount(); ++i) {
325 for (
auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
326 allICs.push_back(*it);
331 std::vector<icutils::Node> nodes;
332 nodes.resize(allICs.size());
333 std::iota(nodes.begin(), nodes.end(), 0);
334 AdjacencyList adjacencyList;
335 adjacencyList.resize(nodes.size());
336 fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
338 nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
339 nodeIt = nodesSorted.rbegin();
342template <
typename ObjectContainer>
347 diag.setDescription(QLatin1String(
"Inline components form a cycle!"));
353template <
typename ObjectContainer>
361 if (nodeIt != nodesSorted.rend()) {
362 const auto &ic = allICs[nodeIt->index()];
363 QV4::ResolvedTypeReference *typeRef =
objectContainer->resolvedType(ic.nameIndex);
364 Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
365 Q_ASSERT(typeRef->typePropertyCache().isNull());
367 QByteArray icTypeName {
objectContainer->stringAt(ic.nameIndex).toUtf8() };
368 QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
369 QScopedValueRollback<
unsigned int> rootChange {
currentRoot, ic.objectIndex};
371 QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
372 if (diag.isValid()) {
373 return {diag,
false, 0};
375 typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
376 Q_ASSERT(!typeRef->typePropertyCache().isNull());
377 return { QQmlError(),
true,
int(ic.objectIndex) };
380 auto diag = buildMetaObjectRecursively(0, m_context, VMEMetaObjectIsRequired::Maybe);
381 return {diag,
false, 0};
384template <
typename ObjectContainer>
387 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &baseTypeCache,
388 QByteArray dynamicClassName)
const
390 QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
391 obj->propertyCount() + obj->aliasCount(),
392 obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
393 obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount());
394 cache->_dynamicClassName =
std::move(dynamicClassName);
396 int effectiveMethodIndex = cache->methodIndexCacheStart;
402 enum class AllowOverride { No, Yes };
403 QHash<QString, AllowOverride> seenSignals{
404 { QStringLiteral(
"destroyed"), AllowOverride::No },
405 { QStringLiteral(
"parentChanged"), AllowOverride::No },
406 { QStringLiteral(
"objectNameChanged"), AllowOverride::No }
408 const QQmlPropertyCache *parentCache = cache.data();
409 while ((parentCache = parentCache->parent().data())) {
410 if (
int pSigCount = parentCache->signalCount()) {
411 int pSigOffset = parentCache->signalOffset();
412 for (
int i = pSigOffset; i < pSigCount; ++i) {
413 const QQmlPropertyData *currPSig = parentCache->signal(i);
415 for (QQmlPropertyCache::StringCache::ConstIterator iter =
416 parentCache->stringCache.begin();
417 iter != parentCache->stringCache.end(); ++iter) {
418 if (currPSig == (*iter).second) {
419 if (currPSig->isOverridableSignal()) {
420 const qsizetype oldSize = seenSignals.size();
421 AllowOverride &entry = seenSignals[iter.key()];
422 if (seenSignals.size() != oldSize)
423 entry = AllowOverride::Yes;
425 seenSignals[iter.key()] = AllowOverride::No;
436 auto p = obj->propertiesBegin();
437 auto pend = obj->propertiesEnd();
438 for (; p != pend; ++p) {
439 auto flags = QQmlPropertyData::defaultSignalFlags();
441 const QString changedSigName =
442 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex()));
443 seenSignals[changedSigName] = AllowOverride::No;
445 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
448 auto a = obj->aliasesBegin();
449 auto aend = obj->aliasesEnd();
450 for (; a != aend; ++a) {
451 auto flags = QQmlPropertyData::defaultSignalFlags();
453 const QString changedSigName =
454 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
455 seenSignals[changedSigName] = AllowOverride::No;
457 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
460 auto e = obj->enumsBegin();
461 auto eend = obj->enumsEnd();
462 for (; e != eend; ++e) {
463 const int enumValueCount = e->enumValueCount();
464 QList<QQmlEnumValue> values;
465 values.reserve(enumValueCount);
467 auto enumValue = e->enumValuesBegin();
468 auto end = e->enumValuesEnd();
469 for (; enumValue != end; ++enumValue)
470 values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
472 cache->appendEnum(stringAt(e->nameIndex), values);
476 auto s = obj->signalsBegin();
477 auto send = obj->signalsEnd();
478 for (; s != send; ++s) {
479 const int paramCount = s->parameterCount();
481 QList<QByteArray> names;
482 names.reserve(paramCount);
483 QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
488 auto param = s->parametersBegin();
489 auto end = s->parametersEnd();
490 for (; param != end; ++param, ++i) {
491 names.append(stringAt(param->nameIndex).toUtf8());
493 QString customTypeName;
494 QMetaType type = metaTypeForParameter(param->type, &customTypeName);
496 return q23::make_unexpected(qQmlCompileError(
498 QQmlPropertyCacheCreatorBase::tr(
"Invalid signal parameter type: %1")
499 .arg(customTypeName)));
501 paramTypes[i] = type;
505 auto flags = QQmlPropertyData::defaultSignalFlags();
507 flags.setHasArguments(
true);
509 QString signalName = stringAt(s->nameIndex);
510 const auto it = seenSignals.find(signalName);
511 if (it == seenSignals.end()) {
512 seenSignals[signalName] = AllowOverride::No;
515 QQmlError message = qQmlCompileError(
517 QQmlPropertyCacheCreatorBase::tr(
518 "Duplicate signal name: "
519 "invalid override of property change signal or superclass signal"));
521 case AllowOverride::No:
522 return q23::make_unexpected(std::move(message));
523 case AllowOverride::Yes:
525 qCWarning(invalidOverride).noquote() << message.toString();
526 *it = AllowOverride::No;
530 cache->appendSignal(signalName, flags, effectiveMethodIndex++,
531 paramCount ? paramTypes.constData() :
nullptr, names);
537 for (; function != fend; ++function) {
538 auto flags = QQmlPropertyData::defaultSlotFlags();
540 const QString slotName = stringAt(function->nameIndex);
541 const auto it = seenSignals.constFind(slotName);
542 if (it != seenSignals.constEnd()) {
544 QQmlError message = qQmlCompileError(
546 QQmlPropertyCacheCreatorBase::tr(
547 "Duplicate method name: "
548 "invalid override of property change signal or superclass signal"));
550 case AllowOverride::No:
551 return q23::make_unexpected(std::move(message));
552 case AllowOverride::Yes:
554 qCWarning(invalidOverride).noquote() << message.toString();
561 QList<QByteArray> parameterNames;
562 QList<QMetaType> parameterTypes;
563 auto formal = function->formalsBegin();
564 auto end = function->formalsEnd();
565 for (; formal != end; ++formal) {
566 flags.setHasArguments(
true);
567 parameterNames << stringAt(formal->nameIndex).toUtf8();
568 QMetaType type = metaTypeForParameter(formal->type);
570 type = QMetaType::fromType<QVariant>();
571 parameterTypes << type;
574 QMetaType returnType = metaTypeForParameter(function->returnType);
575 if (!returnType.isValid())
576 returnType = QMetaType::fromType<QVariant>();
578 cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames,
583 int propertyIndex = cache->propertyIndexCacheStart;
584 int notifyIndex = cache->signalHandlerIndexCacheStart;
585 int objPropertyIdx = 0;
586 p = obj->propertiesBegin();
587 pend = obj->propertiesEnd();
588 for (; p != pend; ++p, ++objPropertyIdx, propertyIndex++, notifyIndex++) {
589 auto propertyDataOrError = tryCreateQQmlPropertyData(*p, propertyIndex, notifyIndex);
590 if (!propertyDataOrError.has_value()) {
591 return q23::make_unexpected(propertyDataOrError.error());
594 QString propertyName = stringAt(p->nameIndex());
595 if (!obj->hasAliasAsDefaultProperty()
596 && objPropertyIdx == obj->indexOfDefaultPropertyOrAlias)
597 cache->_defaultPropertyName = propertyName;
599 const auto &appendResult =
600 cache->appendPropertyAttr(propertyName,
std::move(propertyDataOrError).value());
602 return q23::make_unexpected(
603 qQmlCompileError(p->location, explain(appendResult.error())));
609template <
typename ObjectContainer>
612 const QV4::CompiledData::Property &propertyIR,
int coreIndex,
int notifyIndex)
const
614 const auto propertyTypeOrError = tryResolvePropertyType(propertyIR);
615 if (!propertyTypeOrError.has_value()) {
616 return q23::make_unexpected(propertyTypeOrError.error());
618 const auto propertyType = propertyTypeOrError.value();
620 QQmlPropertyData propertyData;
621 propertyData.setPropType(propertyType.metaType);
622 propertyData.setCoreIndex(coreIndex);
623 propertyData.setNotifyIndex(notifyIndex);
624 propertyData.setFlags(QQmlPropertyCacheCreator::propertyDataFlags(propertyIR, propertyType));
625 propertyData.setTypeVersion(propertyType.revision);
629template <
typename ObjectContainer>
632 auto isAddressable = [](
const QUrl &url) {
633 const QString fileName = url.fileName();
634 return !fileName.isEmpty() && fileName.front().isUpper();
639 || obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0
640 || obj->functionCount() != 0 || obj->enumCount() != 0
641 || obj->inlineComponentCount() != 0
642 || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
644 && !
objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
646 if (!needVMEMetaObject) {
647 auto binding = obj->bindingsBegin();
648 auto end = obj->bindingsEnd();
649 for ( ; binding != end; ++binding) {
650 if (binding->type() == QV4::CompiledData::Binding::Type_Object
651 && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
656 if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
657 if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
659 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
661 QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
662 QQmlError error = baseTypeCache
663 ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
664 : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
665 "Type cannot be used for 'on' assignment"));
671 needVMEMetaObject =
true;
678 QQmlPropertyCache::ConstPtr baseTypeCache;
681 baseTypeCache = propertyCacheForObject(obj, context, &error);
687 if (needVMEMetaObject) {
688 QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
692 propertyCaches->set(objectIndex, baseTypeCache);
696 QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
697 auto binding = obj->bindingsBegin();
698 auto end = obj->bindingsEnd();
699 for (; binding != end; ++binding) {
700 switch (binding->type()) {
701 case QV4::CompiledData::Binding::Type_Object:
702 case QV4::CompiledData::Binding::Type_GroupProperty:
703 case QV4::CompiledData::Binding::Type_AttachedProperty:
712 objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
721 QQmlError error = buildMetaObjectRecursively(
722 binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
731template <
typename ObjectContainer>
734 if (context.instantiatingProperty) {
735 return context.instantiatingPropertyCache();
736 }
else if (obj->inheritedTypeNameIndex != 0) {
737 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
740 if (typeRef->isFullyDynamicType()) {
741 if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
742 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new properties."));
745 if (obj->signalCount() > 0) {
746 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new signals."));
749 if (obj->functionCount() > 0) {
750 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully Dynamic types cannot declare new functions."));
755 if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
756 return propertyCache;
757 *error = qQmlCompileError(
759 QQmlPropertyCacheCreatorBase::tr(
"Type '%1' cannot declare new members.")
760 .arg(stringAt(obj->inheritedTypeNameIndex)));
762 }
else if (
const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
763 if (binding->isAttachedProperty()) {
765 binding->propertyNameIndex);
767 QQmlType qmltype = typeRef->type();
768 if (!qmltype.isValid()) {
769 imports->resolveType(
770 typeLoader, stringAt(binding->propertyNameIndex),
771 &qmltype,
nullptr,
nullptr);
774 const QMetaObject *attachedMo = qmltype.attachedPropertiesType(typeLoader);
776 *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
"Non-existent attached object"));
779 return QQmlMetaType::propertyCache(attachedMo);
785template <
typename ObjectContainer>
788 const QQmlPropertyCache::ConstPtr &baseTypeCache)
790 const auto dynamicClassName = [
this](
int objectIndex,
const auto &baseTypeCache) -> QByteArray {
791 const auto isComponentRoot = objectIndex == 0
792 || objectIndex ==
int(currentRoot) ;
793 if (isComponentRoot && !typeClassName.isEmpty()) {
794 return typeClassName;
796 return QByteArray(QQmlMetaObject(baseTypeCache).className())
798 .append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
801 const auto cacheOrError =
802 tryDeriveCacheFrom(obj, baseTypeCache, dynamicClassName(objectIndex, baseTypeCache));
803 if (!cacheOrError.has_value()) {
804 return cacheOrError.error();
806 auto &cache = cacheOrError.value();
808 using ListPropertyAssignBehavior =
typename ObjectContainer::ListPropertyAssignBehavior;
810 case ListPropertyAssignBehavior::ReplaceIfNotDefault:
811 cache->_listPropertyAssignBehavior =
"ReplaceIfNotDefault";
813 case ListPropertyAssignBehavior::Replace:
814 cache->_listPropertyAssignBehavior =
"Replace";
816 case ListPropertyAssignBehavior::Append:
820 propertyCaches->setOwn(objectIndex, cache);
821 propertyCaches->setNeedsVMEMetaObject(objectIndex);
825template <
typename ObjectContainer>
827 const QV4::CompiledData::ParameterType ¶m, QString *customTypeName)
const
829 const quint32 typeId = param.typeNameIndexOrCommonType();
830 if (param.indexIsCommonType()) {
833 return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
834 return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
838 const QString typeName = stringAt(param.typeNameIndexOrCommonType());
840 *customTypeName = typeName;
842 bool selfReference =
false;
843 if (!imports->resolveType(
844 typeLoader, typeName, &qmltype,
nullptr,
nullptr,
nullptr,
845 QQmlType::AnyRegistrationType, &selfReference))
848 if (!qmltype.isComposite()) {
849 const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
850 if (!typeId.isValid() && qmltype.isInlineComponentType()) {
851 const QQmlType qmlType =
objectContainer->qmlTypeForComponent(qmltype.elementName());
852 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
860 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
863 return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
866template <
typename ObjectContainer>
868 const QV4::CompiledData::Property &propertyIR)
const
869 -> q23::expected<PropertyType, QQmlError>
871 using namespace Qt::StringLiterals;
872 PropertyType propertyType;
873 propertyType.commonType = propertyIR.commonType();
875 if (propertyType.commonType != QV4::CompiledData::CommonType::Invalid) {
877 propertyType.metaType = propertyIR.isList()
878 ? listTypeForPropertyType(propertyType.commonType)
879 : metaTypeForPropertyType(propertyType.commonType);
886 Q_ASSERT(!propertyIR.isCommonType());
888 bool selfReference =
false;
889 QList<QQmlError> errors;
890 const QString typeName = stringAt(propertyIR.commonTypeOrTypeNameIndex());
891 if (!imports->resolveType(typeLoader, typeName, &qmltype,
nullptr,
nullptr, &errors,
892 QQmlType::AnyRegistrationType, &selfReference)) {
893 Q_ASSERT(!errors.isEmpty());
895 if (typeName ==
"list"_L1 && errors[0].description() ==
"is not a type"_L1) {
896 errors[0].setDescription(errors[0].description().append(
897 ". It requires an element type argument (eg. list<int>)"_L1));
900 return q23::make_unexpected(
901 qQmlCompileError(propertyIR.location, typeName + u' ' + errors[0].description()));
904 Q_ASSERT(qmltype.isValid());
906 propertyType.metaType = propertyIR.isList() ? qmltype.qListTypeId() : qmltype.typeId();
908 if (!qmltype.isComposite() && !qmltype.isInlineComponentType())
909 propertyType.revision = qmltype.version();
914template <
typename ObjectContainer>
916 const QV4::CompiledData::Property &propertyIR,
const PropertyType &resolvedPropertyType)
918 QQmlPropertyData::Flags flags;
921 if (propertyIR.isList()) {
922 flags.setType(QQmlPropertyData::Flags::QListType);
923 }
else if (resolvedPropertyType.commonType == QV4::CompiledData::CommonType::Var) {
924 flags.setType(QQmlPropertyData::Flags::VarPropertyType);
925 }
else if (resolvedPropertyType.metaType.flags().testFlag(QMetaType::PointerToQObject)) {
926 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
930 if (!propertyIR.isReadOnly()
931 && !resolvedPropertyType.metaType.flags().testFlag(QMetaType::IsQmlList))
932 flags.setIsWritable(
true);
933 if (propertyIR.isFinal())
934 flags.setIsFinal(
true);
935 if (propertyIR.isVirtual())
936 flags.setIsVirtual(
true);
937 if (propertyIR.isOverride())
938 flags.setDoesOverride(
true);
943template <
typename ObjectContainer,
typename CompiledObject>
944int objectForId(
const ObjectContainer *objectContainer,
const CompiledObject &component,
int id)
946 for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
947 const int candidateIndex = component.namedObjectsInComponentTable()[i];
948 const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
949 if (candidate.objectId() == id)
950 return candidateIndex;
955template <
typename ObjectContainer>
962 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer);
964 const CompiledObject &component,
const QV4::CompiledData::Alias &alias,
int objectIndex,
965 int aliasIndex,
int encodedMetaPropertyIndex);
968 QQmlError propertyDataForAlias(
969 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
970 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
971 int targetPropertyIndex);
973 QQmlPropertyCacheVector *propertyCaches;
974 const ObjectContainer *objectContainer;
977template <
typename ObjectContainer>
979 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer)
981 , objectContainer(objectContainer)
985template <
typename ObjectContainer>
987 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
988 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
int targetPropertyIndex)
991 bool writable =
false;
992 bool resettable =
false;
993 bool notifiesViaBindable =
false;
995 propertyFlags->setIsAlias(
true);
997 if (alias.isAliasToLocalAlias()) {
998 const QV4::CompiledData::Alias *lastAlias = &alias;
999 QVarLengthArray<
const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
1002 const int targetObjectIndex = objectForId(
1003 objectContainer, component, lastAlias->targetObjectId());
1004 Q_ASSERT(targetObjectIndex >= 0);
1005 const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
1006 Q_ASSERT(targetObject);
1008 auto nextAlias = targetObject->aliasesBegin();
1009 for (uint i = 0; i < lastAlias->localAliasIndex; ++i)
1012 const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
1013 if (seenAliases.contains(targetAlias)) {
1014 return qQmlCompileError(targetAlias->location,
1015 QQmlPropertyCacheCreatorBase::tr(
"Cyclic alias"));
1018 seenAliases.append(targetAlias);
1019 lastAlias = targetAlias;
1020 }
while (lastAlias->isAliasToLocalAlias());
1022 return propertyDataForAlias(
1023 component, *lastAlias, type, version, propertyFlags, targetPropertyIndex);
1026 const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId());
1027 Q_ASSERT(targetObjectIndex >= 0);
1028 const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
1030 if (targetPropertyIndex == -1) {
1031 Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
1032 auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
1037 return qQmlCompileError(targetObject.location,
1038 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1041 const auto referencedType = typeRef->type();
1042 Q_ASSERT(referencedType.isValid());
1043 *type = referencedType.typeId();
1044 if (!type->isValid() && referencedType.isInlineComponentType()) {
1045 *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
1046 Q_ASSERT(type->isValid());
1049 *version = typeRef->version();
1051 propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
1053 int coreIndex = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).coreIndex();
1055 = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).valueTypeIndex();
1057 QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
1058 Q_ASSERT(targetCache);
1060 const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
1061 Q_ASSERT(targetProperty);
1063 const QMetaType targetPropType = targetProperty->propType();
1065 const auto populateWithPropertyData = [&](
const QQmlPropertyData *property) {
1066 *type = property->propType();
1067 writable = property->isWritable();
1068 resettable = property->isResettable();
1069 notifiesViaBindable = property->notifiesViaBindable();
1071 if (property->isVarProperty())
1072 propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
1074 propertyFlags->copyPropertyTypeFlags(property->flags());
1078 if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
1081 QQmlPropertyCache::ConstPtr typeCache
1082 = QQmlMetaType::propertyCacheForType(targetPropType);
1086 if (
const QV4::ResolvedTypeReference *typeRef
1087 = objectContainer->resolvedType(targetPropType)) {
1088 typeCache = typeRef->typePropertyCache();
1092 const QQmlPropertyData *typeProperty = typeCache
1093 ? typeCache->property(valueTypeIndex)
1095 if (typeProperty ==
nullptr) {
1096 return qQmlCompileError(
1097 alias.referenceLocation,
1098 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1100 populateWithPropertyData(typeProperty);
1103 populateWithPropertyData(targetProperty);
1105 if (valueTypeIndex != -1) {
1106 const QMetaObject *valueTypeMetaObject
1107 = QQmlMetaType::metaObjectForValueType(*type);
1108 const QMetaProperty valueTypeMetaProperty
1109 = valueTypeMetaObject->property(valueTypeIndex);
1110 *type = valueTypeMetaProperty.metaType();
1114 resettable = writable && valueTypeMetaProperty.isResettable();
1115 writable = writable && valueTypeMetaProperty.isWritable();
1118 propertyFlags->setIsDeepAlias(
true);
1123 propertyFlags->setIsWritable(
1124 writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
1125 propertyFlags->setIsResettable(resettable);
1126 propertyFlags->setIsBindable(notifiesViaBindable);
1130template <
typename ObjectContainer>
1132 const CompiledObject &component,
const QV4::CompiledData::Alias &alias,
int objectIndex,
1133 int aliasIndex,
int encodedMetaPropertyIndex)
1135 const CompiledObject &object = *objectContainer->objectAt(objectIndex);
1137 Q_ASSERT(object.aliasCount() > aliasIndex);
1139 QTypeRevision version = QTypeRevision::zero();
1140 QQmlPropertyData::Flags propertyFlags;
1141 QQmlError error = propertyDataForAlias(
1142 component, alias, &type, &version, &propertyFlags, encodedMetaPropertyIndex);
1143 if (error.isValid())
1146 const QString propertyName = objectContainer->stringAt(alias.nameIndex());
1148 const QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
1149 Q_ASSERT(propertyCache);
1151 const int effectiveSignalIndex
1152 = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
1153 const int effectivePropertyIndex
1154 = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
1156 if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
1157 propertyCache->_defaultPropertyName = propertyName;
1159 const auto &appendResult =
1160 propertyCache->appendAlias(propertyName, propertyFlags, effectivePropertyIndex, type,
1161 version, effectiveSignalIndex, encodedMetaPropertyIndex);
1162 if (!appendResult) {
1163 return qQmlCompileError(alias.location,
1164 QQmlPropertyCacheCreatorBase::explain(appendResult.error()));
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
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQIORing)
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 QString explain(OverrideSemantics::Status reason)
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)