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 {
65 void allocateNamedObjects(
int componentRoot)
const;
66 void setObjectId(
int index)
const;
67 [[nodiscard]]
bool markAsComponent(
int index)
const;
68 [[nodiscard]]
bool isComponentBoundary(
int index)
const;
69 [[nodiscard]] AliasResolutionResult resolveAliasesInObject(
70 int objectIndex, QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator,
72 [[nodiscard]]
bool appendAliasToPropertyCache(
73 const QV4::CompiledData::Alias *alias,
int objectIndex,
int aliasIndex,
74 int encodedPropertyIndex,
int resolvedTargetObjectId,
int targetObjectIndex,
75 QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator, QQmlError *error)
77 *error = aliasCacheCreator->appendAliasToPropertyCache(
78 *alias, objectIndex, aliasIndex, encodedPropertyIndex, resolvedTargetObjectId,
80 resolvedAliases.insert(alias);
81 return !error->isValid();
88 const int childObjectIndex = binding->value.objectIndex;
92 QQmlPropertyCache::ConstPtr baseComponentCache
93 = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
94 QQmlPropertyCache::Ptr wrapperCache = baseComponentCache->copyAndReserve(1, 0, 0, 0);
95 wrapperCache->appendComponentWrapper(
96 wrapperCache->propertyCount(), childObjectIndex);
98 const uint wrapperIndex = m_propertyCaches->count();
99 m_propertyCaches->append(std::move(wrapperCache));
101 m_componentRoots.append(wrapperIndex);
105 [[nodiscard]] QQmlError findAndRegisterImplicitComponents(
106 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache);
107 [[nodiscard]] QQmlError collectIdsAndAliases(
int objectIndex);
108 [[nodiscard]] QQmlError resolveAliases();
109 void resolveGeneralizedGroupedProperties();
110 [[nodiscard]] QQmlError resolveComponentsInInlineComponentRoot(
int root);
112 QString stringAt(
int idx)
const {
return m_compiler->stringAt(idx); }
113 QV4::ResolvedTypeReference *resolvedType(
int id)
const {
return m_compiler->resolvedType(id); }
115 [[nodiscard]] QQmlError error(
116 const QV4::CompiledData::Location &location,
117 const QString &description)
120 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
121 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
122 error.setDescription(description);
123 error.setUrl(m_compiler->url());
127 template<
typename Token>
128 [[nodiscard]] QQmlError error(Token token,
const QString &description)
130 return error(token->location, description);
133 static bool isUsableComponent(
const QMetaObject *metaObject)
139 if (metaObject == &QQmlComponent::staticMetaObject)
142 for (; metaObject; metaObject = metaObject->superClass()) {
143 if (qstrcmp(metaObject->className(),
"QQmlAbstractDelegateComponent") == 0)
150 ObjectContainer *m_compiler =
nullptr;
154 QQmlPropertyCacheVector *m_propertyCaches =
nullptr;
157 QList<quint32> m_componentRoots;
158 QList<
int> m_objectsWithAliases;
159 QList<CompiledBinding *> m_generalizedGroupedProperties;
160 QSet<
const QV4::CompiledData::Alias *> resolvedAliases;
161 typename ObjectContainer::IdToObjectMap m_idToObjectIndex;
164template<
typename ObjectContainer>
166 ObjectContainer *compiler,
167 QQmlPropertyCacheVector *propertyCaches)
168 : m_compiler(compiler)
173template<
typename ObjectContainer>
175 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache)
177 QQmlPropertyResolver propertyResolver(propertyCache);
179 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
180 ? propertyCache->parent()->defaultProperty()
181 : propertyCache->defaultProperty();
183 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
184 if (binding->type() != QV4::CompiledData::Binding::Type_Object)
187 auto targetObject = m_compiler->objectAt(binding->value.objectIndex);
188 auto typeReference = resolvedType(targetObject->inheritedTypeNameIndex);
189 Q_ASSERT(typeReference);
191 const QMetaObject *firstMetaObject =
nullptr;
192 if (
const auto propCache = typeReference->typePropertyCache())
193 firstMetaObject = propCache->firstCppMetaObject();
194 if (isUsableComponent(firstMetaObject))
198 const QQmlPropertyData *pd =
nullptr;
199 if (binding->propertyNameIndex != quint32(0)) {
200 bool notInRevision =
false;
201 pd = propertyResolver.property(stringAt(binding->propertyNameIndex), ¬InRevision);
203 pd = defaultProperty;
205 if (!pd || !pd->isQObject())
211 QQmlPropertyCache::ConstPtr pc = pd->typeVersion().hasMinorVersion()
212 ? QQmlMetaType::rawPropertyCacheForType(pd->propType(), pd->typeVersion())
213 : QQmlMetaType::rawPropertyCacheForType(pd->propType());
214 const QMetaObject *mo = pc ? pc->firstCppMetaObject() :
nullptr;
216 if (mo == &QQmlComponent::staticMetaObject)
218 mo = mo->superClass();
224 if (!wrapImplicitComponent(binding))
225 return error(binding, QQmlComponentAndAliasResolverBase::tr(
"Cannot wrap implicit component"));
231template<
typename ObjectContainer>
238 const auto rootObj = m_compiler->objectAt(root);
239 Q_ASSERT(rootObj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot));
241 if (
const int typeName = rootObj->inheritedTypeNameIndex) {
242 const auto *tref = resolvedType(typeName);
244 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject) {
245 qCWarning(lcQmlTypeCompiler).nospace().noquote()
246 << m_compiler->url().toString() <<
":" << rootObj->location.line() <<
":"
247 << rootObj->location.column()
248 <<
": Using a Component as the root of an inline component is deprecated: "
249 "inline components are "
250 "automatically wrapped into Components when needed.";
255 const QQmlPropertyCache::ConstPtr rootCache = m_propertyCaches->at(root);
258 return findAndRegisterImplicitComponents(rootObj, rootCache);
262template<
typename ObjectContainer>
269 const int objCountWithoutSynthesizedComponents = m_compiler->objectCount();
272 const QQmlError error = resolveComponentsInInlineComponentRoot(root);
278 const int startObjectIndex = root == 0 ? root : root+1;
280 for (
int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
281 auto obj = m_compiler->objectAt(i);
282 const bool isInlineComponentRoot
283 = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
284 const bool isPartOfInlineComponent
285 = obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
286 QQmlPropertyCache::ConstPtr cache = m_propertyCaches->at(i);
290 if (isInlineComponentRoot || isPartOfInlineComponent)
292 }
else if (!isPartOfInlineComponent || isInlineComponentRoot) {
300 if (obj->inheritedTypeNameIndex == 0 && !cache)
303 bool isExplicitComponent =
false;
304 if (obj->inheritedTypeNameIndex) {
305 auto *tref = resolvedType(obj->inheritedTypeNameIndex);
307 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
308 isExplicitComponent =
true;
311 if (!isExplicitComponent) {
313 const QQmlError error = findAndRegisterImplicitComponents(obj, cache);
320 if (!markAsComponent(i))
321 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot mark object as component"));
325 if (isExplicitComponent)
326 qCWarning(lcQmlTypeCompiler).nospace().noquote()
327 << m_compiler->url().toString() <<
":" << obj->location.line() <<
":"
328 << obj->location.column()
329 <<
": Using a Component as the root of a QML document is deprecated: types "
330 "defined in qml documents are "
331 "automatically wrapped into Components when needed.";
334 if (obj->functionCount() > 0)
335 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new functions."));
336 if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
337 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new properties."));
338 if (obj->signalCount() > 0)
339 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new signals."));
341 if (obj->bindingCount() == 0)
342 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot create empty component specification"));
344 const auto rootBinding = obj->bindingsBegin();
345 const auto bindingsEnd = obj->bindingsEnd();
349 for (
auto b = rootBinding; b != bindingsEnd; ++b) {
350 if (b->propertyNameIndex == 0)
353 return error(b, QQmlComponentAndAliasResolverBase::tr(
"Component elements may not contain properties other than id"));
356 if (
auto b = rootBinding;
357 b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
358 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Invalid component body specification"));
364 m_componentRoots.append(i);
367 for (
int i = 0; i < m_componentRoots.size(); ++i) {
368 const int componentRoot = m_componentRoots.at(i);
369 const int childObjectIndex = componentRoot < m_compiler->objectCount()
370 ? m_compiler->objectAt(componentRoot)->bindingsBegin()->value.objectIndex
371 : m_compiler->resolvedIndex(componentRoot);
373 m_idToObjectIndex.clear();
374 m_objectsWithAliases.clear();
375 m_generalizedGroupedProperties.clear();
377 if (
const QQmlError error = collectIdsAndAliases(childObjectIndex);
382 allocateNamedObjects(componentRoot);
384 if (
const QQmlError error = resolveAliases(); error.isValid())
387 resolveGeneralizedGroupedProperties();
391 m_idToObjectIndex.clear();
392 m_objectsWithAliases.clear();
393 m_generalizedGroupedProperties.clear();
395 if (
const QQmlError error = collectIdsAndAliases(root); error.isValid())
398 allocateNamedObjects(root);
399 if (
const QQmlError error = resolveAliases(); error.isValid())
402 resolveGeneralizedGroupedProperties();
406template<
typename ObjectContainer>
409 auto obj = m_compiler->objectAt(objectIndex);
411 if (obj->idNameIndex != 0) {
412 if (m_idToObjectIndex.contains(obj->idNameIndex))
413 return error(obj->locationOfIdProperty, QQmlComponentAndAliasResolverBase::tr(
"id is not unique"));
414 setObjectId(objectIndex);
415 m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
418 if (obj->aliasCount() > 0)
419 m_objectsWithAliases.append(objectIndex);
422 if (isComponentBoundary(objectIndex) && objectIndex != 0)
425 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd();
426 binding != end; ++binding) {
427 switch (binding->type()) {
428 case QV4::CompiledData::Binding::Type_GroupedProperty: {
429 const auto *inner = m_compiler->objectAt(binding->value.objectIndex);
430 if (m_compiler->stringAt(inner->inheritedTypeNameIndex).isEmpty()) {
431 const auto cache = m_propertyCaches->at(objectIndex);
432 if (!cache || !cache->property(
433 m_compiler->stringAt(binding->propertyNameIndex),
nullptr,
nullptr)) {
434 m_generalizedGroupedProperties.append(binding);
439 case QV4::CompiledData::Binding::Type_Object:
440 case QV4::CompiledData::Binding::Type_AttachedProperty:
443 if (m_compiler->implicitComponentForObject(binding->value.objectIndex) != -1)
445 if (
const QQmlError error = collectIdsAndAliases(binding->value.objectIndex);
458template<
typename ObjectContainer>
461 if (m_objectsWithAliases.isEmpty())
464 QQmlPropertyCacheAliasCreator<ObjectContainer> aliasCacheCreator(m_propertyCaches, m_compiler);
466 bool atLeastOneAliasResolved;
468 atLeastOneAliasResolved =
false;
469 QList<
int> pendingObjects;
471 for (
int objectIndex: std::as_const(m_objectsWithAliases)) {
474 const auto result = resolveAliasesInObject(objectIndex, &aliasCacheCreator, &error);
478 if (result == AllAliasesResolved) {
479 atLeastOneAliasResolved =
true;
480 }
else if (result == SomeAliasesResolved) {
481 atLeastOneAliasResolved =
true;
482 pendingObjects.append(objectIndex);
484 pendingObjects.append(objectIndex);
487 qSwap(m_objectsWithAliases, pendingObjects);
488 }
while (!m_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
490 if (!atLeastOneAliasResolved && !m_objectsWithAliases.isEmpty()) {
491 const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
492 for (
auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
493 if (!resolvedAliases.contains(alias)) {
495 alias->location(), QQmlComponentAndAliasResolverBase::tr(
"Cyclic alias"));
503template<
typename ObjectContainer>
506 for (CompiledBinding *binding : std::as_const(m_generalizedGroupedProperties))
507 resolveGeneralizedGroupedProperty(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)