5#ifndef QQMLPROPERTYCACHECREATOR_P_H
6#define QQMLPROPERTYCACHECREATOR_P_H
19#include <private/qqmlvaluetype_p.h>
20#include <private/qqmlengine_p.h>
21#include <private/qqmlmetaobject_p.h>
22#include <private/qqmltypedata_p.h>
23#include <private/inlinecomponentutils_p.h>
24#include <private/qqmlsourcecoordinate_p.h>
25#include <private/qqmlsignalnames_p.h>
26#include <private/qexpected_p.h>
28#include <QtCore/qloggingcategory.h>
29#include <QtCore/qscopedvaluerollback.h>
30#include <QtCore/qtyperevision.h>
32#if QT_CONFIG(regularexpression)
33#include <QtCore/qregularexpression.h>
43 const QString &description)
46 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
47 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
48 error.setDescription(description);
55 int referencingObjectIndex,
const QV4::CompiledData::Binding *instantiatingBinding,
56 const QString &instantiatingPropertyName,
57 const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache);
72 QQmlPropertyCacheVector *propertyCaches)
const;
84 case QV4::CompiledData::CommonType::Void:
return QMetaType();
85 case QV4::CompiledData::CommonType::Var:
return QMetaType::fromType<QVariant>();
86 case QV4::CompiledData::CommonType::Int:
return QMetaType::fromType<
int>();
87 case QV4::CompiledData::CommonType::Bool:
return QMetaType::fromType<
bool>();
88 case QV4::CompiledData::CommonType::Real:
return QMetaType::fromType<qreal>();
89 case QV4::CompiledData::CommonType::String:
return QMetaType::fromType<QString>();
90 case QV4::CompiledData::CommonType::Url:
return QMetaType::fromType<QUrl>();
91 case QV4::CompiledData::CommonType::Time:
return QMetaType::fromType<QTime>();
92 case QV4::CompiledData::CommonType::Date:
return QMetaType::fromType<QDate>();
93 case QV4::CompiledData::CommonType::DateTime:
return QMetaType::fromType<QDateTime>();
94#if QT_CONFIG(regularexpression)
95 case QV4::CompiledData::CommonType::RegExp:
return QMetaType::fromType<QRegularExpression>();
97 case QV4::CompiledData::CommonType::RegExp:
return QMetaType();
99 case QV4::CompiledData::CommonType::Rect:
return QMetaType::fromType<QRectF>();
100 case QV4::CompiledData::CommonType::Point:
return QMetaType::fromType<QPointF>();
101 case QV4::CompiledData::CommonType::Size:
return QMetaType::fromType<QSizeF>();
102 case QV4::CompiledData::CommonType::Invalid:
break;
110 case QV4::CompiledData::CommonType::Void:
return QMetaType();
111 case QV4::CompiledData::CommonType::Var:
return QMetaType::fromType<QList<QVariant>>();
112 case QV4::CompiledData::CommonType::Int:
return QMetaType::fromType<QList<
int>>();
113 case QV4::CompiledData::CommonType::Bool:
return QMetaType::fromType<QList<
bool>>();
114 case QV4::CompiledData::CommonType::Real:
return QMetaType::fromType<QList<qreal>>();
115 case QV4::CompiledData::CommonType::String:
return QMetaType::fromType<QList<QString>>();
116 case QV4::CompiledData::CommonType::Url:
return QMetaType::fromType<QList<QUrl>>();
117 case QV4::CompiledData::CommonType::Time:
return QMetaType::fromType<QList<QTime>>();
118 case QV4::CompiledData::CommonType::Date:
return QMetaType::fromType<QList<QDate>>();
119 case QV4::CompiledData::CommonType::DateTime:
return QMetaType::fromType<QList<QDateTime>>();
120#if QT_CONFIG(regularexpression)
121 case QV4::CompiledData::CommonType::RegExp:
return QMetaType::fromType<QList<QRegularExpression>>();
123 case QV4::CompiledData::CommonType::RegExp:
return QMetaType();
125 case QV4::CompiledData::CommonType::Rect:
return QMetaType::fromType<QList<QRectF>>();
126 case QV4::CompiledData::CommonType::Point:
return QMetaType::fromType<QList<QPointF>>();
127 case QV4::CompiledData::CommonType::Size:
return QMetaType::fromType<QList<QSizeF>>();
128 case QV4::CompiledData::CommonType::Invalid:
break;
134 if (!metaType.isValid())
135 return QV4::CompiledData::CommonType::Void;
137 switch (metaType.id()) {
138 case QMetaType::QVariant:
139 return QV4::CompiledData::CommonType::Var;
141 return QV4::CompiledData::CommonType::Int;
142 case QMetaType::Bool:
143 return QV4::CompiledData::CommonType::Bool;
144 case QMetaType::QReal:
145 return QV4::CompiledData::CommonType::Real;
146 case QMetaType::QString:
147 return QV4::CompiledData::CommonType::String;
148 case QMetaType::QUrl:
149 return QV4::CompiledData::CommonType::Url;
150 case QMetaType::QTime:
151 return QV4::CompiledData::CommonType::Time;
152 case QMetaType::QDate:
153 return QV4::CompiledData::CommonType::Date;
154 case QMetaType::QDateTime:
155 return QV4::CompiledData::CommonType::DateTime;
156#if QT_CONFIG(regularexpression)
157 case QMetaType::QRegularExpression:
158 return QV4::CompiledData::CommonType::RegExp;
160 case QMetaType::QRectF:
161 return QV4::CompiledData::CommonType::Rect;
162 case QMetaType::QPointF:
163 return QV4::CompiledData::CommonType::Point;
164 case QMetaType::QSizeF:
165 return QV4::CompiledData::CommonType::Size;
169 return QV4::CompiledData::CommonType::Invalid;
189 case OverrideSemantics::Status::MissingBase:
190 return tr(
"Nothing to override. Remove \"override\" keyword");
191 case OverrideSemantics::Status::OverridingFinal:
192 return tr(
"Cannot override FINAL property");
193 case OverrideSemantics::Status::OverridingNonVirtualError:
194 return tr(
"Cannot override non virtual property. Add \"virtual\" to the property of "
197 return tr(
"unknown");
202template <
typename ObjectContainer>
211 QQmlTypeLoader *typeLoader,
212 const ObjectContainer *objectContainer,
const QQmlImports *imports,
213 const QByteArray &typeClassName);
218
219
220
221
222
223
224
228
229
230
231
235
236
237
238
239
240
243 QByteArray dynamicClassName = QByteArray())
const;
246
247
248
249
250
251
252
253
254
257 int notifyIndex)
const;
269 QString *customTypeName =
nullptr)
const;
277 QTypeRevision revision = QTypeRevision::zero();
278 QV4::CompiledData::CommonType commonType = QV4::CompiledData::CommonType::Invalid;
281 [[nodiscard]] q23::expected<PropertyType, QQmlError>
282 tryResolvePropertyType(
const QV4::CompiledData::Property &propertyIR)
const;
285 [[nodiscard]]
static QQmlPropertyData::Flags
286 propertyDataFlags(
const QV4::CompiledData::Property &propertyIR,
287 const PropertyType &resolvedPropertyType);
305template <
typename ObjectContainer>
307 QQmlPropertyCacheVector *propertyCaches,
309 QQmlTypeLoader *typeLoader,
310 const ObjectContainer *objectContainer,
const QQmlImports *imports,
311 const QByteArray &typeClassName)
320 propertyCaches->resetAndResize(objectContainer->objectCount());
322 using namespace icutils;
326 for (
int i=0; i != objectContainer->objectCount(); ++i) {
328 for (
auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
329 allICs.push_back(*it);
334 std::vector<icutils::Node> nodes;
335 nodes.resize(allICs.size());
336 std::iota(nodes.begin(), nodes.end(), 0);
337 AdjacencyList adjacencyList;
338 adjacencyList.resize(nodes.size());
339 fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
341 nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
342 nodeIt = nodesSorted.rbegin();
345template <
typename ObjectContainer>
350 diag.setDescription(QLatin1String(
"Inline components form a cycle!"));
356template <
typename ObjectContainer>
364 if (nodeIt != nodesSorted.rend()) {
365 const auto &ic = allICs[nodeIt->index()];
366 QV4::ResolvedTypeReference *typeRef =
objectContainer->resolvedType(ic.nameIndex);
367 Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
368 Q_ASSERT(typeRef->typePropertyCache().isNull());
370 QByteArray icTypeName {
objectContainer->stringAt(ic.nameIndex).toUtf8() };
371 QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
372 QScopedValueRollback<
unsigned int> rootChange {
currentRoot, ic.objectIndex};
374 QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
375 if (diag.isValid()) {
376 return {diag,
false, 0};
378 typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
379 Q_ASSERT(!typeRef->typePropertyCache().isNull());
380 return { QQmlError(),
true,
int(ic.objectIndex) };
383 auto diag = buildMetaObjectRecursively(0, m_context, VMEMetaObjectIsRequired::Maybe);
384 return {diag,
false, 0};
387template <
typename ObjectContainer>
390 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &baseTypeCache,
391 QByteArray dynamicClassName)
const
393 QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
394 obj->propertyCount() + obj->aliasCount(),
395 obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
396 obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount());
397 cache->_dynamicClassName =
std::move(dynamicClassName);
399 int effectiveMethodIndex = cache->methodIndexCacheStart;
405 enum class AllowOverride { No, Yes };
406 QHash<QString, AllowOverride> seenSignals{
407 { QStringLiteral(
"destroyed"), AllowOverride::No },
408 { QStringLiteral(
"parentChanged"), AllowOverride::No },
409 { QStringLiteral(
"objectNameChanged"), AllowOverride::No }
411 const QQmlPropertyCache *parentCache = cache.data();
412 while ((parentCache = parentCache->parent().data())) {
413 if (
int pSigCount = parentCache->signalCount()) {
414 int pSigOffset = parentCache->signalOffset();
415 for (
int i = pSigOffset; i < pSigCount; ++i) {
416 const QQmlPropertyData *currPSig = parentCache->signal(i);
418 for (QQmlPropertyCache::StringCache::ConstIterator iter =
419 parentCache->stringCache.begin();
420 iter != parentCache->stringCache.end(); ++iter) {
421 if (currPSig == (*iter).second) {
422 if (currPSig->isOverridableSignal()) {
423 const qsizetype oldSize = seenSignals.size();
424 AllowOverride &entry = seenSignals[iter.key()];
425 if (seenSignals.size() != oldSize)
426 entry = AllowOverride::Yes;
428 seenSignals[iter.key()] = AllowOverride::No;
439 auto p = obj->propertiesBegin();
440 auto pend = obj->propertiesEnd();
441 for (; p != pend; ++p) {
442 auto flags = QQmlPropertyData::defaultSignalFlags();
444 const QString changedSigName =
445 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex()));
446 seenSignals[changedSigName] = AllowOverride::No;
448 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
451 auto a = obj->aliasesBegin();
452 auto aend = obj->aliasesEnd();
453 for (; a != aend; ++a) {
454 auto flags = QQmlPropertyData::defaultSignalFlags();
456 const QString changedSigName =
457 QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
458 seenSignals[changedSigName] = AllowOverride::No;
460 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
463 auto e = obj->enumsBegin();
464 auto eend = obj->enumsEnd();
465 for (; e != eend; ++e) {
466 const int enumValueCount = e->enumValueCount();
467 QList<QQmlEnumValue> values;
468 values.reserve(enumValueCount);
470 auto enumValue = e->enumValuesBegin();
471 auto end = e->enumValuesEnd();
472 for (; enumValue != end; ++enumValue)
473 values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
475 cache->appendEnum(stringAt(e->nameIndex), values);
479 auto s = obj->signalsBegin();
480 auto send = obj->signalsEnd();
481 for (; s != send; ++s) {
482 const int paramCount = s->parameterCount();
484 QList<QByteArray> names;
485 names.reserve(paramCount);
486 QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
491 auto param = s->parametersBegin();
492 auto end = s->parametersEnd();
493 for (; param != end; ++param, ++i) {
494 names.append(stringAt(param->nameIndex).toUtf8());
496 QString customTypeName;
497 QMetaType type = metaTypeForParameter(param->type, &customTypeName);
499 return q23::make_unexpected(qQmlCompileError(
501 QQmlPropertyCacheCreatorBase::tr(
"Invalid signal parameter type: %1")
502 .arg(customTypeName)));
504 paramTypes[i] = type;
508 auto flags = QQmlPropertyData::defaultSignalFlags();
510 flags.setHasArguments(
true);
512 QString signalName = stringAt(s->nameIndex);
513 const auto it = seenSignals.find(signalName);
514 if (it == seenSignals.end()) {
515 seenSignals[signalName] = AllowOverride::No;
518 QQmlError message = qQmlCompileError(
520 QQmlPropertyCacheCreatorBase::tr(
521 "Duplicate signal name: "
522 "invalid override of property change signal or superclass signal"));
524 case AllowOverride::No:
525 return q23::make_unexpected(std::move(message));
526 case AllowOverride::Yes:
528 qCWarning(invalidOverride).noquote() << message.toString();
529 *it = AllowOverride::No;
533 cache->appendSignal(signalName, flags, effectiveMethodIndex++,
534 paramCount ? paramTypes.constData() :
nullptr, names);
540 for (; function != fend; ++function) {
541 auto flags = QQmlPropertyData::defaultSlotFlags();
543 const QString slotName = stringAt(function->nameIndex);
544 const auto it = seenSignals.constFind(slotName);
545 if (it != seenSignals.constEnd()) {
547 QQmlError message = qQmlCompileError(
549 QQmlPropertyCacheCreatorBase::tr(
550 "Duplicate method name: "
551 "invalid override of property change signal or superclass signal"));
553 case AllowOverride::No:
554 return q23::make_unexpected(std::move(message));
555 case AllowOverride::Yes:
557 qCWarning(invalidOverride).noquote() << message.toString();
564 QList<QByteArray> parameterNames;
565 QList<QMetaType> parameterTypes;
566 auto formal = function->formalsBegin();
567 auto end = function->formalsEnd();
568 for (; formal != end; ++formal) {
569 flags.setHasArguments(
true);
570 parameterNames << stringAt(formal->nameIndex).toUtf8();
571 QMetaType type = metaTypeForParameter(formal->type);
573 type = QMetaType::fromType<QVariant>();
574 parameterTypes << type;
577 QMetaType returnType = metaTypeForParameter(function->returnType);
578 if (!returnType.isValid())
579 returnType = QMetaType::fromType<QVariant>();
581 cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames,
586 int propertyIndex = cache->propertyIndexCacheStart;
587 int notifyIndex = cache->signalHandlerIndexCacheStart;
588 int objPropertyIdx = 0;
589 p = obj->propertiesBegin();
590 pend = obj->propertiesEnd();
591 for (; p != pend; ++p, ++objPropertyIdx, propertyIndex++, notifyIndex++) {
592 auto propertyDataOrError = tryCreateQQmlPropertyData(*p, propertyIndex, notifyIndex);
593 if (!propertyDataOrError.has_value()) {
594 return q23::make_unexpected(propertyDataOrError.error());
597 QString propertyName = stringAt(p->nameIndex());
598 if (!obj->hasAliasAsDefaultProperty()
599 && objPropertyIdx == obj->indexOfDefaultPropertyOrAlias)
600 cache->_defaultPropertyName = propertyName;
602 const auto &appendResult =
603 cache->appendPropertyAttr(propertyName,
std::move(propertyDataOrError).value());
605 return q23::make_unexpected(
606 qQmlCompileError(p->location, explain(appendResult.error())));
612template <
typename ObjectContainer>
615 const QV4::CompiledData::Property &propertyIR,
int coreIndex,
int notifyIndex)
const
617 const auto propertyTypeOrError = tryResolvePropertyType(propertyIR);
618 if (!propertyTypeOrError.has_value()) {
619 return q23::make_unexpected(propertyTypeOrError.error());
621 const auto propertyType = propertyTypeOrError.value();
623 QQmlPropertyData propertyData;
624 propertyData.setPropType(propertyType.metaType);
625 propertyData.setCoreIndex(coreIndex);
626 propertyData.setNotifyIndex(notifyIndex);
627 propertyData.setFlags(QQmlPropertyCacheCreator::propertyDataFlags(propertyIR, propertyType));
628 propertyData.setTypeVersion(propertyType.revision);
632template <
typename ObjectContainer>
635 auto isAddressable = [](
const QUrl &url) {
636 const QString fileName = url.fileName();
637 return !fileName.isEmpty() && fileName.front().isUpper();
642 || obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0
643 || obj->functionCount() != 0 || obj->enumCount() != 0
644 || obj->inlineComponentCount() != 0
645 || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
647 && !
objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
649 if (!needVMEMetaObject) {
650 auto binding = obj->bindingsBegin();
651 auto end = obj->bindingsEnd();
652 for ( ; binding != end; ++binding) {
653 if (binding->type() == QV4::CompiledData::Binding::Type_Object
654 && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
659 if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
660 if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
662 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
664 QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
665 QQmlError error = baseTypeCache
666 ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
667 : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
668 "Type cannot be used for 'on' assignment"));
674 needVMEMetaObject =
true;
681 QQmlPropertyCache::ConstPtr baseTypeCache;
684 baseTypeCache = propertyCacheForObject(obj, context, &error);
690 if (needVMEMetaObject) {
691 QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
695 propertyCaches->set(objectIndex, baseTypeCache);
699 QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
700 auto binding = obj->bindingsBegin();
701 auto end = obj->bindingsEnd();
702 for (; binding != end; ++binding) {
703 switch (binding->type()) {
704 case QV4::CompiledData::Binding::Type_Object:
705 case QV4::CompiledData::Binding::Type_GroupProperty:
706 case QV4::CompiledData::Binding::Type_AttachedProperty:
715 objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
724 QQmlError error = buildMetaObjectRecursively(
725 binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
734template <
typename ObjectContainer>
737 if (context.instantiatingProperty) {
738 return context.instantiatingPropertyCache();
739 }
else if (obj->inheritedTypeNameIndex != 0) {
740 auto *typeRef =
objectContainer->resolvedType(obj->inheritedTypeNameIndex);
743 if (typeRef->isFullyDynamicType()) {
744 if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
745 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new properties."));
748 if (obj->signalCount() > 0) {
749 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully dynamic types cannot declare new signals."));
752 if (obj->functionCount() > 0) {
753 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr(
"Fully Dynamic types cannot declare new functions."));
758 if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
759 return propertyCache;
760 *error = qQmlCompileError(
762 QQmlPropertyCacheCreatorBase::tr(
"Type '%1' cannot declare new members.")
763 .arg(stringAt(obj->inheritedTypeNameIndex)));
765 }
else if (
const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
766 if (binding->isAttachedProperty()) {
768 binding->propertyNameIndex);
770 QQmlType qmltype = typeRef->type();
771 if (!qmltype.isValid()) {
772 imports->resolveType(
773 typeLoader, stringAt(binding->propertyNameIndex),
774 &qmltype,
nullptr,
nullptr);
777 const QMetaObject *attachedMo = qmltype.attachedPropertiesType(typeLoader);
779 *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
"Non-existent attached object"));
782 return QQmlMetaType::propertyCache(attachedMo);
788template <
typename ObjectContainer>
791 const QQmlPropertyCache::ConstPtr &baseTypeCache)
793 const auto dynamicClassName = [
this](
int objectIndex,
const auto &baseTypeCache) -> QByteArray {
794 const auto isComponentRoot = objectIndex == 0
795 || objectIndex ==
int(currentRoot) ;
796 if (isComponentRoot && !typeClassName.isEmpty()) {
797 return typeClassName;
799 return QByteArray(QQmlMetaObject(baseTypeCache).className())
801 .append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
804 const auto cacheOrError =
805 tryDeriveCacheFrom(obj, baseTypeCache, dynamicClassName(objectIndex, baseTypeCache));
806 if (!cacheOrError.has_value()) {
807 return cacheOrError.error();
809 auto &cache = cacheOrError.value();
811 using ListPropertyAssignBehavior =
typename ObjectContainer::ListPropertyAssignBehavior;
813 case ListPropertyAssignBehavior::ReplaceIfNotDefault:
814 cache->_listPropertyAssignBehavior =
"ReplaceIfNotDefault";
816 case ListPropertyAssignBehavior::Replace:
817 cache->_listPropertyAssignBehavior =
"Replace";
819 case ListPropertyAssignBehavior::Append:
823 propertyCaches->setOwn(objectIndex, cache);
824 propertyCaches->setNeedsVMEMetaObject(objectIndex);
828template <
typename ObjectContainer>
830 const QV4::CompiledData::ParameterType ¶m, QString *customTypeName)
const
832 const quint32 typeId = param.typeNameIndexOrCommonType();
833 if (param.indexIsCommonType()) {
836 return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
837 return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
841 const QString typeName = stringAt(param.typeNameIndexOrCommonType());
843 *customTypeName = typeName;
845 bool selfReference =
false;
846 if (!imports->resolveType(
847 typeLoader, typeName, &qmltype,
nullptr,
nullptr,
nullptr,
848 QQmlType::AnyRegistrationType, &selfReference))
851 if (!qmltype.isComposite()) {
852 const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
853 if (!typeId.isValid() && qmltype.isInlineComponentType()) {
854 const QQmlType qmlType =
objectContainer->qmlTypeForComponent(qmltype.elementName());
855 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
863 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
866 return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
869template <
typename ObjectContainer>
871 const QV4::CompiledData::Property &propertyIR)
const
872 -> q23::expected<PropertyType, QQmlError>
874 using namespace Qt::StringLiterals;
875 PropertyType propertyType;
876 propertyType.commonType = propertyIR.commonType();
878 if (propertyType.commonType != QV4::CompiledData::CommonType::Invalid) {
880 propertyType.metaType = propertyIR.isList()
881 ? listTypeForPropertyType(propertyType.commonType)
882 : metaTypeForPropertyType(propertyType.commonType);
889 Q_ASSERT(!propertyIR.isCommonType());
891 bool selfReference =
false;
892 QList<QQmlError> errors;
893 const QString typeName = stringAt(propertyIR.commonTypeOrTypeNameIndex());
894 if (!imports->resolveType(typeLoader, typeName, &qmltype,
nullptr,
nullptr, &errors,
895 QQmlType::AnyRegistrationType, &selfReference)) {
896 Q_ASSERT(!errors.isEmpty());
898 if (typeName ==
"list"_L1 && errors[0].description() ==
"is not a type"_L1) {
899 errors[0].setDescription(errors[0].description().append(
900 ". It requires an element type argument (eg. list<int>)"_L1));
903 return q23::make_unexpected(
904 qQmlCompileError(propertyIR.location, typeName + u' ' + errors[0].description()));
907 Q_ASSERT(qmltype.isValid());
909 propertyType.metaType = propertyIR.isList() ? qmltype.qListTypeId() : qmltype.typeId();
911 if (!qmltype.isComposite() && !qmltype.isInlineComponentType())
912 propertyType.revision = qmltype.version();
917template <
typename ObjectContainer>
919 const QV4::CompiledData::Property &propertyIR,
const PropertyType &resolvedPropertyType)
921 QQmlPropertyData::Flags flags;
924 if (propertyIR.isList()) {
925 flags.setType(QQmlPropertyData::Flags::QListType);
926 }
else if (resolvedPropertyType.commonType == QV4::CompiledData::CommonType::Var) {
927 flags.setType(QQmlPropertyData::Flags::VarPropertyType);
928 }
else if (resolvedPropertyType.metaType.flags().testFlag(QMetaType::PointerToQObject)) {
929 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
933 if (!propertyIR.isReadOnly()
934 && !resolvedPropertyType.metaType.flags().testFlag(QMetaType::IsQmlList))
935 flags.setIsWritable(
true);
936 if (propertyIR.isFinal())
937 flags.setIsFinal(
true);
938 if (propertyIR.isVirtual())
939 flags.setIsVirtual(
true);
940 if (propertyIR.isOverride())
941 flags.setDoesOverride(
true);
946template <
typename ObjectContainer,
typename CompiledObject>
947int objectForId(
const ObjectContainer *objectContainer,
const CompiledObject &component,
int id)
949 for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
950 const int candidateIndex = component.namedObjectsInComponentTable()[i];
951 const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
952 if (candidate.objectId() == id)
953 return candidateIndex;
958template <
typename ObjectContainer>
965 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer);
967 const CompiledObject &component,
const QV4::CompiledData::Alias &alias,
int objectIndex,
968 int aliasIndex,
int encodedMetaPropertyIndex,
int resolvedTargetObjectId);
971 QQmlError propertyDataForAlias(
972 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
973 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
974 int targetPropertyIndex,
int resolvedTargetObjectId);
976 QQmlPropertyCacheVector *propertyCaches;
977 const ObjectContainer *objectContainer;
980template <
typename ObjectContainer>
982 QQmlPropertyCacheVector *propertyCaches,
const ObjectContainer *objectContainer)
984 , objectContainer(objectContainer)
988template <
typename ObjectContainer>
990 const CompiledObject &component,
const QV4::CompiledData::Alias &alias, QMetaType *type,
991 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
992 int targetPropertyIndex,
int resolvedTargetObjectId)
995 bool writable =
false;
996 bool resettable =
false;
997 bool notifiesViaBindable =
false;
999 propertyFlags->setIsAlias(
true);
1001 const int targetObjectIndex = objectForId(objectContainer, component, resolvedTargetObjectId);
1002 Q_ASSERT(targetObjectIndex >= 0);
1003 const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
1005 if (targetPropertyIndex == -1) {
1006 Q_ASSERT(objectContainer->stringAt(alias.propertyNameIndex()).isEmpty());
1007 auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
1012 return qQmlCompileError(targetObject.location,
1013 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1016 const auto referencedType = typeRef->type();
1017 Q_ASSERT(referencedType.isValid());
1018 *type = referencedType.typeId();
1019 if (!type->isValid() && referencedType.isInlineComponentType()) {
1020 *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
1021 Q_ASSERT(type->isValid());
1024 *version = typeRef->version();
1026 propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
1028 int coreIndex = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).coreIndex();
1030 = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).valueTypeIndex();
1032 QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
1033 Q_ASSERT(targetCache);
1035 const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
1036 Q_ASSERT(targetProperty);
1038 const QMetaType targetPropType = targetProperty->propType();
1040 const auto populateWithPropertyData = [&](
const QQmlPropertyData *property) {
1041 *type = property->propType();
1042 writable = property->isWritable();
1043 resettable = property->isResettable();
1044 notifiesViaBindable = property->notifiesViaBindable();
1046 if (property->isVarProperty())
1047 propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
1049 propertyFlags->copyPropertyTypeFlags(property->flags());
1053 if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
1056 QQmlPropertyCache::ConstPtr typeCache
1057 = QQmlMetaType::propertyCacheForType(targetPropType);
1061 if (
const QV4::ResolvedTypeReference *typeRef
1062 = objectContainer->resolvedType(targetPropType)) {
1063 typeCache = typeRef->typePropertyCache();
1067 const QQmlPropertyData *typeProperty = typeCache
1068 ? typeCache->property(valueTypeIndex)
1070 if (typeProperty ==
nullptr) {
1071 return qQmlCompileError(
1072 alias.referenceLocation(),
1073 QQmlPropertyCacheCreatorBase::tr(
"Invalid alias target"));
1075 populateWithPropertyData(typeProperty);
1078 populateWithPropertyData(targetProperty);
1080 if (valueTypeIndex != -1) {
1081 const QMetaObject *valueTypeMetaObject
1082 = QQmlMetaType::metaObjectForValueType(*type);
1083 const QMetaProperty valueTypeMetaProperty
1084 = valueTypeMetaObject->property(valueTypeIndex);
1085 *type = valueTypeMetaProperty.metaType();
1089 resettable = writable && valueTypeMetaProperty.isResettable();
1090 writable = writable && valueTypeMetaProperty.isWritable();
1093 propertyFlags->setIsDeepAlias(
true);
1098 propertyFlags->setIsWritable(writable && !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,
int resolvedTargetObjectId)
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 resolvedTargetObjectId);
1118 if (error.isValid())
1121 const QString propertyName = objectContainer->stringAt(alias.nameIndex());
1123 const QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
1124 Q_ASSERT(propertyCache);
1126 const int effectiveSignalIndex
1127 = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
1128 const int effectivePropertyIndex
1129 = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
1131 if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
1132 propertyCache->_defaultPropertyName = propertyName;
1134 const auto &appendResult =
1135 propertyCache->appendAlias(propertyName, propertyFlags, effectivePropertyIndex, type,
1136 version, effectiveSignalIndex, encodedMetaPropertyIndex,
1137 resolvedTargetObjectId);
1138 if (!appendResult) {
1139 return qQmlCompileError(
1140 alias.location(), QQmlPropertyCacheCreatorBase::explain(appendResult.error()));
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
QQmlError appendAliasToPropertyCache(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int objectIndex, int aliasIndex, int encodedMetaPropertyIndex, int resolvedTargetObjectId)
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)