5#ifndef QQMLCOMPONENTANDALIASRESOLVER_P_H
6#define QQMLCOMPONENTANDALIASRESOLVER_P_H
19#include <QtQml/qqmlcomponent.h>
20#include <QtQml/qqmlerror.h>
22#include <QtCore/qglobal.h>
23#include <QtCore/qhash.h>
25#include <private/qqmltypeloader_p.h>
26#include <private/qqmlpropertyresolver_p.h>
27#include <private/qqmlpropertycachecreator_p.h>
44template<
typename ObjectContainer>
52 ObjectContainer *compiler,
53 QQmlPropertyCacheVector *propertyCaches);
58 enum AliasResolutionResult {
66 void setObjectId(
int index)
const;
67 [[nodiscard]]
bool markAsComponent(
int index)
const;
68 [[nodiscard]] AliasResolutionResult resolveAliasesInObject(
70 QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator, QQmlError *error);
71 [[nodiscard]]
bool appendAliasToPropertyCache(
72 const CompiledObject *component,
const QV4::CompiledData::Alias *alias,
int objectIndex,
73 int aliasIndex,
int encodedPropertyIndex,
int resolvedTargetObjectId,
74 QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator, QQmlError *error)
76 *error = aliasCacheCreator->appendAliasToPropertyCache(
77 *component, *alias, objectIndex, aliasIndex, encodedPropertyIndex,
78 resolvedTargetObjectId);
79 resolvedAliases.insert(alias);
80 return !error->isValid();
87 const int childObjectIndex = binding->value.objectIndex;
91 QQmlPropertyCache::ConstPtr baseComponentCache
92 = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
93 QQmlPropertyCache::Ptr wrapperCache = baseComponentCache->copyAndReserve(1, 0, 0, 0);
94 wrapperCache->appendComponentWrapper(
95 wrapperCache->propertyCount(), childObjectIndex);
97 const uint wrapperIndex = m_propertyCaches->count();
98 m_propertyCaches->append(std::move(wrapperCache));
100 m_componentRoots.append(wrapperIndex);
104 [[nodiscard]] QQmlError findAndRegisterImplicitComponents(
105 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache);
106 [[nodiscard]] QQmlError collectIdsAndAliases(
int objectIndex);
107 [[nodiscard]] QQmlError resolveAliases(
int componentIndex);
108 void resolveGeneralizedGroupProperties(
int componentIndex);
109 [[nodiscard]] QQmlError resolveComponentsInInlineComponentRoot(
int root);
111 QString stringAt(
int idx)
const {
return m_compiler->stringAt(idx); }
112 QV4::ResolvedTypeReference *resolvedType(
int id)
const {
return m_compiler->resolvedType(id); }
114 [[nodiscard]] QQmlError error(
115 const QV4::CompiledData::Location &location,
116 const QString &description)
119 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
120 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
121 error.setDescription(description);
122 error.setUrl(m_compiler->url());
126 template<
typename Token>
127 [[nodiscard]] QQmlError error(Token token,
const QString &description)
129 return error(token->location, description);
132 static bool isUsableComponent(
const QMetaObject *metaObject)
138 if (metaObject == &QQmlComponent::staticMetaObject)
141 for (; metaObject; metaObject = metaObject->superClass()) {
142 if (qstrcmp(metaObject->className(),
"QQmlAbstractDelegateComponent") == 0)
149 ObjectContainer *m_compiler =
nullptr;
153 QQmlPropertyCacheVector *m_propertyCaches =
nullptr;
156 QList<quint32> m_componentRoots;
157 QList<
int> m_objectsWithAliases;
158 QList<CompiledBinding *> m_generalizedGroupProperties;
159 QSet<
const QV4::CompiledData::Alias *> resolvedAliases;
160 typename ObjectContainer::IdToObjectMap m_idToObjectIndex;
163template<
typename ObjectContainer>
165 ObjectContainer *compiler,
166 QQmlPropertyCacheVector *propertyCaches)
167 : m_compiler(compiler)
172template<
typename ObjectContainer>
174 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache)
176 QQmlPropertyResolver propertyResolver(propertyCache);
178 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
179 ? propertyCache->parent()->defaultProperty()
180 : propertyCache->defaultProperty();
182 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
183 if (binding->type() != QV4::CompiledData::Binding::Type_Object)
185 if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
188 auto targetObject = m_compiler->objectAt(binding->value.objectIndex);
189 auto typeReference = resolvedType(targetObject->inheritedTypeNameIndex);
190 Q_ASSERT(typeReference);
192 const QMetaObject *firstMetaObject =
nullptr;
193 if (
const auto propCache = typeReference->typePropertyCache())
194 firstMetaObject = propCache->firstCppMetaObject();
195 if (isUsableComponent(firstMetaObject))
199 const QQmlPropertyData *pd =
nullptr;
200 if (binding->propertyNameIndex != quint32(0)) {
201 bool notInRevision =
false;
202 pd = propertyResolver.property(stringAt(binding->propertyNameIndex), ¬InRevision);
204 pd = defaultProperty;
206 if (!pd || !pd->isQObject())
212 QQmlPropertyCache::ConstPtr pc = pd->typeVersion().hasMinorVersion()
213 ? QQmlMetaType::rawPropertyCacheForType(pd->propType(), pd->typeVersion())
214 : QQmlMetaType::rawPropertyCacheForType(pd->propType());
215 const QMetaObject *mo = pc ? pc->firstCppMetaObject() :
nullptr;
217 if (mo == &QQmlComponent::staticMetaObject)
219 mo = mo->superClass();
225 if (!wrapImplicitComponent(binding))
226 return error(binding, QQmlComponentAndAliasResolverBase::tr(
"Cannot wrap implicit component"));
232template<
typename ObjectContainer>
239 const auto rootObj = m_compiler->objectAt(root);
240 Q_ASSERT(rootObj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot));
242 if (
const int typeName = rootObj->inheritedTypeNameIndex) {
243 const auto *tref = resolvedType(typeName);
245 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject) {
246 qCWarning(lcQmlTypeCompiler).nospace().noquote()
247 << m_compiler->url().toString() <<
":" << rootObj->location.line() <<
":"
248 << rootObj->location.column()
249 <<
": Using a Component as the root of an inline component is deprecated: "
250 "inline components are "
251 "automatically wrapped into Components when needed.";
256 const QQmlPropertyCache::ConstPtr rootCache = m_propertyCaches->at(root);
259 return findAndRegisterImplicitComponents(rootObj, rootCache);
263template<
typename ObjectContainer>
270 const int objCountWithoutSynthesizedComponents = m_compiler->objectCount();
273 const QQmlError error = resolveComponentsInInlineComponentRoot(root);
279 const int startObjectIndex = root == 0 ? root : root+1;
281 for (
int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
282 auto obj = m_compiler->objectAt(i);
283 const bool isInlineComponentRoot
284 = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
285 const bool isPartOfInlineComponent
286 = obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
287 QQmlPropertyCache::ConstPtr cache = m_propertyCaches->at(i);
291 if (isInlineComponentRoot || isPartOfInlineComponent)
293 }
else if (!isPartOfInlineComponent || isInlineComponentRoot) {
301 if (obj->inheritedTypeNameIndex == 0 && !cache)
304 bool isExplicitComponent =
false;
305 if (obj->inheritedTypeNameIndex) {
306 auto *tref = resolvedType(obj->inheritedTypeNameIndex);
308 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
309 isExplicitComponent =
true;
312 if (!isExplicitComponent) {
314 const QQmlError error = findAndRegisterImplicitComponents(obj, cache);
321 if (!markAsComponent(i))
322 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot mark object as component"));
326 if (isExplicitComponent)
327 qCWarning(lcQmlTypeCompiler).nospace().noquote()
328 << m_compiler->url().toString() <<
":" << obj->location.line() <<
":"
329 << obj->location.column()
330 <<
": Using a Component as the root of a QML document is deprecated: types "
331 "defined in qml documents are "
332 "automatically wrapped into Components when needed.";
335 if (obj->functionCount() > 0)
336 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new functions."));
337 if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
338 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new properties."));
339 if (obj->signalCount() > 0)
340 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new signals."));
342 if (obj->bindingCount() == 0)
343 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot create empty component specification"));
345 const auto rootBinding = obj->bindingsBegin();
346 const auto bindingsEnd = obj->bindingsEnd();
350 for (
auto b = rootBinding; b != bindingsEnd; ++b) {
351 if (b->propertyNameIndex == 0)
354 return error(b, QQmlComponentAndAliasResolverBase::tr(
"Component elements may not contain properties other than id"));
357 if (
auto b = rootBinding;
358 b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
359 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Invalid component body specification"));
365 m_componentRoots.append(i);
368 for (
int i = 0; i < m_componentRoots.size(); ++i) {
369 const int componentRoot = m_componentRoots.at(i);
370 const int childObjectIndex = componentRoot < m_compiler->objectCount()
371 ? m_compiler->objectAt(componentRoot)->bindingsBegin()->value.objectIndex
372 : m_compiler->resolvedIndex(componentRoot);
374 m_idToObjectIndex.clear();
375 m_objectsWithAliases.clear();
376 m_generalizedGroupProperties.clear();
378 if (
const QQmlError error = collectIdsAndAliases(childObjectIndex);
383 allocateNamedObjects(m_compiler->objectAt(componentRoot));
385 if (
const QQmlError error = resolveAliases(componentRoot); error.isValid())
388 resolveGeneralizedGroupProperties(componentRoot);
392 m_idToObjectIndex.clear();
393 m_objectsWithAliases.clear();
394 m_generalizedGroupProperties.clear();
396 if (
const QQmlError error = collectIdsAndAliases(root); error.isValid())
399 allocateNamedObjects(m_compiler->objectAt(root));
400 if (
const QQmlError error = resolveAliases(root); error.isValid())
403 resolveGeneralizedGroupProperties(root);
407template<
typename ObjectContainer>
410 auto obj = m_compiler->objectAt(objectIndex);
412 if (obj->idNameIndex != 0) {
413 if (m_idToObjectIndex.contains(obj->idNameIndex))
414 return error(obj->locationOfIdProperty, QQmlComponentAndAliasResolverBase::tr(
"id is not unique"));
415 setObjectId(objectIndex);
416 m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
419 if (obj->aliasCount() > 0)
420 m_objectsWithAliases.append(objectIndex);
423 if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != 0)
426 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd();
427 binding != end; ++binding) {
428 switch (binding->type()) {
429 case QV4::CompiledData::Binding::Type_GroupProperty: {
430 const auto *inner = m_compiler->objectAt(binding->value.objectIndex);
431 if (m_compiler->stringAt(inner->inheritedTypeNameIndex).isEmpty()) {
432 const auto cache = m_propertyCaches->at(objectIndex);
433 if (!cache || !cache->property(
434 m_compiler->stringAt(binding->propertyNameIndex),
nullptr,
nullptr)) {
435 m_generalizedGroupProperties.append(binding);
440 case QV4::CompiledData::Binding::Type_Object:
441 case QV4::CompiledData::Binding::Type_AttachedProperty:
444 if (m_compiler->implicitComponentForObject(binding->value.objectIndex) != -1)
446 if (
const QQmlError error = collectIdsAndAliases(binding->value.objectIndex);
459template<
typename ObjectContainer>
462 if (m_objectsWithAliases.isEmpty())
465 QQmlPropertyCacheAliasCreator<ObjectContainer> aliasCacheCreator(m_propertyCaches, m_compiler);
467 bool atLeastOneAliasResolved;
469 atLeastOneAliasResolved =
false;
470 QList<
int> pendingObjects;
472 for (
int objectIndex: std::as_const(m_objectsWithAliases)) {
475 const auto &component = *m_compiler->objectAt(componentIndex);
477 = resolveAliasesInObject(component, objectIndex, &aliasCacheCreator, &error);
481 if (result == AllAliasesResolved) {
482 atLeastOneAliasResolved =
true;
483 }
else if (result == SomeAliasesResolved) {
484 atLeastOneAliasResolved =
true;
485 pendingObjects.append(objectIndex);
487 pendingObjects.append(objectIndex);
490 qSwap(m_objectsWithAliases, pendingObjects);
491 }
while (!m_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
493 if (!atLeastOneAliasResolved && !m_objectsWithAliases.isEmpty()) {
494 const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
495 for (
auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
496 if (!resolvedAliases.contains(alias)) {
498 alias->location(), QQmlComponentAndAliasResolverBase::tr(
"Cyclic alias"));
506template<
typename ObjectContainer>
510 const auto &component = *m_compiler->objectAt(componentIndex);
511 for (CompiledBinding *binding : m_generalizedGroupProperties)
512 resolveGeneralizedGroupProperty(component, binding);
QQmlComponentAndAliasResolver(ObjectContainer *compiler, QQmlPropertyCacheVector *propertyCaches)
QQmlError resolve(int root=0)
typename ObjectContainer::CompiledObject CompiledObject
typename ObjectContainer::CompiledBinding CompiledBinding
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcQIORing)