7#include <private/qqmlobjectcreator_p.h>
8#include <private/qqmlcustomparser_p.h>
9#include <private/qqmlvmemetaobject_p.h>
10#include <private/qqmlcomponent_p.h>
11#include <private/qqmlpropertyresolver_p.h>
12#include <private/qqmlcomponentandaliasresolver_p.h>
13#include <private/qqmlsignalnames_p.h>
15#include <QtCore/qtyperevision.h>
17#define COMPILE_EXCEPTION(token, desc)
19 recordError((token)->location, desc);
25DEFINE_BOOL_CONFIG_OPTION(
26 disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
31 QQmlTypeLoader *typeLoader, QQmlTypeData *typeData,
QmlIR::Document *parsedQML,
32 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
33 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
34 : resolvedTypes(resolvedTypeCache)
36 , dependencyHasher(dependencyHasher)
46 for (
auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
48 QQmlCustomParser *customParser = (*it)->type().customParser();
50 customParsers.insert(it.key(), customParser);
53 QQmlPendingGroupedPropertyBindings pendingGroupedPropertyBindings;
57 QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(
58 &m_propertyCaches, &pendingGroupedPropertyBindings,
59 loader,
this, imports(), typeData->typeClassName());
60 QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
61 if (cycleError.isValid()) {
65 QQmlPropertyCacheCreatorBase::IncrementalResult result;
67 result = propertyCacheBuilder.buildMetaObjectsIncrementally();
68 const QQmlError &error = result.error;
69 if (error.isValid()) {
75 QQmlComponentAndAliasResolver resolver(
this, &m_propertyCaches);
76 if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
80 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
81 pendingGroupedPropertyBindings.clear();
83 }
while (result.canResume);
91 Q_ASSERT(!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData());
101 Q_ASSERT(document->jsModule.fileName == typeData->urlString());
102 Q_ASSERT(document->jsModule.finalUrl == typeData->finalUrlString());
103 QmlIR::JSCodeGen v4CodeGenerator(document);
104 for (QmlIR::Object *object : std::as_const(document->objects)) {
105 if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
106 Q_ASSERT(v4CodeGenerator.hasError());
107 recordError(v4CodeGenerator.error());
111 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(
false);
116 QmlIR::QmlUnitGenerator qmlGenerator;
117 qmlGenerator.generate(*document, dependencyHasher);
119 if (!errors.isEmpty())
122 copyComponentsAndIds();
123 return std::move(document->javaScriptCompilationUnit);
129 CompilationUnit *unit = document->javaScriptCompilationUnit.data();
130 unit->allocateRuntimeData();
131 for (
int i = 0, count = document->objects.size(); i < count; ++i) {
132 const QmlIR::Object *object = document->objects.at(i);
134 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(i);
135 if (object->isComponent)
136 runtimeObject->flags |= RuntimeObject::IsComponent;
137 runtimeObject->objectId = object->id;
140 std::copy(object->namedObjectsInComponent.begin(), object->namedObjectsInComponent.end(),
141 unit->allocateNamedObjectsInComponent(i, object->namedObjectsInComponent.size()));
148 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
149 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
150 error.setDescription(description);
158 error.setDescription(message.message);
159 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startLine));
160 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startColumn));
174 return document->stringAt(idx);
179 return document->jsGenerator.registerString(str);
186 const auto *p = m_propertyCaches.at(index)->defaultProperty();
187 Q_ASSERT(p && p->isComponentWrapper());
188 return p->wrappedObjectIndex();
193 for (
int i =
objectCount(), end = m_propertyCaches.count(); i < end; ++i) {
194 const auto *p = m_propertyCaches.at(i)->defaultProperty();
195 Q_ASSERT(p && p->isComponentWrapper());
196 if (p->wrappedObjectIndex() == childIndex)
204 return document->javaScriptCompilationUnit->unitData();
209 return typeData->imports();
214 return &document->objects;
219 return &m_propertyCaches;
224 return &m_propertyCaches;
229 return document->jsParserEngine.pool();
234 return document->jsParserEngine.newStringRef(string);
239 return &document->jsGenerator.stringTable;
244 return object->bindingAsString(document, scriptIndex);
249 const quint32 moduleIdx = registerString(module);
250 const quint32 qualifierIdx = registerString(qualifier);
252 for (
int i = 0, count = document->imports.size(); i < count; ++i) {
253 const QV4::CompiledData::Import *existingImport = document->imports.at(i);
254 if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
255 && existingImport->uriIndex == moduleIdx
256 && existingImport->qualifierIndex == qualifierIdx)
259 auto pool = memoryPool();
260 QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
261 import->type = QV4::CompiledData::Import::ImportLibrary;
262 import->version = version;
263 import->uriIndex = moduleIdx;
264 import->qualifierIndex = qualifierIdx;
265 document->imports.append(import);
270 return typeData->qmlType(inlineComponentName);
287 scanObjectRecursively(0);
288 for (
int i = 0; i < qmlObjects.size(); ++i)
289 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
290 scanObjectRecursively(i);
295 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
296 if (!annotateScriptBindings)
297 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
298 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
299 switch (binding->type()) {
300 case QV4::CompiledData::Binding::Type_Script:
301 if (annotateScriptBindings) {
302 binding->stringIndex = compiler->registerString(
303 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
306 case QV4::CompiledData::Binding::Type_Object:
307 case QV4::CompiledData::Binding::Type_AttachedProperty:
308 case QV4::CompiledData::Binding::Type_GroupedProperty:
309 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
327 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
328 for (
int i = 0; i < qmlObjects.size(); ++i) {
329 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
333 const QmlIR::Object *obj = qmlObjects.at(i);
335 QQmlPropertyResolver resolver(propertyCache);
336 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
338 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
339 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
341 bool notInRevision =
false;
342 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
343 if (!pd || pd->propType() != scriptStringMetaType)
346 QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
347 binding->stringIndex = compiler->registerString(script);
353void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
int componentRoot)
const
355 m_compiler->objectAt(componentRoot)
356 ->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
360bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(
int index)
const
362 m_compiler->qmlObjects()->at(index)->isComponent =
true;
367bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::isComponentBoundary(
int index)
const
369 return m_compiler->objectAt(index)->isComponent;
373void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(
int index)
const
375 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
379void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupedProperty(
380 CompiledBinding *binding)
383 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
384 if (targetObjectIndex != -1)
385 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
389
390
391
392
393
394
395
396
397
398
399
400
401
402
405 QStringView property, QStringView subProperty,
406 QQmlPropertyIndex &propIdx, QMetaType targetPropertyType,
407 const QQmlPropertyCacheVector *propertyCaches,
408 const QMap<
int,
int> &idToObjectIndex)
410 for (
auto it = targetObject->bindingsBegin(), end = targetObject->bindingsEnd();
413 if (compiler->stringAt(binding.propertyNameIndex) != property)
415 const auto &cache = propertyCaches->at(binding.value.objectIndex);
418 QQmlPropertyResolver resolver(cache);
419 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
422 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
426 for (
auto it = targetObject->aliasesBegin(), end = targetObject->aliasesEnd();
428 auto innerAlias = *it;
429 if (compiler->stringAt(innerAlias.nameIndex()) != property)
431 const int innerObjectIndex = idToObjectIndex.value(innerAlias.idIndex(), -1);
432 if (innerObjectIndex == -1)
434 const auto &cache = propertyCaches->at(innerObjectIndex);
437 QQmlPropertyResolver resolver(cache);
438 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
441 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
445 const QQmlPropertyCache::ConstPtr typeCache
446 = QQmlMetaType::propertyCacheForType(targetPropertyType);
448 const QQmlPropertyResolver resolver(typeCache);
449 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
451 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
460typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
461QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
462 int objectIndex, QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator,
466 const QmlIR::Object *obj = m_compiler->objectAt(objectIndex);
467 if (!obj->aliasCount())
468 return AllAliasesResolved;
471 int numSkippedAliases = 0;
472 bool hasUnresolvedLocalAliases =
false;
474 for (
const QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
475 if (resolvedAliases.contains(alias)) {
481 const int idIndex = alias->idIndex();
482 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
483 if (targetObjectIndex == -1) {
484 *error = qQmlCompileError(
485 alias->referenceLocation(),
486 QQmlComponentAndAliasResolverBase::tr(
487 "Invalid alias reference. Unable to find id \"%1\"")
488 .arg(stringAt(idIndex)));
492 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
493 Q_ASSERT(targetObject->id >= 0);
494 const int resolvedTargetObjectId = targetObject->id;
496 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
498 QStringView property;
499 QStringView subProperty;
501 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
502 if (propertySeparator != -1) {
503 property = QStringView{aliasPropertyValue}.left(propertySeparator);
504 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
506 property = QStringView(aliasPropertyValue);
508 QQmlPropertyIndex propIdx;
510 if (property.isEmpty()) {
513 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
515 *error = qQmlCompileError(
516 alias->referenceLocation(),
517 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
518 .arg(property.toString()));
522 QQmlPropertyResolver resolver(targetCache);
524 const QQmlPropertyData *targetProperty = resolver.property(
525 property.toString(),
nullptr, QQmlPropertyResolver::IgnoreRevision);
528 if (!targetProperty) {
529 bool aliasPointsToOtherAlias =
false;
530 auto targetAlias = targetObject->aliasesBegin();
531 for (
const auto end = targetObject->aliasesEnd(); targetAlias != end;
533 if (stringAt(targetAlias->nameIndex()) == property) {
534 aliasPointsToOtherAlias =
true;
538 if (aliasPointsToOtherAlias) {
539 if (targetObjectIndex != objectIndex) {
541 return aliasIndex == numSkippedAliases
543 : SomeAliasesResolved;
546 if (resolvedAliases.contains(targetAlias)) {
548 if (!appendAliasToPropertyCache(
549 alias, objectIndex, aliasIndex, -1,
550 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator,
561 hasUnresolvedLocalAliases =
true;
566 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
567 *error = qQmlCompileError(
568 alias->referenceLocation(),
569 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
570 .arg(property.toString()));
574 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
576 if (!subProperty.isEmpty()) {
577 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
578 if (!valueTypeMetaObject) {
580 bool isDeepAlias = subProperty.at(0).isLower();
582 isDeepAlias = resolveDeepAlias(
583 m_compiler, targetObject, property, subProperty, propIdx,
584 targetProperty->propType(), m_propertyCaches, m_idToObjectIndex);
587 *error = qQmlCompileError(
588 alias->referenceLocation(),
589 QQmlComponentAndAliasResolverBase::tr(
590 "Invalid alias target location: %1")
591 .arg(subProperty.toString()));
597 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
598 if (valueTypeIndex == -1) {
599 *error = qQmlCompileError(
600 alias->referenceLocation(),
601 QQmlComponentAndAliasResolverBase::tr(
602 "Invalid alias target location: %1")
603 .arg(subProperty.toString()));
606 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
608 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
613 if (!appendAliasToPropertyCache(
614 alias, objectIndex, aliasIndex, propIdx.toEncoded(),
615 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator, error)) {
620 if (numSkippedAliases == aliasIndex)
621 return NoAliasResolved;
623 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
624 return AllAliasesResolved;
626 return SomeAliasesResolved;
631class RuntimeDataBuilder
634 RuntimeDataBuilder(QV4::CompiledData::CompilationUnit *unit, QQmlTypeLoader *typeLoader,
635 const QQmlImports *imports)
636 : unit(unit), typeLoader(typeLoader), imports(imports)
640 QList<QQmlError> build()
643 if (!unit->runtimeData)
644 unit->allocateRuntimeData();
646 for (
int i = 0, count = unit->objectCount(); i < count; ++i) {
647 if (!classifySignalHandlers(i))
651 for (
int i = 0, count = unit->objectCount(); i < count; ++i) {
652 if (unit->objectAt(i)->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
653 if (!scanObject(i, ScopeDeferred::False))
657 scanObject(0, ScopeDeferred::False);
658 if (!errors.isEmpty())
661 for (
int i = 0, count = unit->objectCount(); i < count; ++i) {
662 classifyBindingsToAliases(i);
663 computeBindingOrder(i);
670 enum class ScopeDeferred :
bool { False, True };
672 bool isValueBinding(
int objectIndex,
int bindingIndex)
const
674 switch (unit->objectAt(objectIndex)->bindingTable()[bindingIndex].type()) {
675 case QV4::CompiledData::Binding::Type_AttachedProperty:
676 case QV4::CompiledData::Binding::Type_GroupedProperty:
679 return !unit->bindingIsSignalHandler(objectIndex, bindingIndex);
683 bool classifySignalHandlers(
int objectIndex)
685 const QQmlPropertyCache::ConstPtr cache = unit->propertyCaches.at(objectIndex);
689 const QV4::CompiledData::Object *obj = unit->objectAt(objectIndex);
690 if (
const QV4::ResolvedTypeReference *typeRef
691 = unit->resolvedType(obj->inheritedTypeNameIndex)) {
692 if (QQmlCustomParser *customParser = typeRef->type().customParser()) {
693 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
698 return classifySignalHandlers(
699 objectIndex, unit->stringAt(obj->inheritedTypeNameIndex), cache,
700 QQmlPropertyResolver::CheckRevision);
703 bool classifySignalHandlers(
704 int objectIndex,
const QString &typeName,
705 const QQmlPropertyCache::ConstPtr &propertyCache,
706 QQmlPropertyResolver::RevisionCheck checkRevision)
710 const Object *obj = unit->objectAt(objectIndex);
711 RuntimeBinding *runtimeBindings
712 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
713 QSet<QString> customSignals;
715 const Binding *binding = obj->bindingTable();
716 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
719 if (unit->bindingIsSignalHandler(objectIndex, i))
722 const QString bindingPropertyName = unit->stringAt(binding->propertyNameIndex);
723 const Binding::Type bindingType = binding->type();
725 if (bindingType == Binding::Type_AttachedProperty) {
726 const QV4::ResolvedTypeReference *typeRef
727 = unit->resolvedType(binding->propertyNameIndex);
728 QQmlType type = typeRef ? typeRef->type() : QQmlType();
730 imports->resolveType(typeLoader, bindingPropertyName, &type,
nullptr,
nullptr);
731 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
733 return recordError(binding->location,
734 QQmlTypeCompiler::tr(
"Non-existent attached object"));
738 if (!classifySignalHandlers(binding->value.objectIndex, bindingPropertyName,
739 QQmlMetaType::propertyCache(attachedType),
740 QQmlPropertyResolver::IgnoreRevision)) {
746 const QString qPropertyName
747 = QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)
748 .value_or(QString());
749 const QString signalName
750 = QQmlSignalNames::anyHandlerNameToSignalName(bindingPropertyName)
751 .value_or(QString());
752 if (signalName.isEmpty())
755 QQmlPropertyResolver resolver(propertyCache);
756 bool notInRevision =
false;
757 const QQmlPropertyData *
const signal
758 = resolver.signal(signalName, ¬InRevision, checkRevision);
759 const QQmlPropertyData *
const signalPropertyData
760 = resolver.property(signalName,
nullptr, checkRevision);
761 const QQmlPropertyData *
const qPropertyData = !qPropertyName.isEmpty()
762 ? resolver.property(qPropertyName,
nullptr, checkRevision)
765 RuntimeBinding::Flag flag = RuntimeBinding::IsSignalHandlerExpression;
766 const bool isPropertyObserver
767 = !signalPropertyData && qPropertyData && qPropertyData->notifiesViaBindable();
768 if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
769 int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
770 sigIndex = propertyCache->originalClone(sigIndex);
771 bool unnamedParameter =
false;
772 const QList<QByteArray> parameterNames
773 = propertyCache->signalParameterNames(sigIndex);
774 for (
const QByteArray ¶meterName : parameterNames) {
775 const QString param = QString::fromUtf8(parameterName);
776 if (param.isEmpty()) {
777 unnamedParameter =
true;
778 }
else if (unnamedParameter) {
781 QQmlTypeCompiler::tr(
"Signal uses unnamed parameter followed by "
782 "named parameter."));
783 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
786 QQmlTypeCompiler::tr(
"Signal parameter \"%1\" hides global "
787 "variable.").arg(param));
790 }
else if (isPropertyObserver) {
791 flag = RuntimeBinding::IsPropertyObserver;
795 if (signalPropertyData)
798 if (
const QV4::ResolvedTypeReference *typeRef
799 = unit->resolvedType(obj->inheritedTypeNameIndex);
800 typeRef && typeRef->type().isValid()) {
801 const QQmlType type = typeRef->type();
804 QQmlTypeCompiler::tr(
"\"%1.%2\" is not available in %3 %4.%5.")
805 .arg(typeName, bindingPropertyName, type.module())
806 .arg(type.version().majorVersion())
807 .arg(type.version().minorVersion()));
811 QQmlTypeCompiler::tr(
"\"%1.%2\" is not available due to component "
812 "versioning.").arg(typeName, bindingPropertyName));
818 if (customSignals.isEmpty()) {
819 for (
int s = 0, sc = obj->signalCount(); s < sc; ++s)
820 customSignals.insert(unit->stringAt(obj->signalAt(s)->nameIndex));
821 const Property *properties = obj->propertyTable();
822 for (
int p = 0, pc = obj->propertyCount(); p < pc; ++p)
823 customSignals.insert(unit->stringAt(properties[p].nameIndex()));
827 if (!customSignals.contains(signalName)
828 && (qPropertyName.isEmpty() || !customSignals.contains(qPropertyName))) {
834 if (bindingType == Binding::Type_Object) {
835 runtimeBindings[i].flags |= RuntimeBinding::IsSignalHandlerObject;
839 if (bindingType != Binding::Type_Script) {
842 bindingType < Binding::Type_Script
843 ? QQmlTypeCompiler::tr(
"Cannot assign a value to a signal "
844 "(expecting a script to be run)")
845 : QQmlTypeCompiler::tr(
"Incorrectly specified signal assignment"));
848 runtimeBindings[i].flags |= flag;
853 void foldEnums(
int objectIndex)
856 const Object *obj = unit->objectAt(objectIndex);
857 RuntimeBinding *runtimeBindings
858 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
859 const Binding *binding = obj->bindingTable();
860 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
861 if (binding->type() != Binding::Type_Script
862 || unit->bindingIsSignalHandler(objectIndex, i)) {
866 if (
const std::optional<
int> value = evaluateQualifiedEnum(objectIndex, binding)) {
867 runtimeBindings[i].flags |= RuntimeBinding::IsFoldedEnum;
868 runtimeBindings[i].enumValue = *value;
873 std::optional<
int> evaluateQualifiedEnum(
int objectIndex,
874 const QV4::CompiledData::Binding *binding)
876 const QQmlPropertyCache::ConstPtr cache = unit->propertyCaches.at(objectIndex);
880 QQmlPropertyResolver resolver(cache);
881 bool notInRevision =
false;
882 const QQmlPropertyData *prop =
883 resolver.property(unit->stringAt(binding->propertyNameIndex), ¬InRevision);
884 if (!prop || prop->isQList())
886 const bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
887 if (!prop->isEnum() && !isIntProp)
890 if (!prop->isWritable()
891 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
892 recordError(binding->location,
893 QQmlTypeCompiler::tr(
894 "Invalid property assignment: \"%1\" is a read-only property")
895 .arg(unit->stringAt(binding->propertyNameIndex)));
899 const QString string = unit->stringAt(binding->stringIndex);
900 if (string.isEmpty() || !string.constData()->isUpper())
903 const int dot = string.indexOf(u'.');
904 if (dot == -1 || dot == string.size() - 1)
906 const int dot2 = string.indexOf(u'.', dot + 1);
907 if (dot2 != -1 && dot2 != string.size() - 1) {
908 if (!string.at(dot + 1).isUpper())
910 if (string.indexOf(u'.', dot2 + 1) != -1)
914 const QHashedStringRef typeName(string.constData(), dot);
915 const QStringView scopedEnumName =
916 (dot2 != -1 ? QStringView{ string }.mid(dot + 1, dot2 - dot - 1) : QStringView());
917 const QStringView enumValue = QStringView{ string }.mid(dot2 != -1 ? dot2 + 1 : dot + 1);
920 return evaluateEnum(typeName.toString(), scopedEnumName, enumValue);
923 imports->resolveType(typeLoader, typeName, &type,
nullptr,
nullptr);
927 QV4::ResolvedTypeReference *tr =
928 unit->resolvedType(unit->objectAt(objectIndex)->inheritedTypeNameIndex);
929 bool useFastPath = type.isValid() && tr && tr->type() == type;
933 mprop = cache->firstCppMetaObject()->property(prop->coreIndex());
934 menum = mprop.enumerator();
935 if (!menum.isScoped() && scopedEnumName.isEmpty()
936 && typeName != QString::fromUtf8(menum.scope())) {
944 const QByteArray enumName = enumValue.toUtf8();
945 if (menum.isScoped() && !scopedEnumName.isEmpty()
946 && enumName != scopedEnumName.toUtf8()) {
949 value = mprop.isFlagType() ? menum.keysToValue(enumName.constData(), &ok)
950 : menum.keyToValue(enumName.constData(), &ok);
952 value = scopedEnumName.isEmpty()
953 ? type.enumValue(typeLoader, enumValue, &ok)
954 : type.scopedEnumValue(typeLoader, scopedEnumName, enumValue, &ok);
956 return ok ? std::optional<
int>(value) : std::nullopt;
959 std::optional<
int> evaluateEnum(
const QString &scope, QStringView enumName,
960 QStringView enumValue)
964 imports->resolveType(typeLoader, scope, &type,
nullptr,
nullptr);
968 const int value = enumName.isEmpty()
969 ? type.enumValue(typeLoader,
970 QHashedStringRef(enumValue.constData(), enumValue.size()), &ok)
971 : type.scopedEnumValue(typeLoader, enumName, enumValue, &ok);
972 return ok ? std::optional<
int>(value) : std::nullopt;
975 void classifyBindingsToAliases(
int objectIndex)
978 const QQmlPropertyCache::ConstPtr propertyCache = unit->propertyCaches.at(objectIndex);
982 const Object *obj = unit->objectAt(objectIndex);
983 RuntimeBinding *runtimeBindings
984 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
985 QQmlPropertyResolver resolver(propertyCache);
986 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
987 ? propertyCache->parent()->defaultProperty()
988 : propertyCache->defaultProperty();
990 const Binding *binding = obj->bindingTable();
991 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
992 if (!isValueBinding(objectIndex, i))
994 bool notInRevision =
false;
995 const QQmlPropertyData *pd = binding->propertyNameIndex != 0
996 ? resolver.property(unit->stringAt(binding->propertyNameIndex), ¬InRevision)
998 if (pd && pd->isAlias())
999 runtimeBindings[i].flags |= RuntimeBinding::IsBindingToAlias;
1003 void computeBindingOrder(
int objectIndex)
1006 const Object *obj = unit->objectAt(objectIndex);
1007 const Binding *bindings = obj->bindingTable();
1008 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(objectIndex);
1009 const RuntimeBinding *runtimeBindings = runtimeObject->bindingTable();
1010 const auto isAlias = [&](quint32 b) {
1011 return runtimeBindings[b].flags & RuntimeBinding::IsBindingToAlias;
1014 RuntimeBindingIndex *order = runtimeObject->bindingOrder();
1016 const auto collect = [&](
auto predicate) {
1017 for (quint16 b = 0; b < obj->nBindings; ++b) {
1022 collect([&](quint16 b) {
return isValueBinding(objectIndex, b) && !isAlias(b); });
1023 collect([&](quint16 b) {
return unit->bindingIsSignalHandler(objectIndex, b); });
1024 collect([&](quint16 b) {
return bindings[b].isAttachedProperty(); });
1025 collect([&](quint16 b) {
return bindings[b].isGroupedProperty(); });
1026 collect([&](quint16 b) {
return isValueBinding(objectIndex, b) && isAlias(b); });
1027 Q_ASSERT(n == obj->nBindings);
1033 error.setUrl(unit->finalUrl());
1034 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
1035 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
1036 error.setDescription(description);
1037 errors.append(error);
1041 bool deferredAndImmediatePropertyNames(
1042 const QV4::CompiledData::Object *obj,
const QQmlPropertyCache::ConstPtr &propertyCache,
1043 QStringList *deferredPropertyNames, QStringList *immediatePropertyNames)
1045 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1046 const int deferredNamesIndex = mo->indexOfClassInfo(
"DeferredPropertyNames");
1047 const int immediateNamesIndex = mo->indexOfClassInfo(
"ImmediatePropertyNames");
1049 if (deferredNamesIndex != -1) {
1050 if (immediateNamesIndex != -1) {
1051 return recordError(obj->location,
1052 QQmlTypeCompiler::tr(
"You cannot define both DeferredPropertyNames "
1053 "and ImmediatePropertyNames on the same type."));
1055 *deferredPropertyNames
1056 = QString::fromUtf8(mo->classInfo(deferredNamesIndex).value()).split(u',');
1057 }
else if (immediateNamesIndex != -1) {
1058 *immediatePropertyNames
1059 = QString::fromUtf8(mo->classInfo(immediateNamesIndex).value()).split(u',');
1061 if (immediatePropertyNames->isEmpty())
1062 immediatePropertyNames->append(QString());
1067 bool scanObject(
int objectIndex, ScopeDeferred scopeDeferred)
1071 if (objectIndex >= unit->objectCount())
1072 return scanObject(unit->resolvedIndex(objectIndex), scopeDeferred);
1074 const Object *obj = unit->objectAt(objectIndex);
1075 if (obj->idNameIndex != 0)
1076 seenObjectWithId =
true;
1078 if (unit->objectIsComponent(objectIndex)) {
1079 Q_ASSERT(obj->nBindings == 1);
1080 const Binding *componentBinding = obj->bindingTable();
1081 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1083 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1086 const QQmlPropertyCache::ConstPtr propertyCache = unit->propertyCaches.at(objectIndex);
1090 QString defaultPropertyName;
1091 const QQmlPropertyData *defaultProperty =
nullptr;
1092 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1093 const QQmlPropertyCache *parentCache = propertyCache->parent().data();
1094 defaultPropertyName = parentCache->defaultPropertyName();
1095 defaultProperty = parentCache->defaultProperty();
1097 defaultPropertyName = propertyCache->defaultPropertyName();
1098 defaultProperty = propertyCache->defaultProperty();
1101 QStringList deferredPropertyNames;
1102 QStringList immediatePropertyNames;
1103 if (!deferredAndImmediatePropertyNames(
1104 obj, propertyCache, &deferredPropertyNames, &immediatePropertyNames)) {
1108 QQmlCustomParser *customParser =
nullptr;
1109 if (
const QV4::ResolvedTypeReference *typeRef
1110 = unit->resolvedType(obj->inheritedTypeNameIndex)) {
1111 const QQmlType type = typeRef->type();
1113 customParser = type.customParser();
1116 QQmlPropertyResolver propertyResolver(propertyCache);
1118 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(objectIndex);
1120 const Binding *binding = obj->bindingTable();
1121 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1122 QString name = unit->stringAt(binding->propertyNameIndex);
1124 const auto markCustomParser = [&]() {
1125 runtimeObject->flags |= RuntimeObject::HasCustomParserBindings;
1126 runtimeObject->bindingTable()[i].flags |= RuntimeBinding::IsCustomParserBinding;
1130 if (binding->type() == Binding::Type_AttachedProperty) {
1131 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1135 }
else if (QQmlSignalNames::isHandlerName(name)
1136 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1142 const bool hasPropertyData = [&]() {
1143 if (name.isEmpty()) {
1144 name = defaultPropertyName;
1145 if (defaultProperty)
1147 }
else if (name.constData()->isUpper()) {
1152 bool notInRevision =
false;
1153 if (propertyResolver.property(
1154 name, ¬InRevision, QQmlPropertyResolver::CheckRevision)) {
1163 if (unit->bindingIsSignalHandler(objectIndex, i))
1171 bool seenSubObjectWithId =
false;
1172 bool isExternal =
false;
1173 if (binding->type() >= Binding::Type_Object) {
1174 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1175 isExternal = !isOwnProperty && binding->isGroupedProperty();
1176 if (isOwnProperty || isExternal) {
1177 qSwap(seenObjectWithId, seenSubObjectWithId);
1180 const bool isImplicitComponent = unit->implicitComponentForObject(
1181 binding->value.objectIndex) != -1;
1182 const ScopeDeferred objectScope =
1183 !isImplicitComponent
1184 && (isExternal || scopeDeferred == ScopeDeferred::True)
1185 ? ScopeDeferred::True
1186 : ScopeDeferred::False;
1187 const bool subObjectValid = scanObject(binding->value.objectIndex, objectScope);
1188 qSwap(seenObjectWithId, seenSubObjectWithId);
1189 seenObjectWithId |= seenSubObjectWithId;
1190 if (!subObjectValid)
1195 bool isDeferred =
false;
1196 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1197 if (seenSubObjectWithId) {
1198 return recordError(binding->location,
1199 QQmlTypeCompiler::tr(
"You cannot assign an id to an object "
1200 "assigned to a deferred property."));
1202 if (isExternal || !disableInternalDeferredProperties())
1204 }
else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1205 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupedProperty) {
1206 if (isExternal || !disableInternalDeferredProperties())
1211 if (binding->type() >= Binding::Type_Object && isExternal && !isDeferred
1215 QQmlTypeCompiler::tr(
"Cannot assign to non-existent property \"%1\"")
1220 runtimeObject->bindingTable()[i].flags |= RuntimeBinding::IsDeferredBinding;
1221 runtimeObject->flags |= RuntimeObject::HasDeferredBindings;
1222 if (binding->type() == Binding::Type_AttachedProperty
1223 || binding->type() == Binding::Type_GroupedProperty) {
1224 unit->runtimeDataForWrite()->objectAt(binding->value.objectIndex)->flags
1225 |= RuntimeObject::PopulatedByDeferredBinding;
1233 QV4::CompiledData::CompilationUnit *unit;
1234 QQmlTypeLoader *typeLoader;
1235 const QQmlImports *imports;
1236 QList<QQmlError> errors;
1237 bool seenObjectWithId =
false;
1243 QV4::CompiledData::CompilationUnit *unit, QQmlTypeLoader *typeLoader,
1244 const QQmlImports *imports)
1246 return RuntimeDataBuilder(unit, typeLoader, imports).build();
void annotateBindingsWithScriptStrings()
QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
Combined button and popup list for selecting options.
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool resolveDeepAlias(QQmlTypeCompiler *compiler, const QmlIR::Object *targetObject, QStringView property, QStringView subProperty, QQmlPropertyIndex &propIdx, QMetaType targetPropertyType, const QQmlPropertyCacheVector *propertyCaches, const QMap< int, int > &idToObjectIndex)
QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
QQmlTypeCompiler * compiler
int implicitComponentForObject(int childIndex) const
void recordError(const QQmlJS::DiagnosticMessage &message)
const QV4::CompiledData::Unit * qmlUnit() const
QQmlType qmlTypeForComponent(const QString &inlineComponentName=QString()) const
QList< QmlIR::Object * > * qmlObjects() const
QQmlPropertyCacheVector * propertyCaches()
QQmlJS::MemoryPool * memoryPool()
void recordError(const QQmlError &e)
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const
const QQmlPropertyCacheVector * propertyCaches() const
int registerString(const QString &str)
const QV4::Compiler::StringTableGenerator * stringPool() const
void recordError(const QV4::CompiledData::Location &location, const QString &description)
QStringView newStringRef(const QString &string)
int resolvedIndex(int index) const
void addImport(const QString &module, const QString &qualifier, QTypeRevision version)
QQmlRefPointer< QV4::CompiledData::CompilationUnit > compile()
QString stringAt(int idx) const
const QQmlImports * imports() const