3#ifndef QQMLCOMPONENTANDALIASRESOLVER_P_H
4#define QQMLCOMPONENTANDALIASRESOLVER_P_H
17#include <QtQml/qqmlcomponent.h>
18#include <QtQml/qqmlerror.h>
20#include <QtCore/qglobal.h>
21#include <QtCore/qhash.h>
23#include <private/qqmltypeloader_p.h>
24#include <private/qqmlpropertyresolver_p.h>
25#include <private/qqmlpropertycachecreator_p.h>
42template<
typename ObjectContainer>
50 ObjectContainer *compiler,
51 QQmlPropertyCacheVector *propertyCaches);
56 enum AliasResolutionResult {
64 void setObjectId(
int index)
const;
65 [[
nodiscard]]
bool markAsComponent(
int index)
const;
66 [[
nodiscard]] AliasResolutionResult resolveAliasesInObject(
68 QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator, QQmlError *error);
69 [[
nodiscard]]
bool appendAliasToPropertyCache(
70 const CompiledObject *component,
const QV4::CompiledData::Alias *alias,
int objectIndex,
71 int aliasIndex,
int encodedPropertyIndex,
72 QQmlPropertyCacheAliasCreator<ObjectContainer> *aliasCacheCreator, QQmlError *error)
74 *error = aliasCacheCreator->appendAliasToPropertyCache(
75 *component, *alias, objectIndex, aliasIndex, encodedPropertyIndex);
76 resolvedAliases.insert(alias);
77 return !error->isValid();
84 [[
nodiscard]] QQmlError findAndRegisterImplicitComponents(
85 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache);
86 [[
nodiscard]] QQmlError collectIdsAndAliases(
int objectIndex);
87 [[
nodiscard]] QQmlError resolveAliases(
int componentIndex);
88 void resolveGeneralizedGroupProperties(
int componentIndex);
89 [[
nodiscard]] QQmlError resolveComponentsInInlineComponentRoot(
int root);
91 QString stringAt(
int idx)
const {
return m_compiler->stringAt(idx); }
92 QV4::ResolvedTypeReference *resolvedType(
int id)
const {
return m_compiler->resolvedType(id); }
95 const QV4::CompiledData::Location &location,
96 const QString &description)
99 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
100 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
101 error.setDescription(description);
102 error.setUrl(m_compiler->url());
106 template<
typename Token>
107 [[nodiscard]] QQmlError error(Token token,
const QString &description)
109 return error(token->location, description);
112 static bool isUsableComponent(
const QMetaObject *metaObject)
118 if (metaObject == &QQmlComponent::staticMetaObject)
121 for (; metaObject; metaObject = metaObject->superClass()) {
122 if (qstrcmp(metaObject->className(),
"QQmlAbstractDelegateComponent") == 0)
129 ObjectContainer *m_compiler =
nullptr;
133 QQmlPropertyCacheVector *m_propertyCaches =
nullptr;
136 QVector<quint32> m_componentRoots;
137 QVector<
int> m_objectsWithAliases;
138 QVector<CompiledBinding *> m_generalizedGroupProperties;
139 QSet<
const QV4::CompiledData::Alias *> resolvedAliases;
140 typename ObjectContainer::IdToObjectMap m_idToObjectIndex;
143template<
typename ObjectContainer>
145 ObjectContainer *compiler,
146 QQmlPropertyCacheVector *propertyCaches)
147 : m_compiler(compiler)
152template<
typename ObjectContainer>
154 const CompiledObject *obj,
const QQmlPropertyCache::ConstPtr &propertyCache)
156 QQmlPropertyResolver propertyResolver(propertyCache);
158 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
159 ? propertyCache->parent()->defaultProperty()
160 : propertyCache->defaultProperty();
162 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
163 if (binding->type() != QV4::CompiledData::Binding::Type_Object)
165 if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
168 auto targetObject = m_compiler->objectAt(binding->value.objectIndex);
169 auto typeReference = resolvedType(targetObject->inheritedTypeNameIndex);
170 Q_ASSERT(typeReference);
172 const QMetaObject *firstMetaObject =
nullptr;
173 if (
const auto propCache = typeReference->typePropertyCache())
174 firstMetaObject = propCache->firstCppMetaObject();
175 if (isUsableComponent(firstMetaObject))
179 const QQmlPropertyData *pd =
nullptr;
180 if (binding->propertyNameIndex != quint32(0)) {
181 bool notInRevision =
false;
182 pd = propertyResolver.property(stringAt(binding->propertyNameIndex), ¬InRevision);
184 pd = defaultProperty;
186 if (!pd || !pd->isQObject())
192 QQmlPropertyCache::ConstPtr pc = pd->typeVersion().hasMinorVersion()
193 ? QQmlMetaType::rawPropertyCacheForType(pd->propType(), pd->typeVersion())
194 : QQmlMetaType::rawPropertyCacheForType(pd->propType());
195 const QMetaObject *mo = pc ? pc->firstCppMetaObject() :
nullptr;
197 if (mo == &QQmlComponent::staticMetaObject)
199 mo = mo->superClass();
205 if (!wrapImplicitComponent(binding))
206 return error(binding, QQmlComponentAndAliasResolverBase::tr(
"Cannot wrap implicit component"));
212template<
typename ObjectContainer>
219 const auto rootObj = m_compiler->objectAt(root);
220 Q_ASSERT(rootObj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot));
222 if (
const int typeName = rootObj->inheritedTypeNameIndex) {
223 const auto *tref = resolvedType(typeName);
225 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject) {
226 qCWarning(lcQmlTypeCompiler).nospace().noquote()
227 << m_compiler->url().toString() <<
":" << rootObj->location.line() <<
":"
228 << rootObj->location.column()
229 <<
": Using a Component as the root of an inline component is deprecated: "
230 "inline components are "
231 "automatically wrapped into Components when needed.";
236 const QQmlPropertyCache::ConstPtr rootCache = m_propertyCaches->at(root);
239 return findAndRegisterImplicitComponents(rootObj, rootCache);
243template<
typename ObjectContainer>
250 const int objCountWithoutSynthesizedComponents = m_compiler->objectCount();
253 const QQmlError error = resolveComponentsInInlineComponentRoot(root);
259 const int startObjectIndex = root == 0 ? root : root+1;
261 for (
int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
262 auto obj = m_compiler->objectAt(i);
263 const bool isInlineComponentRoot
264 = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
265 const bool isPartOfInlineComponent
266 = obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
267 QQmlPropertyCache::ConstPtr cache = m_propertyCaches->at(i);
271 if (isInlineComponentRoot || isPartOfInlineComponent)
273 }
else if (!isPartOfInlineComponent || isInlineComponentRoot) {
281 if (obj->inheritedTypeNameIndex == 0 && !cache)
284 bool isExplicitComponent =
false;
285 if (obj->inheritedTypeNameIndex) {
286 auto *tref = resolvedType(obj->inheritedTypeNameIndex);
288 if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
289 isExplicitComponent =
true;
292 if (!isExplicitComponent) {
294 const QQmlError error = findAndRegisterImplicitComponents(obj, cache);
301 if (!markAsComponent(i))
302 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot mark object as component"));
306 if (isExplicitComponent)
307 qCWarning(lcQmlTypeCompiler).nospace().noquote()
308 << m_compiler->url().toString() <<
":" << obj->location.line() <<
":"
309 << obj->location.column()
310 <<
": Using a Component as the root of a QML document is deprecated: types "
311 "defined in qml documents are "
312 "automatically wrapped into Components when needed.";
315 if (obj->functionCount() > 0)
316 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new functions."));
317 if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
318 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new properties."));
319 if (obj->signalCount() > 0)
320 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Component objects cannot declare new signals."));
322 if (obj->bindingCount() == 0)
323 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Cannot create empty component specification"));
325 const auto rootBinding = obj->bindingsBegin();
326 const auto bindingsEnd = obj->bindingsEnd();
330 for (
auto b = rootBinding; b != bindingsEnd; ++b) {
331 if (b->propertyNameIndex == 0)
334 return error(b, QQmlComponentAndAliasResolverBase::tr(
"Component elements may not contain properties other than id"));
337 if (
auto b = rootBinding;
338 b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
339 return error(obj, QQmlComponentAndAliasResolverBase::tr(
"Invalid component body specification"));
345 m_componentRoots.append(i);
348 for (
int i = 0; i < m_componentRoots.size(); ++i) {
349 CompiledObject *component = m_compiler->objectAt(m_componentRoots.at(i));
350 const auto rootBinding = component->bindingsBegin();
352 m_idToObjectIndex.clear();
353 m_objectsWithAliases.clear();
354 m_generalizedGroupProperties.clear();
356 if (
const QQmlError error = collectIdsAndAliases(rootBinding->value.objectIndex);
361 allocateNamedObjects(component);
363 if (
const QQmlError error = resolveAliases(m_componentRoots.at(i)); error.isValid())
366 resolveGeneralizedGroupProperties(m_componentRoots.at(i));
370 m_idToObjectIndex.clear();
371 m_objectsWithAliases.clear();
372 m_generalizedGroupProperties.clear();
374 if (
const QQmlError error = collectIdsAndAliases(root); error.isValid())
377 allocateNamedObjects(m_compiler->objectAt(root));
378 if (
const QQmlError error = resolveAliases(root); error.isValid())
381 resolveGeneralizedGroupProperties(root);
385template<
typename ObjectContainer>
388 auto obj = m_compiler->objectAt(objectIndex);
390 if (obj->idNameIndex != 0) {
391 if (m_idToObjectIndex.contains(obj->idNameIndex))
392 return error(obj->locationOfIdProperty, QQmlComponentAndAliasResolverBase::tr(
"id is not unique"));
393 setObjectId(objectIndex);
394 m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
397 if (obj->aliasCount() > 0)
398 m_objectsWithAliases.append(objectIndex);
401 if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != 0)
404 for (
auto binding = obj->bindingsBegin(), end = obj->bindingsEnd();
405 binding != end; ++binding) {
406 switch (binding->type()) {
407 case QV4::CompiledData::Binding::Type_GroupProperty: {
408 const auto *inner = m_compiler->objectAt(binding->value.objectIndex);
409 if (m_compiler->stringAt(inner->inheritedTypeNameIndex).isEmpty()) {
410 const auto cache = m_propertyCaches->at(objectIndex);
411 if (!cache || !cache->property(
412 m_compiler->stringAt(binding->propertyNameIndex),
nullptr,
nullptr)) {
413 m_generalizedGroupProperties.append(binding);
418 case QV4::CompiledData::Binding::Type_Object:
419 case QV4::CompiledData::Binding::Type_AttachedProperty:
420 if (
const QQmlError error = collectIdsAndAliases(binding->value.objectIndex);
433template<
typename ObjectContainer>
436 if (m_objectsWithAliases.isEmpty())
439 QQmlPropertyCacheAliasCreator<ObjectContainer> aliasCacheCreator(m_propertyCaches, m_compiler);
441 bool atLeastOneAliasResolved;
443 atLeastOneAliasResolved =
false;
444 QVector<
int> pendingObjects;
446 for (
int objectIndex: std::as_const(m_objectsWithAliases)) {
449 const auto &component = *m_compiler->objectAt(componentIndex);
451 = resolveAliasesInObject(component, objectIndex, &aliasCacheCreator, &error);
455 if (result == AllAliasesResolved) {
456 atLeastOneAliasResolved =
true;
457 }
else if (result == SomeAliasesResolved) {
458 atLeastOneAliasResolved =
true;
459 pendingObjects.append(objectIndex);
461 pendingObjects.append(objectIndex);
464 qSwap(m_objectsWithAliases, pendingObjects);
465 }
while (!m_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
467 if (!atLeastOneAliasResolved && !m_objectsWithAliases.isEmpty()) {
468 const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
469 for (
auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
470 if (!resolvedAliases.contains(alias))
471 return error(alias->location, QQmlComponentAndAliasResolverBase::tr(
"Circular alias reference detected"));
478template<
typename ObjectContainer>
482 const auto &component = *m_compiler->objectAt(componentIndex);
483 for (CompiledBinding *binding : m_generalizedGroupProperties)
484 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(lcEventDispatcher)