Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmlpropertycachecreator_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QQMLPROPERTYCACHECREATOR_P_H
4#define QQMLPROPERTYCACHECREATOR_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qqmlvaluetype_p.h>
18#include <private/qqmlengine_p.h>
19#include <private/qqmlmetaobject_p.h>
20#include <private/qqmlpropertyresolver_p.h>
21#include <private/qqmltypedata_p.h>
22#include <private/inlinecomponentutils_p.h>
23#include <private/qqmlsourcecoordinate_p.h>
24
25#include <QScopedValueRollback>
26#include <vector>
27
29
31 const QString &description)
32{
36 error.setDescription(description);
37 return error;
38}
39
46
49
55};
56
57struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext>
58{
60 QQmlPropertyCacheVector *propertyCaches) const;
61};
62
64{
66public:
68
71
72 static bool canCreateClassNameTypeByUrl(const QUrl &url);
74
76
78 // valid if and only if an error occurred
80 // true if there was no error and there are still components left to process
81 bool canResume = false;
82 // the object index of the last processed (inline) component root.
84 };
85};
86
87template <typename ObjectContainer>
89{
90public:
91 using CompiledObject = typename ObjectContainer::CompiledObject;
92 using InlineComponent = typename std::remove_reference<decltype (*(std::declval<CompiledObject>().inlineComponentsBegin()))>::type;
93
97 const ObjectContainer *objectContainer, const QQmlImports *imports,
100
101
110 IncrementalResult buildMetaObjectsIncrementally();
111
118
120 Maybe,
121 Always
122 };
123protected:
126 QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache);
127
129
130 QString stringAt(int index) const { return objectContainer->stringAt(index); }
131
133 const ObjectContainer * const objectContainer;
134 const QQmlImports * const imports;
137 QByteArray typeClassName; // not const as we temporarily chang it for inline components
138 unsigned int currentRoot; // set to objectID of inline component root when handling inline components
139
141 std::vector<InlineComponent> allICs;
142 std::vector<icutils::Node> nodesSorted;
143 std::vector<icutils::Node>::reverse_iterator nodeIt = nodesSorted.rbegin();
144 bool hasCycle = false;
145};
146
147template <typename ObjectContainer>
149 QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
150 QQmlEnginePrivate *enginePrivate,
151 const ObjectContainer *objectContainer, const QQmlImports *imports,
152 const QByteArray &typeClassName)
153 : enginePrivate(enginePrivate)
154 , objectContainer(objectContainer)
155 , imports(imports)
156 , propertyCaches(propertyCaches)
157 , pendingGroupPropertyBindings(pendingGroupPropertyBindings)
158 , typeClassName(typeClassName)
159 , currentRoot(-1)
160{
162
163 using namespace icutils;
164
165 // get a list of all inline components
166
167 for (int i=0; i != objectContainer->objectCount(); ++i) {
168 const CompiledObject *obj = objectContainer->objectAt(i);
169 for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
170 allICs.push_back(*it);
171 }
172 }
173
174 // create a graph on inline components referencing inline components
175 std::vector<icutils::Node> nodes;
176 nodes.resize(allICs.size());
177 std::iota(nodes.begin(), nodes.end(), 0);
178 AdjacencyList adjacencyList;
179 adjacencyList.resize(nodes.size());
180 fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
181
182 nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
183 nodeIt = nodesSorted.rbegin();
184}
185
186template <typename ObjectContainer>
188{
189 if (hasCycle) {
190 QQmlError diag;
191 diag.setDescription(QLatin1String("Inline components form a cycle!"));
192 return diag;
193 }
194 return {};
195}
196
197template <typename ObjectContainer>
200{
201 // needs to be checked with verifyNoICCycle before this function is called
202 Q_ASSERT(!hasCycle);
203
204 // create meta objects for inline components before compiling actual root component
205 if (nodeIt != nodesSorted.rend()) {
206 const auto &ic = allICs[nodeIt->index()];
207 QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
208 Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
209 Q_ASSERT(typeRef->typePropertyCache().isNull()); // not set yet
210
211 QByteArray icTypeName { objectContainer->stringAt(ic.nameIndex).toUtf8() };
212 QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
213 QScopedValueRollback<unsigned int> rootChange {currentRoot, ic.objectIndex};
214 ++nodeIt;
215 QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
216 if (diag.isValid()) {
217 return {diag, false, 0};
218 }
219 typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
220 Q_ASSERT(!typeRef->typePropertyCache().isNull());
221 return { QQmlError(), true, int(ic.objectIndex) };
222 }
223
224 auto diag = buildMetaObjectRecursively(/*root object*/0, m_context, VMEMetaObjectIsRequired::Maybe);
225 return {diag, false, 0};
226}
227
228template <typename ObjectContainer>
230{
231 auto isAddressable = [](const QUrl &url) {
232 const QString fileName = url.fileName();
233 return !fileName.isEmpty() && fileName.front().isUpper();
234 };
235
236 const CompiledObject *obj = objectContainer->objectAt(objectIndex);
237 bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
238 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
240 || (objectIndex == 0 && isAddressable(objectContainer->url())))
241 && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
242
243 if (!needVMEMetaObject) {
244 auto binding = obj->bindingsBegin();
245 auto end = obj->bindingsEnd();
246 for ( ; binding != end; ++binding) {
247 if (binding->type() == QV4::CompiledData::Binding::Type_Object
248 && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
249 // If the on assignment is inside a group property, we need to distinguish between QObject based
250 // group properties and value type group properties. For the former the base type is derived from
251 // the property that references us, for the latter we only need a meta-object on the referencing object
252 // because interceptors can't go to the shared value type instances.
253 if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
254 if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
255 const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
256 auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
257 Q_ASSERT(typeRef);
258 QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
259 QQmlError error = baseTypeCache
260 ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
261 : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
262 "Type cannot be used for 'on' assignment"));
263 if (error.isValid())
264 return error;
265 }
266 } else {
267 // On assignments are implemented using value interceptors, which require a VME meta object.
268 needVMEMetaObject = true;
269 }
270 break;
271 }
272 }
273 }
274
275 QQmlPropertyCache::ConstPtr baseTypeCache;
276 {
278 baseTypeCache = propertyCacheForObject(obj, context, &error);
279 if (error.isValid())
280 return error;
281 }
282
283 if (baseTypeCache) {
284 if (needVMEMetaObject) {
285 QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
286 if (error.isValid())
287 return error;
288 } else {
289 propertyCaches->set(objectIndex, baseTypeCache);
290 }
291 }
292
293 QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
294 auto binding = obj->bindingsBegin();
295 auto end = obj->bindingsEnd();
296 for (; binding != end; ++binding) {
297 switch (binding->type()) {
301 // We can always resolve object, group, and attached properties.
302 break;
303 default:
304 // Everything else is of no interest here.
305 continue;
306 }
307
309 objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
310
311 // Binding to group property where we failed to look up the type of the
312 // property? Possibly a group property that is an alias that's not resolved yet.
313 // Let's attempt to resolve it after we're done with the aliases and fill in the
314 // propertyCaches entry then.
315 if (!thisCache || !context.resolveInstantiatingProperty())
316 pendingGroupPropertyBindings->append(context);
317
318 QQmlError error = buildMetaObjectRecursively(
319 binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
320 if (error.isValid())
321 return error;
322 }
323
324 QQmlError noError;
325 return noError;
326}
327
328template <typename ObjectContainer>
330{
331 if (context.instantiatingProperty) {
332 return context.instantiatingPropertyCache();
333 } else if (obj->inheritedTypeNameIndex != 0) {
334 auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
335 Q_ASSERT(typeRef);
336
337 if (typeRef->isFullyDynamicType()) {
338 if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
339 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
340 return nullptr;
341 }
342 if (obj->signalCount() > 0) {
343 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals."));
344 return nullptr;
345 }
346 if (obj->functionCount() > 0) {
347 *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions."));
348 return nullptr;
349 }
350 }
351
352 if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
353 return propertyCache;
355 obj->location,
356 QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.")
357 .arg(stringAt(obj->inheritedTypeNameIndex)));
358 return nullptr;
359 } else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
360 if (binding->isAttachedProperty()) {
361 auto *typeRef = objectContainer->resolvedType(
362 binding->propertyNameIndex);
363 Q_ASSERT(typeRef);
364 QQmlType qmltype = typeRef->type();
365 if (!qmltype.isValid()) {
366 imports->resolveType(stringAt(binding->propertyNameIndex),
367 &qmltype, nullptr, nullptr, nullptr);
368 }
369
370 const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
371 if (!attachedMo) {
372 *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
373 return nullptr;
374 }
375 return QQmlMetaType::propertyCache(attachedMo);
376 } else if (binding->isGroupProperty()) {
377 const auto *obj = objectContainer->objectAt(binding->value.objectIndex);
378 if (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
379 return nullptr;
380
381 for (int i = 0, end = objectContainer->objectCount(); i != end; ++i) {
382 const auto *ext = objectContainer->objectAt(i);
383 if (ext->idNameIndex != binding->propertyNameIndex)
384 continue;
385
386 if (ext->inheritedTypeNameIndex == 0)
387 return nullptr;
388
389 QQmlBindingInstantiationContext pendingContext(i, &(*binding), QString(), nullptr);
390 pendingGroupPropertyBindings->append(pendingContext);
391 return nullptr;
392 }
393 }
394 }
395 return nullptr;
396}
397
398template <typename ObjectContainer>
400 int objectIndex, const CompiledObject *obj,
401 const QQmlPropertyCache::ConstPtr &baseTypeCache)
402{
403 QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
404 obj->propertyCount() + obj->aliasCount(),
405 obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
406 obj->signalCount() + obj->propertyCount() + obj->aliasCount(),
407 obj->enumCount());
408
409 propertyCaches->setOwn(objectIndex, cache);
410 propertyCaches->setNeedsVMEMetaObject(objectIndex);
411
412 QByteArray newClassName;
413
414 if (objectIndex == /*root object*/0 || int(currentRoot) == objectIndex) {
415 newClassName = typeClassName;
416 }
417 if (newClassName.isEmpty()) {
418 newClassName = QQmlMetaObject(baseTypeCache).className();
419 newClassName.append("_QML_");
420 newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
421 }
422
423 cache->_dynamicClassName = newClassName;
424
425 using ListPropertyAssignBehavior = typename ObjectContainer::ListPropertyAssignBehavior;
426 switch (objectContainer->listPropertyAssignBehavior()) {
427 case ListPropertyAssignBehavior::ReplaceIfNotDefault:
428 cache->_listPropertyAssignBehavior = "ReplaceIfNotDefault";
429 break;
430 case ListPropertyAssignBehavior::Replace:
431 cache->_listPropertyAssignBehavior = "Replace";
432 break;
433 case ListPropertyAssignBehavior::Append:
434 break;
435 }
436
437 QQmlPropertyResolver resolver(baseTypeCache);
438
439 auto p = obj->propertiesBegin();
440 auto pend = obj->propertiesEnd();
441 for ( ; p != pend; ++p) {
442 bool notInRevision = false;
443 const QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
444 if (d && d->isFinal())
445 return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
446 }
447
448 auto a = obj->aliasesBegin();
449 auto aend = obj->aliasesEnd();
450 for ( ; a != aend; ++a) {
451 bool notInRevision = false;
452 const QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), &notInRevision);
453 if (d && d->isFinal())
454 return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
455 }
456
457 int effectivePropertyIndex = cache->propertyIndexCacheStart;
458 int effectiveMethodIndex = cache->methodIndexCacheStart;
459
460 // For property change signal override detection.
461 // We prepopulate a set of signal names which already exist in the object,
462 // and throw an error if there is a signal/method defined as an override.
463 QSet<QString> seenSignals;
464 seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
465 const QQmlPropertyCache *parentCache = cache.data();
466 while ((parentCache = parentCache->parent().data())) {
467 if (int pSigCount = parentCache->signalCount()) {
468 int pSigOffset = parentCache->signalOffset();
469 for (int i = pSigOffset; i < pSigCount; ++i) {
470 const QQmlPropertyData *currPSig = parentCache->signal(i);
471 // XXX TODO: find a better way to get signal name from the property data :-/
472 for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
473 iter != parentCache->stringCache.end(); ++iter) {
474 if (currPSig == (*iter).second) {
475 seenSignals.insert(iter.key());
476 break;
477 }
478 }
479 }
480 }
481 }
482
483 // Set up notify signals for properties - first normal, then alias
484 p = obj->propertiesBegin();
485 pend = obj->propertiesEnd();
486 for ( ; p != pend; ++p) {
488
489 QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
490 seenSignals.insert(changedSigName);
491
492 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
493 }
494
495 a = obj->aliasesBegin();
496 aend = obj->aliasesEnd();
497 for ( ; a != aend; ++a) {
499
500 QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed");
501 seenSignals.insert(changedSigName);
502
503 cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
504 }
505
506 auto e = obj->enumsBegin();
507 auto eend = obj->enumsEnd();
508 for ( ; e != eend; ++e) {
509 const int enumValueCount = e->enumValueCount();
511 values.reserve(enumValueCount);
512
513 auto enumValue = e->enumValuesBegin();
514 auto end = e->enumValuesEnd();
515 for ( ; enumValue != end; ++enumValue)
516 values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
517
518 cache->appendEnum(stringAt(e->nameIndex), values);
519 }
520
521 // Dynamic signals
522 auto s = obj->signalsBegin();
523 auto send = obj->signalsEnd();
524 for ( ; s != send; ++s) {
525 const int paramCount = s->parameterCount();
526
528 names.reserve(paramCount);
529 QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
530
531 if (paramCount) {
532
533 int i = 0;
534 auto param = s->parametersBegin();
535 auto end = s->parametersEnd();
536 for ( ; param != end; ++param, ++i) {
537 names.append(stringAt(param->nameIndex).toUtf8());
538
539 QString customTypeName;
540 QMetaType type = metaTypeForParameter(param->type, &customTypeName);
541 if (!type.isValid())
542 return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
543
544 paramTypes[i] = type;
545 }
546 }
547
549 if (paramCount)
550 flags.setHasArguments(true);
551
552 QString signalName = stringAt(s->nameIndex);
553 if (seenSignals.contains(signalName))
554 return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
555 seenSignals.insert(signalName);
556
557 cache->appendSignal(signalName, flags, effectiveMethodIndex++,
558 paramCount?paramTypes.constData():nullptr, names);
559 }
560
561
562 // Dynamic slots
563 auto function = objectContainer->objectFunctionsBegin(obj);
564 auto fend = objectContainer->objectFunctionsEnd(obj);
565 for ( ; function != fend; ++function) {
567
568 const QString slotName = stringAt(function->nameIndex);
569 if (seenSignals.contains(slotName))
570 return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
571 // Note: we don't append slotName to the seenSignals list, since we don't
572 // protect against overriding change signals or methods with properties.
573
574 QList<QByteArray> parameterNames;
575 QVector<QMetaType> parameterTypes;
576 auto formal = function->formalsBegin();
577 auto end = function->formalsEnd();
578 for ( ; formal != end; ++formal) {
579 flags.setHasArguments(true);
580 parameterNames << stringAt(formal->nameIndex).toUtf8();
581 QMetaType type = metaTypeForParameter(formal->type);
582 if (!type.isValid())
583 type = QMetaType::fromType<QVariant>();
584 parameterTypes << type;
585 }
586
587 QMetaType returnType = metaTypeForParameter(function->returnType);
588 if (!returnType.isValid())
589 returnType = QMetaType::fromType<QVariant>();
590
591 cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes);
592 }
593
594
595 // Dynamic properties
596 int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
597 int propertyIdx = 0;
598 p = obj->propertiesBegin();
599 pend = obj->propertiesEnd();
600 for ( ; p != pend; ++p, ++propertyIdx) {
601 QMetaType propertyType;
602 QTypeRevision propertyTypeVersion = QTypeRevision::zero();
603 QQmlPropertyData::Flags propertyFlags;
604
605 const QV4::CompiledData::CommonType type = p->commonType();
606
607 if (p->isList())
608 propertyFlags.type = QQmlPropertyData::Flags::QListType;
610 propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
611
613 propertyType = p->isList()
614 ? listTypeForPropertyType(type)
615 : metaTypeForPropertyType(type);
616 } else {
617 Q_ASSERT(!p->isCommonType());
618
619 QQmlType qmltype;
620 bool selfReference = false;
621 if (!imports->resolveType(
622 stringAt(p->commonTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
623 nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
624 return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
625 }
626
627 // inline components are not necessarily valid yet
628 Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
629 if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
630 QQmlType compositeType;
631 if (qmltype.isInlineComponentType()) {
632 const QString icName = qmltype.elementName();
634 qmltype.sourceUrl(), icName);
635 if (!compositeType.isValid()) // type has not been registered yet, we must be in containing type
636 compositeType = objectContainer->qmlTypeForComponent(icName);
637 Q_ASSERT(compositeType.isValid());
638 } else if (selfReference) {
639 compositeType = objectContainer->qmlTypeForComponent();
640 } else {
641 QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
642 Q_ASSERT(tdata);
643 Q_ASSERT(tdata->isComplete());
644
645 auto compilationUnit = tdata->compilationUnit();
646 compositeType = compilationUnit->qmlTypeForComponent();
647 }
648
649 if (p->isList()) {
650 propertyType = compositeType.qListTypeId();
651 } else {
652 propertyType = compositeType.typeId();
653 }
654 } else {
655 if (p->isList())
656 propertyType = qmltype.qListTypeId();
657 else
658 propertyType = qmltype.typeId();
659 propertyTypeVersion = qmltype.version();
660 }
661
662 if (p->isList())
663 propertyFlags.type = QQmlPropertyData::Flags::QListType;
664 else if (propertyType.flags().testFlag(QMetaType::PointerToQObject))
665 propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
666 else
667 propertyFlags.type = QQmlPropertyData::Flags::ValueType;
668 }
669
670 if (!p->isReadOnly() && !propertyType.flags().testFlag(QMetaType::IsQmlList))
671 propertyFlags.setIsWritable(true);
672
673
674 QString propertyName = stringAt(p->nameIndex);
675 if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
676 cache->_defaultPropertyName = propertyName;
677 cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
678 propertyType, propertyTypeVersion, effectiveSignalIndex);
679
680 effectiveSignalIndex++;
681 }
682
683 QQmlError noError;
684 return noError;
685}
686
687template <typename ObjectContainer>
689 const QV4::CompiledData::ParameterType &param, QString *customTypeName)
690{
691 const quint32 typeId = param.typeNameIndexOrCommonType();
692 if (param.indexIsCommonType()) {
693 // built-in type
694 if (param.isList())
695 return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
696 return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
697 }
698
699 // lazily resolved type
700 const QString typeName = stringAt(param.typeNameIndexOrCommonType());
701 if (customTypeName)
702 *customTypeName = typeName;
703 QQmlType qmltype;
704 bool selfReference = false;
705 if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr,
706 QQmlType::AnyRegistrationType, &selfReference))
707 return QMetaType();
708
709 if (!qmltype.isComposite()) {
710 const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
711 if (!typeId.isValid() && qmltype.isInlineComponentType()) {
712 const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
713 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
714 } else {
715 return typeId;
716 }
717 }
718
719 if (selfReference) {
720 const QQmlType qmlType = objectContainer->qmlTypeForComponent();
721 return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
722 }
723
724 QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
725 Q_ASSERT(tdata);
726 Q_ASSERT(tdata->isComplete());
727
728 auto compilationUnit = tdata->compilationUnit();
729
730 return param.isList()
731 ? compilationUnit->qmlType.qListTypeId()
732 : compilationUnit->qmlType.typeId();
733}
734
735template <typename ObjectContainer>
737{
738public:
739 typedef typename ObjectContainer::CompiledObject CompiledObject;
740
742 QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
744 const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
745
746private:
747 QQmlError propertyDataForAlias(
749 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
750 QQmlEnginePrivate *enginePriv);
751 int objectForId(const CompiledObject &component, int id) const;
752
753 QQmlPropertyCacheVector *propertyCaches;
754 const ObjectContainer *objectContainer;
755};
756
757template <typename ObjectContainer>
759 QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
760 : propertyCaches(propertyCaches)
761 , objectContainer(objectContainer)
762{
763}
764
765template <typename ObjectContainer>
767 const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
768 QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
769 QQmlEnginePrivate *enginePriv)
770{
771 *type = QMetaType();
772 bool writable = false;
773 bool resettable = false;
774 bool bindable = false;
775
776 propertyFlags->setIsAlias(true);
777
778 if (alias.isAliasToLocalAlias()) {
779 const QV4::CompiledData::Alias *lastAlias = &alias;
781
782 do {
783 const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId());
784 Q_ASSERT(targetObjectIndex >= 0);
785 const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
786 Q_ASSERT(targetObject);
787
788 auto nextAlias = targetObject->aliasesBegin();
789 for (uint i = 0; i < lastAlias->localAliasIndex; ++i)
790 ++nextAlias;
791
792 const QV4::CompiledData::Alias *targetAlias = &(*nextAlias);
793 if (seenAliases.contains(targetAlias)) {
794 return qQmlCompileError(targetAlias->location,
795 QQmlPropertyCacheCreatorBase::tr("Cyclic alias"));
796 }
797
798 seenAliases.append(targetAlias);
799 lastAlias = targetAlias;
800 } while (lastAlias->isAliasToLocalAlias());
801
802 return propertyDataForAlias(
803 component, *lastAlias, type, version, propertyFlags, enginePriv);
804 }
805
806 const int targetObjectIndex = objectForId(component, alias.targetObjectId());
807 Q_ASSERT(targetObjectIndex >= 0);
808 const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
809
810 if (alias.encodedMetaPropertyIndex == -1) {
812 auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
813 if (!typeRef) {
814 // Can be caused by the alias target not being a valid id or property. E.g.:
815 // property alias dataValue: dataVal
816 // invalidAliasComponent { id: dataVal }
817 return qQmlCompileError(targetObject.location,
818 QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
819 }
820
821 const auto referencedType = typeRef->type();
822 if (referencedType.isValid()) {
823 *type = referencedType.typeId();
824 if (!type->isValid() && referencedType.isInlineComponentType()) {
825 *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
826 Q_ASSERT(type->isValid());
827 }
828 } else {
829 *type = typeRef->compilationUnit()->qmlType.typeId();
830 }
831
832 *version = typeRef->version();
833
835 } else {
837 int valueTypeIndex = QQmlPropertyIndex::fromEncoded(
839
840 QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
841 Q_ASSERT(targetCache);
842
843 const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
844 Q_ASSERT(targetProperty);
845
846 // for deep aliases, valueTypeIndex is always set
847 if (!QQmlMetaType::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
848 // deep alias property
849 *type = targetProperty->propType();
851 Q_ASSERT(typeCache);
852 const QQmlPropertyData *typeProperty = typeCache->property(valueTypeIndex);
853
854 if (typeProperty == nullptr) {
856 QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
857 }
858
859 *type = typeProperty->propType();
860 writable = typeProperty->isWritable();
861 resettable = typeProperty->isResettable();
862 bindable = typeProperty->isBindable();
863 } else {
864 // value type or primitive type or enum
865 *type = targetProperty->propType();
866
867 writable = targetProperty->isWritable();
868 resettable = targetProperty->isResettable();
869 bindable = targetProperty->isBindable();
870
871 if (valueTypeIndex != -1) {
872 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(*type);
873 if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
874 *type = QMetaType::fromType<int>();
875 else
876 *type = valueTypeMetaObject->property(valueTypeIndex).metaType();
877 } else {
878 if (targetProperty->isEnum()) {
879 *type = QMetaType::fromType<int>();
880 } else {
881 // Copy type flags
882 propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
883
884 if (targetProperty->isVarProperty())
886 }
887 }
888 }
889 }
890
892 && writable);
893 propertyFlags->setIsResettable(resettable);
894 propertyFlags->setIsBindable(bindable);
895 return QQmlError();
896}
897
898template <typename ObjectContainer>
900 const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
901{
902 const CompiledObject &object = *objectContainer->objectAt(objectIndex);
903 if (!object.aliasCount())
904 return QQmlError();
905
906 QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
907 Q_ASSERT(propertyCache);
908
909 int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
910 int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
911
912 int aliasIndex = 0;
913 auto alias = object.aliasesBegin();
914 auto end = object.aliasesEnd();
915 for ( ; alias != end; ++alias, ++aliasIndex) {
917
920 QQmlPropertyData::Flags propertyFlags;
921 QQmlError error = propertyDataForAlias(component, *alias, &type, &version,
922 &propertyFlags, enginePriv);
923 if (error.isValid())
924 return error;
925
926 const QString propertyName = objectContainer->stringAt(alias->nameIndex());
927
928 if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
929 propertyCache->_defaultPropertyName = propertyName;
930
931 propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
932 type, version, effectiveSignalIndex++);
933 }
934
935 return QQmlError();
936}
937
938template <typename ObjectContainer>
939inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
940{
941 for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
942 const int candidateIndex = component.namedObjectsInComponentTable()[i];
943 const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
944 if (candidate.objectId() == id)
945 return candidateIndex;
946 }
947 return -1;
948}
949
951
952#endif // QQMLPROPERTYCACHECREATOR_P_H
\inmodule QtCore
Definition qatomic.h:112
\inmodule QtCore
Definition qbytearray.h:57
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
ConstIterator end() const
ConstIterator begin() const
typename QLinkedStringHash< QPair< int, QQmlPropertyData * > >::ConstIterator ConstIterator
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
void append(parameter_type t)
Definition qlist.h:441
QMetaType metaType() const
bool isEnumType() const
Returns true if the property's type is an enumeration value; otherwise returns false.
\inmodule QtCore
Definition qmetatype.h:320
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
bool isValid() const
@ PointerToQObject
Definition qmetatype.h:385
QQmlTypeLoader typeLoader
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
void setDescription(const QString &)
Sets the error description.
bool isValid() const
Returns true if this error is valid, otherwise false.
The QQmlImports class encapsulates one QML document's import statements.
bool resolveType(const QHashedStringRef &type, QQmlType *type_return, QTypeRevision *version_return, QQmlImportNamespace **ns_return, QList< QQmlError > *errors=nullptr, QQmlType::RegistrationType registrationType=QQmlType::AnyRegistrationType, bool *typeRecursionDetected=nullptr) const
const char * className() const
static const QMetaObject * metaObjectForValueType(QMetaType type)
static QQmlType inlineComponentTypeForUrl(const QUrl &url)
static QQmlPropertyCache::ConstPtr propertyCache(QObject *object, QTypeRevision version=QTypeRevision())
Returns a QQmlPropertyCache for obj if one is available.
static bool isValueType(QMetaType type)
static QQmlPropertyCache::ConstPtr propertyCacheForType(QMetaType metaType)
QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
QQmlError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
ObjectContainer::CompiledObject CompiledObject
QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName=nullptr)
IncrementalResult buildMetaObjectsIncrementally()
typename ObjectContainer::CompiledObject CompiledObject
QString stringAt(int index) const
QQmlEnginePrivate *const enginePrivate
QQmlBindingInstantiationContext m_context
QQmlPendingGroupPropertyBindings * pendingGroupPropertyBindings
QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache)
typename std::remove_reference< decltype(*(std::declval< CompiledObject >().inlineComponentsBegin()))>::type InlineComponent
const ObjectContainer *const objectContainer
std::vector< icutils::Node >::reverse_iterator nodeIt
QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports, const QByteArray &typeClassName)
std::vector< InlineComponent > allICs
QQmlPropertyCacheVector * propertyCaches
std::vector< icutils::Node > nodesSorted
QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const
bool needsVMEMetaObject(int index) const
QQmlPropertyCache::ConstPtr at(int index) const
void set(int index, const QQmlPropertyCache::ConstPtr &replacement)
void setOwn(int index, const QQmlPropertyCache::Ptr &replacement)
QQmlPropertyCache::Ptr ownAt(int index) const
const QQmlPropertyData * signal(int index) const
const QQmlPropertyCache::ConstPtr & parent() const
void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex, QMetaType propType, QTypeRevision revision, int notifyIndex)
bool isResettable() const
bool isVarProperty() const
QMetaType propType() const
static Flags defaultSlotFlags()
static Flags defaultSignalFlags()
static QQmlPropertyIndex fromEncoded(qint32 encodedIndex)
T * data() const
bool isNull() const
QQmlRefPointer< QQmlTypeData > getType(const QUrl &unNormalizedUrl, Mode mode=PreferSynchronous)
Returns a QQmlTypeData for the specified url.
@ AnyRegistrationType
Definition qqmltype_p.h:158
QTypeRevision version() const
Definition qqmltype.cpp:112
QMetaType typeId() const
Definition qqmltype.cpp:643
const QMetaObject * attachedPropertiesType(QQmlEnginePrivate *engine) const
Definition qqmltype.cpp:692
QMetaType qListTypeId() const
Definition qqmltype.cpp:648
QUrl sourceUrl() const
Definition qqmltype.cpp:743
bool isComposite() const
Definition qqmltype.cpp:614
bool isValid() const
Definition qqmltype_p.h:58
bool isInlineComponentType() const
Definition qqmltype.cpp:739
QString elementName() const
Definition qqmltype.cpp:442
Definition qset.h:18
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore
static constexpr QTypeRevision zero()
Produces a QTypeRevision with major and minor version {0}.
\inmodule QtCore
Definition qurl.h:94
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2494
QQmlPropertyCache::ConstPtr typePropertyCache() const
void setTypePropertyCache(QQmlPropertyCache::ConstPtr cache)
const T * constData() const
double e
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
std::vector< std::vector< Node * > > AdjacencyList
static void * context
#define Q_DECLARE_TR_FUNCTIONS(context)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
const char * typeName
GLint location
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLenum type
GLbitfield flags
GLenum const GLint * param
GLuint name
GLhandleARB obj
[2]
GLuint GLuint * names
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
QT_BEGIN_NAMESPACE QQmlError qQmlCompileError(const QV4::CompiledData::Location &location, const QString &description)
int qmlConvertSourceCoordinate< quint32, int >(quint32 n)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_AUTOTEST_EXPORT
unsigned int quint32
Definition qtypes.h:45
unsigned int uint
Definition qtypes.h:29
QUrl url("example.com")
[constructor-url-reference]
QUrl baseUrl
\inmodule QtCore
QMetaProperty property(int index) const
Returns the meta-data for the property with the given index.
QQmlPropertyCache::ConstPtr referencingObjectPropertyCache
const QV4::CompiledData::Binding * instantiatingBinding
const QQmlPropertyData * instantiatingProperty
QQmlPropertyCache::ConstPtr instantiatingPropertyCache() const
void resolveMissingPropertyCaches(QQmlPropertyCacheVector *propertyCaches) const
static bool canCreateClassNameTypeByUrl(const QUrl &url)
static QByteArray createClassNameTypeByUrl(const QUrl &url)
static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type)
static QAtomicInt Q_AUTOTEST_EXPORT classIndexCounter
static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name)
static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type)
void copyPropertyTypeFlags(Flags from)
const QQmlPropertyData * property(int index) const
bool hasFlag(Flag flag) const