aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlpropertycachecreator_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlpropertycachecreator_p.h')
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h529
1 files changed, 253 insertions, 276 deletions
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index e58d8ece1b..4d49ca6ed4 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -21,8 +21,14 @@
#include <private/qqmltypedata_p.h>
#include <private/inlinecomponentutils_p.h>
#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QScopedValueRollback>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
#include <vector>
QT_BEGIN_NAMESPACE
@@ -66,12 +72,62 @@ struct QQmlPropertyCacheCreatorBase
public:
static QAtomicInt Q_AUTOTEST_EXPORT classIndexCounter;
- static QMetaType metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
- static QMetaType listTypeForPropertyType(QV4::CompiledData::BuiltinType type);
+ static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QVariant>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<int>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<bool>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<qreal>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QString>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QUrl>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QTime>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QDate>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QDateTime>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QRegularExpression>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QRectF>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QPointF>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QSizeF>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
+
+ static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QList<QVariant>>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<QList<int>>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<QList<bool>>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<QList<qreal>>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QList<QString>>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QList<QUrl>>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QList<QTime>>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QList<QDate>>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QList<QDateTime>>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QList<QRegularExpression>>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QList<QRectF>>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QList<QPointF>>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QList<QSizeF>>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
+ static bool canCreateClassNameTypeByUrl(const QUrl &url);
static QByteArray createClassNameTypeByUrl(const QUrl &url);
- static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, int icId);
+ static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name);
struct IncrementalResult {
// valid if and only if an error occurred
@@ -115,14 +171,6 @@ public:
*/
QQmlError verifyNoICCycle();
- /*!
- \internal
- Fills the property caches for the CompiledObjects by
- calling buildMetaObjectsIncrementally until it can no
- longer resume.
- */
- QQmlError buildMetaObjects();
-
enum class VMEMetaObjectIsRequired {
Maybe,
Always
@@ -165,7 +213,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
, typeClassName(typeClassName)
, currentRoot(-1)
{
- propertyCaches->resize(objectContainer->objectCount());
+ propertyCaches->resetAndResize(objectContainer->objectCount());
using namespace icutils;
@@ -179,7 +227,7 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
}
// create a graph on inline components referencing inline components
- std::vector<Node> nodes;
+ std::vector<icutils::Node> nodes;
nodes.resize(allICs.size());
std::iota(nodes.begin(), nodes.end(), 0);
AdjacencyList adjacencyList;
@@ -233,20 +281,6 @@ QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally()
}
template <typename ObjectContainer>
-inline QQmlError
-QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
-{
- QQmlError error = verifyNoICCycle();
- if (error.isValid())
- return error;
- QQmlPropertyCacheCreatorBase::IncrementalResult result;
- do {
- result = buildMetaObjectsIncrementally();
- } while (result.canResume);
- return result.error;
-}
-
-template <typename ObjectContainer>
inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
{
auto isAddressable = [](const QUrl &url) {
@@ -277,7 +311,10 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
- QQmlError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ QQmlError error = baseTypeCache
+ ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
+ : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
+ "Type cannot be used for 'on' assignment"));
if (error.isValid())
return error;
}
@@ -367,7 +404,13 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr
}
}
- return typeRef->createPropertyCache();
+ if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
+ return propertyCache;
+ *error = qQmlCompileError(
+ obj->location,
+ QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.")
+ .arg(stringAt(obj->inheritedTypeNameIndex)));
+ return nullptr;
} else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
if (binding->isAttachedProperty()) {
auto *typeRef = objectContainer->resolvedType(
@@ -375,8 +418,9 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr
Q_ASSERT(typeRef);
QQmlType qmltype = typeRef->type();
if (!qmltype.isValid()) {
- imports->resolveType(stringAt(binding->propertyNameIndex),
- &qmltype, nullptr, nullptr, nullptr);
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &qmltype, nullptr, nullptr);
}
const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
@@ -385,23 +429,6 @@ inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::pr
return nullptr;
}
return QQmlMetaType::propertyCache(attachedMo);
- } else if (binding->isGroupProperty()) {
- const auto *obj = objectContainer->objectAt(binding->value.objectIndex);
- if (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
- return nullptr;
-
- for (int i = 0, end = objectContainer->objectCount(); i != end; ++i) {
- const auto *ext = objectContainer->objectAt(i);
- if (ext->idNameIndex != binding->propertyNameIndex)
- continue;
-
- if (ext->inheritedTypeNameIndex == 0)
- return nullptr;
-
- QQmlBindingInstantiationContext pendingContext(i, &(*binding), QString(), nullptr);
- pendingGroupPropertyBindings->append(pendingContext);
- return nullptr;
- }
}
}
return nullptr;
@@ -472,8 +499,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
// For property change signal override detection.
// We prepopulate a set of signal names which already exist in the object,
// and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
+ // TODO: Remove AllowOverride once we can. No override should be allowed.
+ enum class AllowOverride { No, Yes };
+ QHash<QString, AllowOverride> seenSignals {
+ { QStringLiteral("destroyed"), AllowOverride::No },
+ { QStringLiteral("parentChanged"), AllowOverride::No },
+ { QStringLiteral("objectNameChanged"), AllowOverride::No }
+ };
const QQmlPropertyCache *parentCache = cache.data();
while ((parentCache = parentCache->parent().data())) {
if (int pSigCount = parentCache->signalCount()) {
@@ -484,7 +516,15 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
iter != parentCache->stringCache.end(); ++iter) {
if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
+ if (currPSig->isOverridableSignal()) {
+ const qsizetype oldSize = seenSignals.size();
+ AllowOverride &entry = seenSignals[iter.key()];
+ if (seenSignals.size() != oldSize)
+ entry = AllowOverride::Yes;
+ } else {
+ seenSignals[iter.key()] = AllowOverride::No;
+ }
+
break;
}
}
@@ -498,8 +538,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
for ( ; p != pend; ++p) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -509,8 +550,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
for ( ; a != aend; ++a) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -562,10 +604,26 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
flags.setHasArguments(true);
QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
+ const auto it = seenSignals.find(signalName);
+ if (it == seenSignals.end()) {
+ seenSignals[signalName] = AllowOverride::No;
+ } else {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ s->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate signal name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ *it = AllowOverride::No; // No further overriding allowed.
+ break;
+ }
+ }
cache->appendSignal(signalName, flags, effectiveMethodIndex++,
paramCount?paramTypes.constData():nullptr, names);
}
@@ -578,8 +636,23 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
auto flags = QQmlPropertyData::defaultSlotFlags();
const QString slotName = stringAt(function->nameIndex);
- if (seenSignals.contains(slotName))
- return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ const auto it = seenSignals.constFind(slotName);
+ if (it != seenSignals.constEnd()) {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ function->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate method name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ break;
+ }
+ }
// Note: we don't append slotName to the seenSignals list, since we don't
// protect against overriding change signals or methods with properties.
@@ -614,58 +687,53 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
QTypeRevision propertyTypeVersion = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- const QV4::CompiledData::BuiltinType type = p->builtinType();
+ const QV4::CompiledData::CommonType type = p->commonType();
if (p->isList())
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
- else if (type == QV4::CompiledData::BuiltinType::Var)
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
+ else if (type == QV4::CompiledData::CommonType::Var)
+ propertyFlags.setType(QQmlPropertyData::Flags::VarPropertyType);
- if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
+ if (type != QV4::CompiledData::CommonType::Invalid) {
propertyType = p->isList()
? listTypeForPropertyType(type)
: metaTypeForPropertyType(type);
} else {
- Q_ASSERT(!p->isBuiltinType());
+ Q_ASSERT(!p->isCommonType());
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
- nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
+ if (!imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate),
+ stringAt(p->commonTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
+ nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
// inline components are not necessarily valid yet
- Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
+ Q_ASSERT(qmltype.isValid());
if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
- CompositeMetaTypeIds typeIds;
+ QQmlType compositeType;
if (qmltype.isInlineComponentType()) {
- auto objectId = qmltype.inlineComponentId();
- auto containingType = qmltype.containingType();
- if (containingType.isValid()) {
- auto icType = containingType.lookupInlineComponentById(objectId);
- typeIds = {icType.typeId(), icType.qListTypeId()};
- } else {
- typeIds = {};
- }
- if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type
- typeIds = objectContainer->typeIdsForComponent(objectId);
- Q_ASSERT(typeIds.isValid());
+ compositeType = qmltype;
+ Q_ASSERT(compositeType.isValid());
} else if (selfReference) {
- typeIds = objectContainer->typeIdsForComponent();
+ compositeType = objectContainer->qmlTypeForComponent();
} else {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ // compositeType may not be the same type as qmlType because multiple engines
+ // may load different types for the same document. Therefore we have to ask
+ // our engine's type loader here.
+ QQmlRefPointer<QQmlTypeData> tdata
+ = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
- typeIds = compilationUnit->typeIdsForComponent();
+ compositeType = tdata->compilationUnit()->qmlTypeForComponent();
}
if (p->isList()) {
- propertyType = typeIds.listId;
+ propertyType = compositeType.qListTypeId();
} else {
- propertyType = typeIds.id;
+ propertyType = compositeType.typeId();
}
} else {
if (p->isList())
@@ -676,11 +744,9 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
}
if (p->isList())
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
else if (propertyType.flags().testFlag(QMetaType::PointerToQObject))
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else
- propertyFlags.type = QQmlPropertyData::Flags::ValueType;
+ propertyFlags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
}
if (!p->isReadOnly() && !propertyType.flags().testFlag(QMetaType::IsQmlList))
@@ -701,50 +767,56 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
}
template <typename ObjectContainer>
-inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
- QString *customTypeName)
+inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(
+ const QV4::CompiledData::ParameterType &param, QString *customTypeName)
{
- const quint32 typeId = param.typeNameIndexOrBuiltinType();
- if (param.indexIsBuiltinType()) {
+ const quint32 typeId = param.typeNameIndexOrCommonType();
+ if (param.indexIsCommonType()) {
// built-in type
if (param.isList())
- return listTypeForPropertyType(QV4::CompiledData::BuiltinType(typeId));
- return metaTypeForPropertyType(QV4::CompiledData::BuiltinType(typeId));
+ return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
+ return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
}
// lazily resolved type
- const QString typeName = stringAt(param.typeNameIndexOrBuiltinType());
+ const QString typeName = stringAt(param.typeNameIndexOrCommonType());
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr,
- QQmlType::AnyRegistrationType, &selfReference))
+ if (!imports->resolveType(
+ &enginePrivate->typeLoader, typeName, &qmltype, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &selfReference))
return QMetaType();
if (!qmltype.isComposite()) {
const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
if (!typeId.isValid() && qmltype.isInlineComponentType()) {
- const int objectId = qmltype.inlineComponentId();
- const auto typeIds = objectContainer->typeIdsForComponent(objectId);
- return param.isList() ? typeIds.listId : typeIds.id;
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
} else {
return typeId;
}
}
if (selfReference) {
- const auto typeIds = objectContainer->typeIdsForComponent();
- return param.isList() ? typeIds.listId : typeIds.id;
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent();
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
}
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
+ return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
+}
- return param.isList() ? compilationUnit->typeIds.listId : compilationUnit->typeIds.id;
+template <typename ObjectContainer, typename CompiledObject>
+int objectForId(const ObjectContainer *objectContainer, const CompiledObject &component, int id)
+{
+ for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
+ if (candidate.objectId() == id)
+ return candidateIndex;
+ }
+ return -1;
}
template <typename ObjectContainer>
@@ -753,126 +825,27 @@ class QQmlPropertyCacheAliasCreator
public:
typedef typename ObjectContainer::CompiledObject CompiledObject;
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
-
- QQmlError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
+ QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
+ QQmlError appendAliasesToPropertyCache(
+ const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv);
- QQmlError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type, QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv);
-
- void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
-
- int objectForId(const CompiledObject &component, int id) const;
+ QQmlError propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
+ QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
+ QQmlEnginePrivate *enginePriv);
QQmlPropertyCacheVector *propertyCaches;
const ObjectContainer *objectContainer;
};
template <typename ObjectContainer>
-inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
+inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
: propertyCaches(propertyCaches)
, objectContainer(objectContainer)
{
-
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv)
-{
- // skip the root object (index 0) as that one does not have a first object index originating
- // from a binding.
- for (int i = 1; i < objectContainer->objectCount(); ++i) {
- const CompiledObject &component = *objectContainer->objectAt(i);
- if (!component.hasFlag(QV4::CompiledData::Object::IsComponent))
- continue;
-
- const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv);
- }
-
- const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv);
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv)
-{
- QVector<int> objectsWithAliases;
- collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
- if (objectsWithAliases.isEmpty())
- return;
-
- const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
-
- const int targetObjectIndex = objectForId(component, alias->targetObjectId());
- Q_ASSERT(targetObjectIndex >= 0);
-
- if (alias->isAliasToLocalAlias())
- continue;
-
- if (alias->encodedMetaPropertyIndex == -1)
- continue;
-
- const QQmlPropertyCache::ConstPtr targetCache
- = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
-
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- if (!targetProperty)
- return false;
- }
- return true;
- };
-
- do {
- QVector<int> pendingObjects;
-
- for (int objectIndex: std::as_const(objectsWithAliases)) {
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
-
- if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex, enginePriv);
- } else {
- pendingObjects.append(objectIndex);
- }
-
- }
- objectsWithAliases = std::move(pendingObjects);
- } while (!objectsWithAliases.isEmpty());
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (object.aliasCount() > 0)
- objectsWithAliases->append(objectIndex);
-
- // Stop at Component boundary
- if (object.hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0)
- return;
-
- auto binding = object.bindingsBegin();
- auto end = object.bindingsEnd();
- for (; binding != end; ++binding) {
- switch (binding->type()) {
- case QV4::CompiledData::Binding::Type_Object:
- case QV4::CompiledData::Binding::Type_AttachedProperty:
- case QV4::CompiledData::Binding::Type_GroupProperty:
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
- break;
- default:
- break;
- }
- }
}
template <typename ObjectContainer>
@@ -893,7 +866,8 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId());
+ const int targetObjectIndex = objectForId(
+ objectContainer, component, lastAlias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
@@ -912,10 +886,11 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
lastAlias = targetAlias;
} while (lastAlias->isAliasToLocalAlias());
- return propertyDataForAlias(component, *lastAlias, type, version, propertyFlags, enginePriv);
+ return propertyDataForAlias(
+ component, *lastAlias, type, version, propertyFlags, enginePriv);
}
- const int targetObjectIndex = objectForId(component, alias.targetObjectId());
+ const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
@@ -934,20 +909,20 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
if (referencedType.isValid()) {
*type = referencedType.typeId();
if (!type->isValid() && referencedType.isInlineComponentType()) {
- int objectId = referencedType.inlineComponentId();
- *type = objectContainer->typeIdsForComponent(objectId).id;
+ *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
Q_ASSERT(type->isValid());
}
} else {
- *type = typeRef->compilationUnit()->typeIds.id;
+ *type = typeRef->compilationUnit()->metaType();
}
*version = typeRef->version();
- propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
+ propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
} else {
int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
- int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
+ int valueTypeIndex = QQmlPropertyIndex::fromEncoded(
+ alias.encodedMetaPropertyIndex).valueTypeIndex();
QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
@@ -955,53 +930,67 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
+ const QMetaType targetPropType = targetProperty->propType();
+
+ const auto populateWithPropertyData = [&](const QQmlPropertyData *property) {
+ *type = property->propType();
+ writable = property->isWritable();
+ resettable = property->isResettable();
+ bindable = property->isBindable();
+
+ if (property->isVarProperty())
+ propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
+ else
+ propertyFlags->copyPropertyTypeFlags(property->flags());
+ };
+
// for deep aliases, valueTypeIndex is always set
- if (!QQmlMetaType::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
// deep alias property
- *type = targetProperty->propType();
- QQmlPropertyCache::ConstPtr typeCache = QQmlMetaType::propertyCacheForType(*type);
- Q_ASSERT(typeCache);
- const QQmlPropertyData *typeProperty = typeCache->property(valueTypeIndex);
- if (typeProperty == nullptr) {
- return qQmlCompileError(alias.referenceLocation,
- QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ QQmlPropertyCache::ConstPtr typeCache
+ = QQmlMetaType::propertyCacheForType(targetPropType);
+
+ if (!typeCache) {
+ // See if it's a half-resolved composite type
+ if (const QV4::ResolvedTypeReference *typeRef
+ = objectContainer->resolvedType(targetPropType)) {
+ typeCache = typeRef->typePropertyCache();
+ }
}
- *type = typeProperty->propType();
- writable = typeProperty->isWritable();
- resettable = typeProperty->isResettable();
- bindable = typeProperty->isBindable();
+ const QQmlPropertyData *typeProperty = typeCache
+ ? typeCache->property(valueTypeIndex)
+ : nullptr;
+ if (typeProperty == nullptr) {
+ return qQmlCompileError(
+ alias.referenceLocation,
+ QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ }
+ populateWithPropertyData(typeProperty);
} else {
// value type or primitive type or enum
- *type = targetProperty->propType();
-
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
- bindable = targetProperty->isBindable();
+ populateWithPropertyData(targetProperty);
if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QMetaType::fromType<int>();
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).metaType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QMetaType::fromType<int>();
- } else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
-
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
- }
+ const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType(*type);
+ const QMetaProperty valueTypeMetaProperty
+ = valueTypeMetaObject->property(valueTypeIndex);
+ *type = valueTypeMetaProperty.metaType();
+
+ // We can only write or reset the value type property if we can write
+ // the value type itself.
+ resettable = writable && valueTypeMetaProperty.isResettable();
+ writable = writable && valueTypeMetaProperty.isWritable();
+
+ bindable = valueTypeMetaProperty.isBindable();
}
}
}
- propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly))
- && writable);
+ propertyFlags->setIsWritable(
+ writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
propertyFlags->setIsResettable(resettable);
propertyFlags->setIsBindable(bindable);
return QQmlError();
@@ -1047,18 +1036,6 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
return QQmlError();
}
-template <typename ObjectContainer>
-inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
-{
- for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
- const int candidateIndex = component.namedObjectsInComponentTable()[i];
- const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.objectId() == id)
- return candidateIndex;
- }
- return -1;
-}
-
QT_END_NAMESPACE
#endif // QQMLPROPERTYCACHECREATOR_P_H