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#define COMPILE_EXCEPTION(token, desc)
17 recordError((token)->location, desc);
23DEFINE_BOOL_CONFIG_OPTION(
24 disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
29 QQmlTypeLoader *typeLoader, QQmlTypeData *typeData,
QmlIR::Document *parsedQML,
30 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
31 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
32 : resolvedTypes(resolvedTypeCache)
34 , dependencyHasher(dependencyHasher)
44 for (
auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
46 QQmlCustomParser *customParser = (*it)->type().customParser();
48 customParsers.insert(it.key(), customParser);
51 QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
55 QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(
56 &m_propertyCaches, &pendingGroupPropertyBindings,
57 loader,
this, imports(), typeData->typeClassName());
58 QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
59 if (cycleError.isValid()) {
63 QQmlPropertyCacheCreatorBase::IncrementalResult result;
65 result = propertyCacheBuilder.buildMetaObjectsIncrementally();
66 const QQmlError &error = result.error;
67 if (error.isValid()) {
73 QQmlComponentAndAliasResolver resolver(
this, &m_propertyCaches);
74 if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
78 pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
79 pendingGroupPropertyBindings.clear();
81 }
while (result.canResume);
112 if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
121 Q_ASSERT(document->jsModule.fileName == typeData->urlString());
122 Q_ASSERT(document->jsModule.finalUrl == typeData->finalUrlString());
123 QmlIR::JSCodeGen v4CodeGenerator(document);
124 for (QmlIR::Object *object : std::as_const(document->objects)) {
125 if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
126 Q_ASSERT(v4CodeGenerator.hasError());
127 recordError(v4CodeGenerator.error());
131 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(
false);
136 QmlIR::QmlUnitGenerator qmlGenerator;
137 qmlGenerator.generate(*document, dependencyHasher);
139 if (!errors.isEmpty())
142 return std::move(document->javaScriptCompilationUnit);
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->jsGenerator.registerConstant(v);
209 return document->javaScriptCompilationUnit->unitData();
214 return typeData->imports();
219 return &document->objects;
224 return &m_propertyCaches;
229 return &m_propertyCaches;
234 return document->jsParserEngine.pool();
239 return document->jsParserEngine.newStringRef(string);
244 return &document->jsGenerator.stringTable;
249 return object->bindingAsString(document, scriptIndex);
254 const quint32 moduleIdx = registerString(module);
255 const quint32 qualifierIdx = registerString(qualifier);
257 for (
int i = 0, count = document->imports.size(); i < count; ++i) {
258 const QV4::CompiledData::Import *existingImport = document->imports.at(i);
259 if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
260 && existingImport->uriIndex == moduleIdx
261 && existingImport->qualifierIndex == qualifierIdx)
264 auto pool = memoryPool();
265 QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
266 import->type = QV4::CompiledData::Import::ImportLibrary;
267 import->version = version;
268 import->uriIndex = moduleIdx;
269 import->qualifierIndex = qualifierIdx;
270 document->imports.append(import);
275 return typeData->qmlType(inlineComponentName);
285 , typeLoader(typeCompiler->typeLoader())
286 , qmlObjects(*typeCompiler->qmlObjects())
288 , customParsers(typeCompiler->customParserCache())
289 , propertyCaches(typeCompiler->propertyCaches())
295 for (
int objectIndex = 0; objectIndex < qmlObjects.size(); ++objectIndex) {
296 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
297 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(objectIndex);
300 if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
301 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
304 const QString elementName = stringAt(obj->inheritedTypeNameIndex);
312 const QmlIR::Object *obj,
const QString &typeName,
313 const QQmlPropertyCache::ConstPtr &propertyCache,
314 QQmlPropertyResolver::RevisionCheck checkRevision)
317 QHash<QString, QStringList> customSignals;
319 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
320 const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
322 const QV4::CompiledData::Binding::Type bindingType = binding->type();
323 if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
324 const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
325 auto *typeRef = resolvedType(binding->propertyNameIndex);
326 QQmlType type = typeRef ? typeRef->type() : QQmlType();
328 imports->resolveType(typeLoader, bindingPropertyName, &type,
nullptr,
nullptr);
330 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
333 QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
337 attachedObj, bindingPropertyName, cache,
338 QQmlPropertyResolver::IgnoreRevision)) {
345 QString qPropertyName;
347 if (
auto propertyName =
348 QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
349 qPropertyName = *propertyName;
350 signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
352 signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
353 .value_or(QString());
355 if (signalName.isEmpty())
358 QQmlPropertyResolver resolver(propertyCache);
360 bool notInRevision =
false;
361 const QQmlPropertyData *
const signal
362 = resolver.signal(signalName, ¬InRevision, checkRevision);
363 const QQmlPropertyData *
const signalPropertyData
364 = resolver.property(signalName,
nullptr, checkRevision);
365 const QQmlPropertyData *
const qPropertyData = !qPropertyName.isEmpty()
366 ? resolver.property(qPropertyName,
nullptr, checkRevision)
368 QString finalSignalHandlerPropertyName = signalName;
369 QV4::CompiledData::Binding::Flag flag
370 = QV4::CompiledData::Binding::IsSignalHandlerExpression;
372 const bool isPropertyObserver
373 = !signalPropertyData && qPropertyData && qPropertyData->notifiesViaBindable();
374 if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
375 int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
376 sigIndex = propertyCache->originalClone(sigIndex);
378 bool unnamedParameter =
false;
380 QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
381 for (
int i = 0; i < parameterNames.size(); ++i) {
382 const QString param = QString::fromUtf8(parameterNames.at(i));
384 unnamedParameter =
true;
385 else if (unnamedParameter) {
386 COMPILE_EXCEPTION(binding, tr(
"Signal uses unnamed parameter followed by named parameter."));
387 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
388 COMPILE_EXCEPTION(binding, tr(
"Signal parameter \"%1\" hides global variable.").arg(param));
391 }
else if (isPropertyObserver) {
392 finalSignalHandlerPropertyName = qPropertyName;
393 flag = QV4::CompiledData::Binding::IsPropertyObserver;
397 if (signalPropertyData)
400 const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
402 auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
403 const QQmlType type = typeRef ? typeRef->type() : QQmlType();
404 if (type.isValid()) {
406 .arg(typeName, originalPropertyName, type.module())
407 .arg(type.version().majorVersion())
408 .arg(type.version().minorVersion()));
412 tr(
"\"%1.%2\" is not available due to component versioning.")
413 .arg(typeName, originalPropertyName));
420 if (customSignals.isEmpty()) {
421 for (
const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
422 const QString &signalName = stringAt(signal->nameIndex);
423 customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
426 for (
const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
427 const QString propName = stringAt(property->nameIndex());
428 customSignals.insert(propName, QStringList());
432 QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
433 if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
434 entry = customSignals.constFind(qPropertyName);
436 if (entry == customSignals.constEnd()) {
444 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
445 binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
449 if (bindingType != QV4::CompiledData::Binding::Type_Script) {
450 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
451 COMPILE_EXCEPTION(binding, tr(
"Cannot assign a value to a signal (expecting a script to be run)"));
457 binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
458 binding->setFlag(flag);
465 , qmlObjects(*typeCompiler->qmlObjects())
466 , propertyCaches(typeCompiler->propertyCaches())
473 for (
int i = 0; i < qmlObjects.size(); ++i) {
474 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
477 const QmlIR::Object *obj = qmlObjects.at(i);
479 QQmlPropertyResolver resolver(propertyCache);
481 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
482 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
483 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
484 || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
485 || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
488 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
491 const QString propertyName = stringAt(binding->propertyNameIndex);
492 bool notInRevision =
false;
493 const QQmlPropertyData *pd = resolver.property(propertyName, ¬InRevision);
494 if (!pd || pd->isQList())
497 if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
500 if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
508bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView,
int enumValue,
bool)
510 binding->setType(QV4::CompiledData::Binding::Type_Number);
511 binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((
double)enumValue));
513 binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
518 const QmlIR::Object *obj,
const QQmlPropertyCache::ConstPtr &propertyCache,
519 const QQmlPropertyData *prop, QmlIR::Binding *binding)
521 bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
522 if (!prop->isEnum() && !isIntProp)
525 if (!prop->isWritable()
526 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
527 COMPILE_EXCEPTION(binding, tr(
"Invalid property assignment: \"%1\" is a read-only property")
528 .arg(stringAt(binding->propertyNameIndex)));
531 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
532 const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
533 if (!string.constData()->isUpper())
539 for (
const QChar &c : string)
540 if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
547 int dot = string.indexOf(QLatin1Char(
'.'));
548 if (dot == -1 || dot == string.size()-1)
551 int dot2 = string.indexOf(QLatin1Char(
'.'), dot+1);
552 if (dot2 != -1 && dot2 != string.size()-1) {
553 if (!string.at(dot+1).isUpper())
555 if (string.indexOf(QLatin1Char(
'.'), dot2+1) != -1)
559 QHashedStringRef typeName(string.constData(), dot);
560 const bool isQtObject = (typeName == QLatin1String(
"Qt"));
561 const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
563 const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
568 int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
570 if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
576 imports->resolveType(compiler->typeLoader(), typeName, &type,
nullptr,
nullptr);
578 if (!type.isValid() && !isQtObject)
584 auto *tr = resolvedType(obj->inheritedTypeNameIndex);
587 bool useFastPath = type.isValid() && tr && tr->type() == type;
591 mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
592 menum = mprop.enumerator();
595 if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
596 useFastPath =
false;;
599 QByteArray enumName = enumValue.toUtf8();
600 if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
603 if (mprop.isFlagType()) {
604 value = menum.keysToValue(enumName.constData(), &ok);
606 value = menum.keyToValue(enumName.constData(), &ok);
610 if (type.isValid()) {
611 if (!scopedEnumName.isEmpty()) {
612 value = type.scopedEnumValue(
613 compiler->typeLoader(), scopedEnumName, enumValue, &ok);
615 value = type.enumValue(compiler->typeLoader(), QHashedStringRef(enumValue), &ok);
618 QByteArray enumName = enumValue.toUtf8();
619 const QMetaObject *metaObject = &Qt::staticMetaObject;
620 for (
int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
621 QMetaEnum e = metaObject->enumerator(ii);
622 value = e.keyToValue(enumName.constData(), &ok);
630 return assignEnumToBinding(binding, enumValue, value, isQtObject);
633int QQmlEnumTypeResolver::evaluateEnum(
const QString &scope, QStringView enumName, QStringView enumValue,
bool *ok)
const
635 Q_ASSERT_X(ok,
"QQmlEnumTypeResolver::evaluateEnum",
"ok must not be a null pointer");
638 if (scope != QLatin1String(
"Qt")) {
640 imports->resolveType(compiler->typeLoader(), scope, &type,
nullptr,
nullptr);
643 if (!enumName.isEmpty())
644 return type.scopedEnumValue(compiler->typeLoader(), enumName, enumValue, ok);
645 return type.enumValue(
646 compiler->typeLoader(),
647 QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
650 const QMetaObject *mo = &Qt::staticMetaObject;
651 int i = mo->enumeratorCount();
652 const QByteArray ba = enumValue.toUtf8();
654 int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
670 scanObjectRecursively(0);
671 for (
int i = 0; i < qmlObjects.size(); ++i)
672 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
673 scanObjectRecursively(i);
678 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
679 if (!annotateScriptBindings)
680 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
681 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
682 switch (binding->type()) {
683 case QV4::CompiledData::Binding::Type_Script:
684 if (annotateScriptBindings) {
685 binding->stringIndex = compiler->registerString(
686 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
689 case QV4::CompiledData::Binding::Type_Object:
690 case QV4::CompiledData::Binding::Type_AttachedProperty:
691 case QV4::CompiledData::Binding::Type_GroupProperty:
692 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
709 for (
int i = 0; i < qmlObjects.size(); ++i) {
710 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
714 const QmlIR::Object *obj = qmlObjects.at(i);
716 QQmlPropertyResolver resolver(propertyCache);
717 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
719 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
720 if (!binding->isValueBinding())
722 bool notInRevision =
false;
723 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
724 if (pd && pd->isAlias())
725 binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
740 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
741 for (
int i = 0; i < qmlObjects.size(); ++i) {
742 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
746 const QmlIR::Object *obj = qmlObjects.at(i);
748 QQmlPropertyResolver resolver(propertyCache);
749 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
751 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
752 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
754 bool notInRevision =
false;
755 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
756 if (!pd || pd->propType() != scriptStringMetaType)
759 QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
760 binding->stringIndex = compiler->registerString(script);
766void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
767 QmlIR::Object *object)
const
769 object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
773bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(
int index)
const
775 m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
780void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(
int index)
const
782 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
786void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
787 const CompiledObject &component, CompiledBinding *binding)
791 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
792 if (targetObjectIndex != -1)
793 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
797
798
799
800
801
802
803
804
805
806
807
808
809
810
813 QStringView property, QStringView subProperty,
814 QQmlPropertyIndex &propIdx, QMetaType targetPropertyType,
815 const QQmlPropertyCacheVector *propertyCaches,
816 const QMap<
int,
int> &idToObjectIndex)
818 for (
auto it = targetObject->bindingsBegin(), end = targetObject->bindingsEnd();
821 if (compiler->stringAt(binding.propertyNameIndex) != property)
823 const auto &cache = propertyCaches->at(binding.value.objectIndex);
826 QQmlPropertyResolver resolver(cache);
827 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
830 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
834 for (
auto it = targetObject->aliasesBegin(), end = targetObject->aliasesEnd();
836 auto innerAlias = *it;
837 if (compiler->stringAt(innerAlias.nameIndex()) != property)
839 const int innerObjectIndex = idToObjectIndex.value(innerAlias.idIndex(), -1);
840 if (innerObjectIndex == -1)
842 const auto &cache = propertyCaches->at(innerObjectIndex);
845 QQmlPropertyResolver resolver(cache);
846 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
849 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
853 const QQmlPropertyCache::ConstPtr typeCache
854 = QQmlMetaType::propertyCacheForType(targetPropertyType);
856 const QQmlPropertyResolver resolver(typeCache);
857 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
859 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
868typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
869QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
870 const CompiledObject &component,
int objectIndex,
871 QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator, QQmlError *error)
875 const QmlIR::Object *obj = m_compiler->objectAt(objectIndex);
876 if (!obj->aliasCount())
877 return AllAliasesResolved;
880 int numSkippedAliases = 0;
881 bool hasUnresolvedLocalAliases =
false;
883 for (
const QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
884 if (resolvedAliases.contains(alias)) {
890 const int idIndex = alias->idIndex();
891 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
892 if (targetObjectIndex == -1) {
893 *error = qQmlCompileError(
894 alias->referenceLocation(),
895 QQmlComponentAndAliasResolverBase::tr(
896 "Invalid alias reference. Unable to find id \"%1\"")
897 .arg(stringAt(idIndex)));
901 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
902 Q_ASSERT(targetObject->id >= 0);
903 const int resolvedTargetObjectId = targetObject->id;
905 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
907 QStringView property;
908 QStringView subProperty;
910 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
911 if (propertySeparator != -1) {
912 property = QStringView{aliasPropertyValue}.left(propertySeparator);
913 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
915 property = QStringView(aliasPropertyValue);
917 QQmlPropertyIndex propIdx;
919 if (property.isEmpty()) {
922 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
924 *error = qQmlCompileError(
925 alias->referenceLocation(),
926 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
927 .arg(property.toString()));
931 QQmlPropertyResolver resolver(targetCache);
933 const QQmlPropertyData *targetProperty = resolver.property(
934 property.toString(),
nullptr, QQmlPropertyResolver::IgnoreRevision);
937 if (!targetProperty) {
938 bool aliasPointsToOtherAlias =
false;
939 int localAliasIndex = 0;
940 auto targetAlias = targetObject->aliasesBegin();
941 for (
const auto end = targetObject->aliasesEnd(); targetAlias != end;
942 ++targetAlias, ++localAliasIndex) {
943 if (stringAt(targetAlias->nameIndex()) == property) {
944 aliasPointsToOtherAlias =
true;
948 if (aliasPointsToOtherAlias) {
949 if (targetObjectIndex != objectIndex) {
951 return aliasIndex == numSkippedAliases
953 : SomeAliasesResolved;
956 if (resolvedAliases.contains(targetAlias)) {
958 if (!appendAliasToPropertyCache(
959 &component, alias, objectIndex, aliasIndex, -1,
960 resolvedTargetObjectId, aliasCacheCreator, error)) {
970 hasUnresolvedLocalAliases =
true;
975 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
976 *error = qQmlCompileError(
977 alias->referenceLocation(),
978 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
979 .arg(property.toString()));
983 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
985 if (!subProperty.isEmpty()) {
986 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
987 if (!valueTypeMetaObject) {
989 bool isDeepAlias = subProperty.at(0).isLower();
991 isDeepAlias = resolveDeepAlias(
992 m_compiler, targetObject, property, subProperty, propIdx,
993 targetProperty->propType(), m_propertyCaches, m_idToObjectIndex);
996 *error = qQmlCompileError(
997 alias->referenceLocation(),
998 QQmlComponentAndAliasResolverBase::tr(
999 "Invalid alias target location: %1")
1000 .arg(subProperty.toString()));
1005 int valueTypeIndex =
1006 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
1007 if (valueTypeIndex == -1) {
1008 *error = qQmlCompileError(
1009 alias->referenceLocation(),
1010 QQmlComponentAndAliasResolverBase::tr(
1011 "Invalid alias target location: %1")
1012 .arg(subProperty.toString()));
1015 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
1017 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
1022 if (!appendAliasToPropertyCache(
1023 &component, alias, objectIndex, aliasIndex, propIdx.toEncoded(),
1024 resolvedTargetObjectId, aliasCacheCreator, error)) {
1029 if (numSkippedAliases == aliasIndex)
1030 return NoAliasResolved;
1032 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
1033 return AllAliasesResolved;
1035 return SomeAliasesResolved;
1040 , qmlObjects(typeCompiler->qmlObjects())
1041 , propertyCaches(typeCompiler->propertyCaches())
1042 , customParsers(typeCompiler->customParserCache())
1043 , _seenObjectWithId(
false)
1049 for (
int i = 0; i < qmlObjects->size(); ++i) {
1050 if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
1051 && !scanObject(i, ScopeDeferred::False)) {
1055 return scanObject(0, ScopeDeferred::False);
1059 int objectIndex, ScopeDeferred scopeDeferred)
1063 QmlIR::Object *obj = qmlObjects->at(objectIndex);
1064 if (obj->idNameIndex != 0)
1065 _seenObjectWithId =
true;
1067 if (obj->flags & Object::IsComponent) {
1068 Q_ASSERT(obj->bindingCount() == 1);
1069 const Binding *componentBinding = obj->firstBinding();
1070 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1072 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1075 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1079 QString defaultPropertyName;
1080 const QQmlPropertyData *defaultProperty =
nullptr;
1081 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1082 const QQmlPropertyCache *cache = propertyCache->parent().data();
1083 defaultPropertyName = cache->defaultPropertyName();
1084 defaultProperty = cache->defaultProperty();
1086 defaultPropertyName = propertyCache->defaultPropertyName();
1087 defaultProperty = propertyCache->defaultProperty();
1090 QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
1092 QQmlPropertyResolver propertyResolver(propertyCache);
1094 QStringList deferredPropertyNames;
1095 QStringList immediatePropertyNames;
1097 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1098 const int deferredNamesIndex = mo->indexOfClassInfo(
"DeferredPropertyNames");
1099 const int immediateNamesIndex = mo->indexOfClassInfo(
"ImmediatePropertyNames");
1100 if (deferredNamesIndex != -1) {
1101 if (immediateNamesIndex != -1) {
1103 "ImmediatePropertyNames on the same type."));
1105 const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
1106 deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1107 }
else if (immediateNamesIndex != -1) {
1108 const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
1109 immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1112 if (immediatePropertyNames.isEmpty())
1113 immediatePropertyNames.append(QString());
1117 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
1118 QString name = stringAt(binding->propertyNameIndex);
1121 if (binding->type() == Binding::Type_AttachedProperty) {
1122 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1123 binding->setFlag(Binding::IsCustomParserBinding);
1124 obj->flags |= Object::HasCustomParserBindings;
1127 }
else if (QQmlSignalNames::isHandlerName(name)
1128 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1129 obj->flags |= Object::HasCustomParserBindings;
1130 binding->setFlag(Binding::IsCustomParserBinding);
1135 const bool hasPropertyData = [&]() {
1136 if (name.isEmpty()) {
1137 name = defaultPropertyName;
1138 if (defaultProperty)
1140 }
else if (name.constData()->isUpper()) {
1145 bool notInRevision =
false;
1146 if (propertyResolver.property(
1147 name, ¬InRevision, QQmlPropertyResolver::CheckRevision)) {
1155 const Binding::Flags bindingFlags = binding->flags();
1156 if (bindingFlags & Binding::IsSignalHandlerExpression
1157 || bindingFlags & Binding::IsSignalHandlerObject
1158 || bindingFlags & Binding::IsPropertyObserver) {
1165 obj->flags |= Object::HasCustomParserBindings;
1166 binding->setFlag(Binding::IsCustomParserBinding);
1170 bool seenSubObjectWithId =
false;
1171 bool isExternal =
false;
1172 if (binding->type() >= Binding::Type_Object) {
1173 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1174 isExternal = !isOwnProperty && binding->isGroupProperty();
1175 if (isOwnProperty || isExternal) {
1176 qSwap(_seenObjectWithId, seenSubObjectWithId);
1179 const bool isImplicitComponent
1180 = compiler->implicitComponentForObject(binding->value.objectIndex) != -1;
1182 const ScopeDeferred objectScope =
1183 !isImplicitComponent && (isExternal || scopeDeferred == ScopeDeferred::True)
1184 ? ScopeDeferred::True
1185 : ScopeDeferred::False;
1186 const bool subObjectValid = scanObject(binding->value.objectIndex, objectScope);
1187 qSwap(_seenObjectWithId, seenSubObjectWithId);
1188 if (!subObjectValid)
1190 _seenObjectWithId |= seenSubObjectWithId;
1194 bool isDeferred =
false;
1195 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1196 if (seenSubObjectWithId) {
1198 "to a deferred property."));
1200 if (isExternal || !disableInternalDeferredProperties())
1202 }
else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1203 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
1204 if (isExternal || !disableInternalDeferredProperties())
1209 if (binding->type() >= Binding::Type_Object) {
1210 if (isExternal && !isDeferred && !customParser) {
1212 binding, tr(
"Cannot assign to non-existent property \"%1\"").arg(name));
1217 binding->setFlag(Binding::IsDeferredBinding);
1218 obj->flags |= Object::HasDeferredBindings;
void annotateBindingsToAliases()
QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void annotateBindingsWithScriptStrings()
QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
bool resolveEnumBindings()
QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
Combined button and popup list for selecting options.
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
#define COMPILE_EXCEPTION(location, desc)
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
int registerConstant(QV4::ReturnedValue v)
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
bool resolveSignalHandlerExpressions()