6#include <private/qqmlobjectcreator_p.h>
7#include <private/qqmlcustomparser_p.h>
8#include <private/qqmlvmemetaobject_p.h>
9#include <private/qqmlcomponent_p.h>
10#include <private/qqmlpropertyresolver_p.h>
11#include <private/qqmlcomponentandaliasresolver_p.h>
12#include <private/qqmlsignalnames_p.h>
14#define COMPILE_EXCEPTION(token, desc)
16 recordError((token)->location, desc);
22DEFINE_BOOL_CONFIG_OPTION(
23 disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
28 QQmlTypeLoader *typeLoader, QQmlTypeData *typeData,
QmlIR::Document *parsedQML,
29 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
30 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
31 : resolvedTypes(resolvedTypeCache)
33 , dependencyHasher(dependencyHasher)
43 for (
auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
45 QQmlCustomParser *customParser = (*it)->type().customParser();
47 customParsers.insert(it.key(), customParser);
50 QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
54 QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(
55 &m_propertyCaches, &pendingGroupPropertyBindings,
56 loader,
this, imports(), typeData->typeClassName());
57 QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
58 if (cycleError.isValid()) {
62 QQmlPropertyCacheCreatorBase::IncrementalResult result;
64 result = propertyCacheBuilder.buildMetaObjectsIncrementally();
65 const QQmlError &error = result.error;
66 if (error.isValid()) {
72 QQmlComponentAndAliasResolver resolver(
this, &m_propertyCaches);
73 if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
77 pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
78 pendingGroupPropertyBindings.clear();
80 }
while (result.canResume);
116 if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
125 Q_ASSERT(document->jsModule.fileName == typeData->urlString());
126 Q_ASSERT(document->jsModule.finalUrl == typeData->finalUrlString());
127 QmlIR::JSCodeGen v4CodeGenerator(document);
128 for (QmlIR::Object *object : std::as_const(document->objects)) {
129 if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
130 Q_ASSERT(v4CodeGenerator.hasError());
131 recordError(v4CodeGenerator.error());
135 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(
false);
140 QmlIR::QmlUnitGenerator qmlGenerator;
141 qmlGenerator.generate(*document, dependencyHasher);
143 if (!errors.isEmpty())
146 return std::move(document->javaScriptCompilationUnit);
152 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
153 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
154 error.setDescription(description);
162 error.setDescription(message.message);
163 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startLine));
164 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startColumn));
178 return document->stringAt(idx);
183 return document->jsGenerator.registerString(str);
188 return document->jsGenerator.registerConstant(v);
193 return document->javaScriptCompilationUnit->unitData();
198 return typeData->imports();
203 return &document->objects;
208 return &m_propertyCaches;
213 return &m_propertyCaches;
218 return document->jsParserEngine.pool();
223 return document->jsParserEngine.newStringRef(string);
228 return &document->jsGenerator.stringTable;
233 return object->bindingAsString(document, scriptIndex);
238 const quint32 moduleIdx = registerString(module);
239 const quint32 qualifierIdx = registerString(qualifier);
241 for (
int i = 0, count = document->imports.size(); i < count; ++i) {
242 const QV4::CompiledData::Import *existingImport = document->imports.at(i);
243 if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
244 && existingImport->uriIndex == moduleIdx
245 && existingImport->qualifierIndex == qualifierIdx)
248 auto pool = memoryPool();
249 QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
250 import->type = QV4::CompiledData::Import::ImportLibrary;
251 import->version = version;
252 import->uriIndex = moduleIdx;
253 import->qualifierIndex = qualifierIdx;
254 document->imports.append(import);
259 return typeData->qmlType(inlineComponentName);
269 , typeLoader(typeCompiler->typeLoader())
270 , qmlObjects(*typeCompiler->qmlObjects())
272 , customParsers(typeCompiler->customParserCache())
273 , propertyCaches(typeCompiler->propertyCaches())
279 for (
int objectIndex = 0; objectIndex < qmlObjects.size(); ++objectIndex) {
280 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
281 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(objectIndex);
284 if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
285 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
288 const QString elementName = stringAt(obj->inheritedTypeNameIndex);
296 const QmlIR::Object *obj,
const QString &typeName,
297 const QQmlPropertyCache::ConstPtr &propertyCache,
298 QQmlPropertyResolver::RevisionCheck checkRevision)
301 QHash<QString, QStringList> customSignals;
303 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
304 const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
306 const QV4::CompiledData::Binding::Type bindingType = binding->type();
307 if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
308 const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
309 auto *typeRef = resolvedType(binding->propertyNameIndex);
310 QQmlType type = typeRef ? typeRef->type() : QQmlType();
312 imports->resolveType(typeLoader, bindingPropertyName, &type,
nullptr,
nullptr);
314 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
317 QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
320 if (!resolveSignalHandlerExpressions(
321 attachedObj, bindingPropertyName, cache,
322 QQmlPropertyResolver::IgnoreRevision)) {
329 QString qPropertyName;
331 if (
auto propertyName =
332 QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
333 qPropertyName = *propertyName;
334 signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
336 signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
337 .value_or(QString());
339 if (signalName.isEmpty())
342 QQmlPropertyResolver resolver(propertyCache);
344 bool notInRevision =
false;
345 const QQmlPropertyData *
const signal
346 = resolver.signal(signalName, ¬InRevision, checkRevision);
347 const QQmlPropertyData *
const signalPropertyData
348 = resolver.property(signalName,
nullptr, checkRevision);
349 const QQmlPropertyData *
const qPropertyData = !qPropertyName.isEmpty()
350 ? resolver.property(qPropertyName,
nullptr, checkRevision)
352 QString finalSignalHandlerPropertyName = signalName;
353 QV4::CompiledData::Binding::Flag flag
354 = QV4::CompiledData::Binding::IsSignalHandlerExpression;
356 const bool isPropertyObserver
357 = !signalPropertyData && qPropertyData && qPropertyData->notifiesViaBindable();
358 if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
359 int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
360 sigIndex = propertyCache->originalClone(sigIndex);
362 bool unnamedParameter =
false;
364 QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
365 for (
int i = 0; i < parameterNames.size(); ++i) {
366 const QString param = QString::fromUtf8(parameterNames.at(i));
368 unnamedParameter =
true;
369 else if (unnamedParameter) {
370 COMPILE_EXCEPTION(binding, tr(
"Signal uses unnamed parameter followed by named parameter."));
371 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
372 COMPILE_EXCEPTION(binding, tr(
"Signal parameter \"%1\" hides global variable.").arg(param));
375 }
else if (isPropertyObserver) {
376 finalSignalHandlerPropertyName = qPropertyName;
377 flag = QV4::CompiledData::Binding::IsPropertyObserver;
381 if (signalPropertyData)
384 const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
386 auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
387 const QQmlType type = typeRef ? typeRef->type() : QQmlType();
388 if (type.isValid()) {
390 .arg(typeName).arg(originalPropertyName).arg(type.module())
391 .arg(type.version().majorVersion())
392 .arg(type.version().minorVersion()));
394 COMPILE_EXCEPTION(binding, tr(
"\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
401 if (customSignals.isEmpty()) {
402 for (
const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
403 const QString &signalName = stringAt(signal->nameIndex);
404 customSignals.insert(signalName, signal->parameterStringList(
compiler->stringPool()));
407 for (
const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
408 const QString propName = stringAt(property->nameIndex());
409 customSignals.insert(propName, QStringList());
413 QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
414 if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
415 entry = customSignals.constFind(qPropertyName);
417 if (entry == customSignals.constEnd()) {
425 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
426 binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
430 if (bindingType != QV4::CompiledData::Binding::Type_Script) {
431 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
432 COMPILE_EXCEPTION(binding, tr(
"Cannot assign a value to a signal (expecting a script to be run)"));
438 binding->propertyNameIndex =
compiler->registerString(finalSignalHandlerPropertyName);
439 binding->setFlag(flag);
446 , qmlObjects(*typeCompiler->qmlObjects())
447 , propertyCaches(typeCompiler->propertyCaches())
454 for (
int i = 0; i < qmlObjects.size(); ++i) {
455 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
458 const QmlIR::Object *obj = qmlObjects.at(i);
460 QQmlPropertyResolver resolver(propertyCache);
462 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
463 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
464 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
465 || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
466 || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
469 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
472 const QString propertyName = stringAt(binding->propertyNameIndex);
473 bool notInRevision =
false;
474 const QQmlPropertyData *pd = resolver.property(propertyName, ¬InRevision);
475 if (!pd || pd->isQList())
478 if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
481 if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
489bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView,
int enumValue,
bool)
491 binding->setType(QV4::CompiledData::Binding::Type_Number);
492 binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((
double)enumValue));
494 binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
499 const QmlIR::Object *obj,
const QQmlPropertyCache::ConstPtr &propertyCache,
500 const QQmlPropertyData *prop, QmlIR::Binding *binding)
502 bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
503 if (!prop->isEnum() && !isIntProp)
506 if (!prop->isWritable()
507 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
508 COMPILE_EXCEPTION(binding, tr(
"Invalid property assignment: \"%1\" is a read-only property")
509 .arg(stringAt(binding->propertyNameIndex)));
512 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
513 const QString string =
compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
514 if (!string.constData()->isUpper())
520 for (
const QChar &c : string)
521 if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
528 int dot = string.indexOf(QLatin1Char(
'.'));
529 if (dot == -1 || dot == string.size()-1)
532 int dot2 = string.indexOf(QLatin1Char(
'.'), dot+1);
533 if (dot2 != -1 && dot2 != string.size()-1) {
534 if (!string.at(dot+1).isUpper())
536 if (string.indexOf(QLatin1Char(
'.'), dot2+1) != -1)
540 QHashedStringRef typeName(string.constData(), dot);
541 const bool isQtObject = (typeName == QLatin1String(
"Qt"));
542 const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
544 const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
549 int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
551 if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
557 imports->resolveType(
compiler->typeLoader(), typeName, &type,
nullptr,
nullptr);
559 if (!type.isValid() && !isQtObject)
565 auto *tr = resolvedType(obj->inheritedTypeNameIndex);
568 bool useFastPath = type.isValid() && tr && tr->type() == type;
572 mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
573 menum = mprop.enumerator();
576 if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
577 useFastPath =
false;;
580 QByteArray enumName = enumValue.toUtf8();
581 if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
584 if (mprop.isFlagType()) {
585 value = menum.keysToValue(enumName.constData(), &ok);
587 value = menum.keyToValue(enumName.constData(), &ok);
591 if (type.isValid()) {
592 if (!scopedEnumName.isEmpty()) {
593 value = type.scopedEnumValue(
594 compiler->typeLoader(), scopedEnumName, enumValue, &ok);
596 value = type.enumValue(
compiler->typeLoader(), QHashedStringRef(enumValue), &ok);
599 QByteArray enumName = enumValue.toUtf8();
600 const QMetaObject *metaObject = &Qt::staticMetaObject;
601 for (
int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
602 QMetaEnum e = metaObject->enumerator(ii);
603 value = e.keyToValue(enumName.constData(), &ok);
611 return assignEnumToBinding(binding, enumValue, value, isQtObject);
614int QQmlEnumTypeResolver::evaluateEnum(
const QString &scope, QStringView enumName, QStringView enumValue,
bool *ok)
const
616 Q_ASSERT_X(ok,
"QQmlEnumTypeResolver::evaluateEnum",
"ok must not be a null pointer");
619 if (scope != QLatin1String(
"Qt")) {
621 imports->resolveType(
compiler->typeLoader(), scope, &type,
nullptr,
nullptr);
624 if (!enumName.isEmpty())
625 return type.scopedEnumValue(
compiler->typeLoader(), enumName, enumValue, ok);
626 return type.enumValue(
628 QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
631 const QMetaObject *mo = &Qt::staticMetaObject;
632 int i = mo->enumeratorCount();
633 const QByteArray ba = enumValue.toUtf8();
635 int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
651 scanObjectRecursively(0);
652 for (
int i = 0; i < qmlObjects.size(); ++i)
653 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
654 scanObjectRecursively(i);
659 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
660 if (!annotateScriptBindings)
661 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
662 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
663 switch (binding->type()) {
664 case QV4::CompiledData::Binding::Type_Script:
665 if (annotateScriptBindings) {
666 binding->stringIndex =
compiler->registerString(
667 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
670 case QV4::CompiledData::Binding::Type_Object:
671 case QV4::CompiledData::Binding::Type_AttachedProperty:
672 case QV4::CompiledData::Binding::Type_GroupProperty:
673 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
690 for (
int i = 0; i < qmlObjects.size(); ++i) {
691 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
695 const QmlIR::Object *obj = qmlObjects.at(i);
697 QQmlPropertyResolver resolver(propertyCache);
698 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
700 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
701 if (!binding->isValueBinding())
703 bool notInRevision =
false;
704 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
705 if (pd && pd->isAlias())
706 binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
721 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
722 for (
int i = 0; i < qmlObjects.size(); ++i) {
723 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
727 const QmlIR::Object *obj = qmlObjects.at(i);
729 QQmlPropertyResolver resolver(propertyCache);
730 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
732 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
733 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
735 bool notInRevision =
false;
736 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
737 if (!pd || pd->propType() != scriptStringMetaType)
740 QString script =
compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
741 binding->stringIndex =
compiler->registerString(script);
747void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
748 QmlIR::Object *object)
const
750 object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
754bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(
int index)
const
756 m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
761void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(
int index)
const
763 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
767bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlIR::Binding *binding)
769 QQmlJS::MemoryPool *pool = m_compiler->memoryPool();
770 QVector<QmlIR::Object *> *qmlObjects = m_compiler->qmlObjects();
773 QQmlType componentType = QQmlMetaType::qmlType(
774 &QQmlComponent::staticMetaObject, QStringLiteral(
"QML"),
775 QTypeRevision::fromVersion(1, 0));
776 Q_ASSERT(componentType.isValid());
777 const QString qualifier = QStringLiteral(
"QML");
779 m_compiler->addImport(componentType.module(), qualifier, componentType.version());
781 QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
782 syntheticComponent->init(
784 m_compiler->registerString(
785 qualifier + QLatin1Char(
'.') + componentType.elementName()),
786 m_compiler->registerString(QString()), binding->valueLocation);
787 syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
789 if (!m_compiler->resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
790 auto typeRef =
new QV4::ResolvedTypeReference;
791 typeRef->setType(componentType);
792 typeRef->setVersion(componentType.version());
793 m_compiler->resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
796 qmlObjects->append(syntheticComponent);
797 const int componentIndex = qmlObjects->size() - 1;
799 QQmlPropertyCache::ConstPtr componentCache
800 = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
801 m_propertyCaches->append(componentCache);
803 QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
804 *syntheticBinding = *binding;
807 syntheticBinding->propertyNameIndex = 0;
809 syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
810 QString error = syntheticComponent->appendBinding(syntheticBinding,
false);
811 Q_ASSERT(error.isEmpty());
814 binding->value.objectIndex = componentIndex;
816 m_componentRoots.append(componentIndex);
821void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
822 const CompiledObject &component, CompiledBinding *binding)
826 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
827 if (targetObjectIndex != -1)
828 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
832typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
833QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
834 const CompiledObject &component,
int objectIndex,
835 QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator, QQmlError *error)
844 const QmlIR::Object *
const obj = m_compiler->objectAt(objectIndex);
845 if (!obj->aliasCount())
846 return AllAliasesResolved;
849 int numSkippedAliases = 0;
850 bool hasUnresolvedLocalAliases =
false;
852 for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
853 if (resolvedAliases.contains(alias)) {
859 const int idIndex = alias->idIndex();
860 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
861 if (targetObjectIndex == -1) {
862 *error = qQmlCompileError(
863 alias->referenceLocation,
864 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
868 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
869 Q_ASSERT(targetObject->id >= 0);
870 alias->setTargetObjectId(targetObject->id);
871 alias->setIsAliasToLocalAlias(
false);
873 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
875 QStringView property;
876 QStringView subProperty;
878 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
879 if (propertySeparator != -1) {
880 property = QStringView{aliasPropertyValue}.left(propertySeparator);
881 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
883 property = QStringView(aliasPropertyValue);
885 QQmlPropertyIndex propIdx;
887 if (property.isEmpty()) {
888 alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
890 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
892 *error = qQmlCompileError(
893 alias->referenceLocation,
894 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1").arg(property.toString()));
898 QQmlPropertyResolver resolver(targetCache);
900 const QQmlPropertyData *targetProperty = resolver.property(
901 property.toString(),
nullptr, QQmlPropertyResolver::IgnoreRevision);
904 if (!targetProperty) {
905 bool aliasPointsToOtherAlias =
false;
906 int localAliasIndex = 0;
907 auto targetAlias = targetObject->aliasesBegin();
908 for (
const auto end = targetObject->aliasesEnd(); targetAlias != end;
909 ++targetAlias, ++localAliasIndex) {
910 if (stringAt(targetAlias->nameIndex()) == property) {
911 aliasPointsToOtherAlias =
true;
915 if (aliasPointsToOtherAlias) {
916 if (targetObjectIndex != objectIndex) {
918 alias->setIdIndex(idIndex);
919 return aliasIndex == numSkippedAliases
921 : SomeAliasesResolved;
924 if (resolvedAliases.contains(targetAlias)) {
926 alias->localAliasIndex = localAliasIndex;
927 alias->setIsAliasToLocalAlias(
true);
928 if (!appendAliasToPropertyCache(
929 &component, alias, objectIndex, aliasIndex, -1,
930 aliasCacheCreator, error)) {
938 alias->setIdIndex(idIndex);
941 hasUnresolvedLocalAliases =
true;
946 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
947 *error = qQmlCompileError(
948 alias->referenceLocation,
949 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1").arg(property.toString()));
953 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
955 if (!subProperty.isEmpty()) {
956 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
957 if (!valueTypeMetaObject) {
959 bool isDeepAlias = subProperty.at(0).isLower();
962 for (
auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
964 if (m_compiler->stringAt(binding.propertyNameIndex) == property) {
965 resolver = QQmlPropertyResolver(m_propertyCaches->at(binding.value.objectIndex));
966 const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
967 if (actualProperty) {
968 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
975 *error = qQmlCompileError(
976 alias->referenceLocation,
977 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1").arg(subProperty.toString()));
983 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
984 if (valueTypeIndex == -1) {
985 *error = qQmlCompileError(
986 alias->referenceLocation,
987 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1").arg(subProperty.toString()));
990 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
992 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
995 if (targetProperty->isQObject())
996 alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
1000 if (!appendAliasToPropertyCache(
1001 &component, alias, objectIndex, aliasIndex, propIdx.toEncoded(),
1002 aliasCacheCreator, error)) {
1007 if (numSkippedAliases == aliasIndex)
1008 return NoAliasResolved;
1010 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
1011 return AllAliasesResolved;
1013 return SomeAliasesResolved;
1018 , qmlObjects(typeCompiler->qmlObjects())
1019 , propertyCaches(typeCompiler->propertyCaches())
1020 , customParsers(typeCompiler->customParserCache())
1021 , _seenObjectWithId(
false)
1027 for (
int i = 0; i < qmlObjects->size(); ++i) {
1028 if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
1029 && !scanObject(i, ScopeDeferred::False)) {
1033 return scanObject(0, ScopeDeferred::False);
1037 int objectIndex, ScopeDeferred scopeDeferred)
1041 QmlIR::Object *obj = qmlObjects->at(objectIndex);
1042 if (obj->idNameIndex != 0)
1043 _seenObjectWithId =
true;
1045 if (obj->flags & Object::IsComponent) {
1046 Q_ASSERT(obj->bindingCount() == 1);
1047 const Binding *componentBinding = obj->firstBinding();
1048 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1050 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1053 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1057 QString defaultPropertyName;
1058 const QQmlPropertyData *defaultProperty =
nullptr;
1059 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1060 const QQmlPropertyCache *cache = propertyCache->parent().data();
1061 defaultPropertyName = cache->defaultPropertyName();
1062 defaultProperty = cache->defaultProperty();
1064 defaultPropertyName = propertyCache->defaultPropertyName();
1065 defaultProperty = propertyCache->defaultProperty();
1068 QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
1070 QQmlPropertyResolver propertyResolver(propertyCache);
1072 QStringList deferredPropertyNames;
1073 QStringList immediatePropertyNames;
1075 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1076 const int deferredNamesIndex = mo->indexOfClassInfo(
"DeferredPropertyNames");
1077 const int immediateNamesIndex = mo->indexOfClassInfo(
"ImmediatePropertyNames");
1078 if (deferredNamesIndex != -1) {
1079 if (immediateNamesIndex != -1) {
1081 "ImmediatePropertyNames on the same type."));
1083 const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
1084 deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1085 }
else if (immediateNamesIndex != -1) {
1086 const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
1087 immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1090 if (immediatePropertyNames.isEmpty())
1091 immediatePropertyNames.append(QString());
1095 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
1096 QString name = stringAt(binding->propertyNameIndex);
1099 if (binding->type() == Binding::Type_AttachedProperty) {
1100 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1101 binding->setFlag(Binding::IsCustomParserBinding);
1102 obj->flags |= Object::HasCustomParserBindings;
1105 }
else if (QQmlSignalNames::isHandlerName(name)
1106 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1107 obj->flags |= Object::HasCustomParserBindings;
1108 binding->setFlag(Binding::IsCustomParserBinding);
1113 const bool hasPropertyData = [&]() {
1114 if (name.isEmpty()) {
1115 name = defaultPropertyName;
1116 if (defaultProperty)
1118 }
else if (name.constData()->isUpper()) {
1123 bool notInRevision =
false;
1124 if (propertyResolver.property(
1125 name, ¬InRevision, QQmlPropertyResolver::CheckRevision)) {
1133 const Binding::Flags bindingFlags = binding->flags();
1134 if (bindingFlags & Binding::IsSignalHandlerExpression
1135 || bindingFlags & Binding::IsSignalHandlerObject
1136 || bindingFlags & Binding::IsPropertyObserver) {
1143 obj->flags |= Object::HasCustomParserBindings;
1144 binding->setFlag(Binding::IsCustomParserBinding);
1148 bool seenSubObjectWithId =
false;
1149 bool isExternal =
false;
1150 if (binding->type() >= Binding::Type_Object) {
1151 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1152 isExternal = !isOwnProperty && binding->isGroupProperty();
1153 if (isOwnProperty || isExternal) {
1154 qSwap(_seenObjectWithId, seenSubObjectWithId);
1155 const bool subObjectValid = scanObject(
1156 binding->value.objectIndex,
1157 (isExternal || scopeDeferred == ScopeDeferred::True)
1158 ? ScopeDeferred::True
1159 : ScopeDeferred::False);
1160 qSwap(_seenObjectWithId, seenSubObjectWithId);
1161 if (!subObjectValid)
1163 _seenObjectWithId |= seenSubObjectWithId;
1167 bool isDeferred =
false;
1168 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1169 if (seenSubObjectWithId) {
1171 "to a deferred property."));
1173 if (isExternal || !disableInternalDeferredProperties())
1175 }
else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1176 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
1177 if (isExternal || !disableInternalDeferredProperties())
1182 if (binding->type() >= Binding::Type_Object) {
1183 if (isExternal && !isDeferred && !customParser) {
1185 binding, tr(
"Cannot assign to non-existent property \"%1\"").arg(name));
1190 binding->setFlag(Binding::IsDeferredBinding);
1191 obj->flags |= Object::HasDeferredBindings;
1208 for (
int i = 0; i < qmlObjects.size(); ++i)
1209 mergeDefaultProperties(i);
1214 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1218 QmlIR::Object *object = qmlObjects.at(objectIndex);
1220 QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
1221 QmlIR::Binding *bindingsToReinsert =
nullptr;
1222 QmlIR::Binding *tail =
nullptr;
1224 QmlIR::Binding *previousBinding =
nullptr;
1225 QmlIR::Binding *binding = object->firstBinding();
1227 if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
1228 previousBinding = binding;
1229 binding = binding->next;
1233 QmlIR::Binding *toReinsert = binding;
1234 binding = object->unlinkBinding(previousBinding, binding);
1237 bindingsToReinsert = toReinsert;
1240 tail->next = toReinsert;
1243 tail->next =
nullptr;
1246 binding = bindingsToReinsert;
1248 QmlIR::Binding *toReinsert = binding;
1249 binding = binding->next;
1250 object->insertSorted(toReinsert);
void annotateBindingsToAliases()
QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void annotateBindingsWithScriptStrings()
QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
void mergeDefaultProperties()
QQmlDefaultPropertyMerger(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)
QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
QQmlTypeCompiler * compiler
int registerConstant(QV4::ReturnedValue v)
void recordError(const QQmlJS::DiagnosticMessage &message)
const QV4::CompiledData::Unit * qmlUnit() const
QQmlType qmlTypeForComponent(const QString &inlineComponentName=QString()) 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)
void addImport(const QString &module, const QString &qualifier, QTypeRevision version)
QQmlRefPointer< QV4::CompiledData::CompilationUnit > compile()
QVector< QmlIR::Object * > * qmlObjects() const
QString stringAt(int idx) const
const QQmlImports * imports() const
bool resolveSignalHandlerExpressions()