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);
117 if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
126 Q_ASSERT(document->jsModule.fileName == typeData->urlString());
127 Q_ASSERT(document->jsModule.finalUrl == typeData->finalUrlString());
128 QmlIR::JSCodeGen v4CodeGenerator(document);
129 for (QmlIR::Object *object : std::as_const(document->objects)) {
130 if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
131 Q_ASSERT(v4CodeGenerator.hasError());
132 recordError(v4CodeGenerator.error());
136 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(
false);
141 QmlIR::QmlUnitGenerator qmlGenerator;
142 qmlGenerator.generate(*document, dependencyHasher);
144 if (!errors.isEmpty())
147 return std::move(document->javaScriptCompilationUnit);
153 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(location.line()));
154 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(location.column()));
155 error.setDescription(description);
163 error.setDescription(message.message);
164 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startLine));
165 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(message.loc.startColumn));
179 return document->stringAt(idx);
184 return document->jsGenerator.registerString(str);
189 return document->jsGenerator.registerConstant(v);
194 return document->javaScriptCompilationUnit->unitData();
199 return typeData->imports();
204 return &document->objects;
209 return &m_propertyCaches;
214 return &m_propertyCaches;
219 return document->jsParserEngine.pool();
224 return document->jsParserEngine.newStringRef(string);
229 return &document->jsGenerator.stringTable;
234 return object->bindingAsString(document, scriptIndex);
239 const quint32 moduleIdx = registerString(module);
240 const quint32 qualifierIdx = registerString(qualifier);
242 for (
int i = 0, count = document->imports.size(); i < count; ++i) {
243 const QV4::CompiledData::Import *existingImport = document->imports.at(i);
244 if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
245 && existingImport->uriIndex == moduleIdx
246 && existingImport->qualifierIndex == qualifierIdx)
249 auto pool = memoryPool();
250 QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
251 import->type = QV4::CompiledData::Import::ImportLibrary;
252 import->version = version;
253 import->uriIndex = moduleIdx;
254 import->qualifierIndex = qualifierIdx;
255 document->imports.append(import);
260 return typeData->qmlType(inlineComponentName);
270 , typeLoader(typeCompiler->typeLoader())
271 , qmlObjects(*typeCompiler->qmlObjects())
273 , customParsers(typeCompiler->customParserCache())
274 , propertyCaches(typeCompiler->propertyCaches())
280 for (
int objectIndex = 0; objectIndex < qmlObjects.size(); ++objectIndex) {
281 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
282 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(objectIndex);
285 if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
286 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
289 const QString elementName = stringAt(obj->inheritedTypeNameIndex);
297 const QmlIR::Object *obj,
const QString &typeName,
298 const QQmlPropertyCache::ConstPtr &propertyCache,
299 QQmlPropertyResolver::RevisionCheck checkRevision)
302 QHash<QString, QStringList> customSignals;
304 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
305 const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
307 const QV4::CompiledData::Binding::Type bindingType = binding->type();
308 if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
309 const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
310 auto *typeRef = resolvedType(binding->propertyNameIndex);
311 QQmlType type = typeRef ? typeRef->type() : QQmlType();
313 imports->resolveType(typeLoader, bindingPropertyName, &type,
nullptr,
nullptr);
315 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
318 QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
322 attachedObj, bindingPropertyName, cache,
323 QQmlPropertyResolver::IgnoreRevision)) {
330 QString qPropertyName;
332 if (
auto propertyName =
333 QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
334 qPropertyName = *propertyName;
335 signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
337 signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
338 .value_or(QString());
340 if (signalName.isEmpty())
343 QQmlPropertyResolver resolver(propertyCache);
345 bool notInRevision =
false;
346 const QQmlPropertyData *
const signal
347 = resolver.signal(signalName, ¬InRevision, checkRevision);
348 const QQmlPropertyData *
const signalPropertyData
349 = resolver.property(signalName,
nullptr, checkRevision);
350 const QQmlPropertyData *
const qPropertyData = !qPropertyName.isEmpty()
351 ? resolver.property(qPropertyName,
nullptr, checkRevision)
353 QString finalSignalHandlerPropertyName = signalName;
354 QV4::CompiledData::Binding::Flag flag
355 = QV4::CompiledData::Binding::IsSignalHandlerExpression;
357 const bool isPropertyObserver
358 = !signalPropertyData && qPropertyData && qPropertyData->notifiesViaBindable();
359 if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
360 int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
361 sigIndex = propertyCache->originalClone(sigIndex);
363 bool unnamedParameter =
false;
365 QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
366 for (
int i = 0; i < parameterNames.size(); ++i) {
367 const QString param = QString::fromUtf8(parameterNames.at(i));
369 unnamedParameter =
true;
370 else if (unnamedParameter) {
371 COMPILE_EXCEPTION(binding, tr(
"Signal uses unnamed parameter followed by named parameter."));
372 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
373 COMPILE_EXCEPTION(binding, tr(
"Signal parameter \"%1\" hides global variable.").arg(param));
376 }
else if (isPropertyObserver) {
377 finalSignalHandlerPropertyName = qPropertyName;
378 flag = QV4::CompiledData::Binding::IsPropertyObserver;
382 if (signalPropertyData)
385 const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
387 auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
388 const QQmlType type = typeRef ? typeRef->type() : QQmlType();
389 if (type.isValid()) {
391 .arg(typeName, originalPropertyName, type.module())
392 .arg(type.version().majorVersion())
393 .arg(type.version().minorVersion()));
397 tr(
"\"%1.%2\" is not available due to component versioning.")
398 .arg(typeName, originalPropertyName));
405 if (customSignals.isEmpty()) {
406 for (
const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
407 const QString &signalName = stringAt(signal->nameIndex);
408 customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
411 for (
const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
412 const QString propName = stringAt(property->nameIndex());
413 customSignals.insert(propName, QStringList());
417 QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
418 if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
419 entry = customSignals.constFind(qPropertyName);
421 if (entry == customSignals.constEnd()) {
429 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
430 binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
434 if (bindingType != QV4::CompiledData::Binding::Type_Script) {
435 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
436 COMPILE_EXCEPTION(binding, tr(
"Cannot assign a value to a signal (expecting a script to be run)"));
442 binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
443 binding->setFlag(flag);
450 , qmlObjects(*typeCompiler->qmlObjects())
451 , propertyCaches(typeCompiler->propertyCaches())
458 for (
int i = 0; i < qmlObjects.size(); ++i) {
459 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
462 const QmlIR::Object *obj = qmlObjects.at(i);
464 QQmlPropertyResolver resolver(propertyCache);
466 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
467 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
468 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
469 || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
470 || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
473 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
476 const QString propertyName = stringAt(binding->propertyNameIndex);
477 bool notInRevision =
false;
478 const QQmlPropertyData *pd = resolver.property(propertyName, ¬InRevision);
479 if (!pd || pd->isQList())
482 if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
485 if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
493bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView,
int enumValue,
bool)
495 binding->setType(QV4::CompiledData::Binding::Type_Number);
496 binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((
double)enumValue));
498 binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
503 const QmlIR::Object *obj,
const QQmlPropertyCache::ConstPtr &propertyCache,
504 const QQmlPropertyData *prop, QmlIR::Binding *binding)
506 bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
507 if (!prop->isEnum() && !isIntProp)
510 if (!prop->isWritable()
511 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
512 COMPILE_EXCEPTION(binding, tr(
"Invalid property assignment: \"%1\" is a read-only property")
513 .arg(stringAt(binding->propertyNameIndex)));
516 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
517 const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
518 if (!string.constData()->isUpper())
524 for (
const QChar &c : string)
525 if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
532 int dot = string.indexOf(QLatin1Char(
'.'));
533 if (dot == -1 || dot == string.size()-1)
536 int dot2 = string.indexOf(QLatin1Char(
'.'), dot+1);
537 if (dot2 != -1 && dot2 != string.size()-1) {
538 if (!string.at(dot+1).isUpper())
540 if (string.indexOf(QLatin1Char(
'.'), dot2+1) != -1)
544 QHashedStringRef typeName(string.constData(), dot);
545 const bool isQtObject = (typeName == QLatin1String(
"Qt"));
546 const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
548 const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
553 int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
555 if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
561 imports->resolveType(compiler->typeLoader(), typeName, &type,
nullptr,
nullptr);
563 if (!type.isValid() && !isQtObject)
569 auto *tr = resolvedType(obj->inheritedTypeNameIndex);
572 bool useFastPath = type.isValid() && tr && tr->type() == type;
576 mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
577 menum = mprop.enumerator();
580 if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
581 useFastPath =
false;;
584 QByteArray enumName = enumValue.toUtf8();
585 if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
588 if (mprop.isFlagType()) {
589 value = menum.keysToValue(enumName.constData(), &ok);
591 value = menum.keyToValue(enumName.constData(), &ok);
595 if (type.isValid()) {
596 if (!scopedEnumName.isEmpty()) {
597 value = type.scopedEnumValue(
598 compiler->typeLoader(), scopedEnumName, enumValue, &ok);
600 value = type.enumValue(compiler->typeLoader(), QHashedStringRef(enumValue), &ok);
603 QByteArray enumName = enumValue.toUtf8();
604 const QMetaObject *metaObject = &Qt::staticMetaObject;
605 for (
int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
606 QMetaEnum e = metaObject->enumerator(ii);
607 value = e.keyToValue(enumName.constData(), &ok);
615 return assignEnumToBinding(binding, enumValue, value, isQtObject);
618int QQmlEnumTypeResolver::evaluateEnum(
const QString &scope, QStringView enumName, QStringView enumValue,
bool *ok)
const
620 Q_ASSERT_X(ok,
"QQmlEnumTypeResolver::evaluateEnum",
"ok must not be a null pointer");
623 if (scope != QLatin1String(
"Qt")) {
625 imports->resolveType(compiler->typeLoader(), scope, &type,
nullptr,
nullptr);
628 if (!enumName.isEmpty())
629 return type.scopedEnumValue(compiler->typeLoader(), enumName, enumValue, ok);
630 return type.enumValue(
631 compiler->typeLoader(),
632 QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
635 const QMetaObject *mo = &Qt::staticMetaObject;
636 int i = mo->enumeratorCount();
637 const QByteArray ba = enumValue.toUtf8();
639 int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
655 scanObjectRecursively(0);
656 for (
int i = 0; i < qmlObjects.size(); ++i)
657 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
658 scanObjectRecursively(i);
663 const QmlIR::Object *
const obj = qmlObjects.at(objectIndex);
664 if (!annotateScriptBindings)
665 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
666 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
667 switch (binding->type()) {
668 case QV4::CompiledData::Binding::Type_Script:
669 if (annotateScriptBindings) {
670 binding->stringIndex = compiler->registerString(
671 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
674 case QV4::CompiledData::Binding::Type_Object:
675 case QV4::CompiledData::Binding::Type_AttachedProperty:
676 case QV4::CompiledData::Binding::Type_GroupProperty:
677 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
694 for (
int i = 0; i < qmlObjects.size(); ++i) {
695 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
699 const QmlIR::Object *obj = qmlObjects.at(i);
701 QQmlPropertyResolver resolver(propertyCache);
702 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
704 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
705 if (!binding->isValueBinding())
707 bool notInRevision =
false;
708 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
709 if (pd && pd->isAlias())
710 binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
725 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
726 for (
int i = 0; i < qmlObjects.size(); ++i) {
727 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
731 const QmlIR::Object *obj = qmlObjects.at(i);
733 QQmlPropertyResolver resolver(propertyCache);
734 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
736 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
737 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
739 bool notInRevision =
false;
740 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty;
741 if (!pd || pd->propType() != scriptStringMetaType)
744 QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
745 binding->stringIndex = compiler->registerString(script);
751void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
752 QmlIR::Object *object)
const
754 object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
758bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(
int index)
const
760 m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
765void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(
int index)
const
767 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
771bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlIR::Binding *binding)
773 QQmlJS::MemoryPool *pool = m_compiler->memoryPool();
774 QList<QmlIR::Object *> *qmlObjects = m_compiler->qmlObjects();
777 QQmlType componentType = QQmlMetaType::qmlType(
778 &QQmlComponent::staticMetaObject, QStringLiteral(
"QML"),
779 QTypeRevision::fromVersion(1, 0));
780 Q_ASSERT(componentType.isValid());
781 const QString qualifier = QStringLiteral(
"QML");
783 m_compiler->addImport(componentType.module(), qualifier, componentType.version());
785 QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
786 syntheticComponent->init(
788 m_compiler->registerString(
789 qualifier + QLatin1Char(
'.') + componentType.elementName()),
790 m_compiler->registerString(QString()), binding->valueLocation);
791 syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
793 if (!m_compiler->resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
794 auto typeRef =
new QV4::ResolvedTypeReference;
795 typeRef->setType(componentType);
796 typeRef->setVersion(componentType.version());
797 m_compiler->resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
800 qmlObjects->append(syntheticComponent);
801 const int componentIndex = qmlObjects->size() - 1;
803 QQmlPropertyCache::ConstPtr componentCache
804 = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
805 m_propertyCaches->append(componentCache);
807 QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
808 *syntheticBinding = *binding;
811 syntheticBinding->propertyNameIndex = 0;
813 syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
814 QString error = syntheticComponent->appendBinding(syntheticBinding,
false);
815 Q_ASSERT(error.isEmpty());
818 binding->value.objectIndex = componentIndex;
820 m_componentRoots.append(componentIndex);
825void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
826 const CompiledObject &component, CompiledBinding *binding)
830 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
831 if (targetObjectIndex != -1)
832 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
836
837
838
839
840
841
842
843
844
845
846
847
848
849
852 QStringView property, QStringView subProperty,
853 QQmlPropertyIndex &propIdx, QMetaType targetPropertyType,
854 const QQmlPropertyCacheVector *propertyCaches,
855 const QMap<
int,
int> &idToObjectIndex)
857 for (
auto it = targetObject->bindingsBegin(), end = targetObject->bindingsEnd();
860 if (compiler->stringAt(binding.propertyNameIndex) != property)
862 const auto &cache = propertyCaches->at(binding.value.objectIndex);
865 QQmlPropertyResolver resolver(cache);
866 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
869 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
873 for (
auto it = targetObject->aliasesBegin(), end = targetObject->aliasesEnd();
875 auto innerAlias = *it;
876 if (compiler->stringAt(innerAlias.nameIndex()) != property)
878 const int innerObjectIndex = idToObjectIndex.value(innerAlias.idIndex(), -1);
879 if (innerObjectIndex == -1)
881 const auto &cache = propertyCaches->at(innerObjectIndex);
884 QQmlPropertyResolver resolver(cache);
885 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
888 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
892 const QQmlPropertyCache::ConstPtr typeCache
893 = QQmlMetaType::propertyCacheForType(targetPropertyType);
895 const QQmlPropertyResolver resolver(typeCache);
896 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
898 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
907typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
908QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
909 const CompiledObject &component,
int objectIndex,
910 QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator, QQmlError *error)
914 const QmlIR::Object *obj = m_compiler->objectAt(objectIndex);
915 if (!obj->aliasCount())
916 return AllAliasesResolved;
919 int numSkippedAliases = 0;
920 bool hasUnresolvedLocalAliases =
false;
922 for (
const QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
923 if (resolvedAliases.contains(alias)) {
929 const int idIndex = alias->idIndex();
930 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
931 if (targetObjectIndex == -1) {
932 *error = qQmlCompileError(
933 alias->referenceLocation(),
934 QQmlComponentAndAliasResolverBase::tr(
935 "Invalid alias reference. Unable to find id \"%1\"")
936 .arg(stringAt(idIndex)));
940 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
941 Q_ASSERT(targetObject->id >= 0);
942 const int resolvedTargetObjectId = targetObject->id;
944 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
946 QStringView property;
947 QStringView subProperty;
949 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
950 if (propertySeparator != -1) {
951 property = QStringView{aliasPropertyValue}.left(propertySeparator);
952 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
954 property = QStringView(aliasPropertyValue);
956 QQmlPropertyIndex propIdx;
958 if (property.isEmpty()) {
961 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
963 *error = qQmlCompileError(
964 alias->referenceLocation(),
965 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
966 .arg(property.toString()));
970 QQmlPropertyResolver resolver(targetCache);
972 const QQmlPropertyData *targetProperty = resolver.property(
973 property.toString(),
nullptr, QQmlPropertyResolver::IgnoreRevision);
976 if (!targetProperty) {
977 bool aliasPointsToOtherAlias =
false;
978 int localAliasIndex = 0;
979 auto targetAlias = targetObject->aliasesBegin();
980 for (
const auto end = targetObject->aliasesEnd(); targetAlias != end;
981 ++targetAlias, ++localAliasIndex) {
982 if (stringAt(targetAlias->nameIndex()) == property) {
983 aliasPointsToOtherAlias =
true;
987 if (aliasPointsToOtherAlias) {
988 if (targetObjectIndex != objectIndex) {
990 return aliasIndex == numSkippedAliases
992 : SomeAliasesResolved;
995 if (resolvedAliases.contains(targetAlias)) {
997 if (!appendAliasToPropertyCache(
998 &component, alias, objectIndex, aliasIndex, -1,
999 resolvedTargetObjectId, aliasCacheCreator, error)) {
1008 ++numSkippedAliases;
1009 hasUnresolvedLocalAliases =
true;
1014 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
1015 *error = qQmlCompileError(
1016 alias->referenceLocation(),
1017 QQmlComponentAndAliasResolverBase::tr(
"Invalid alias target location: %1")
1018 .arg(property.toString()));
1022 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
1024 if (!subProperty.isEmpty()) {
1025 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
1026 if (!valueTypeMetaObject) {
1028 bool isDeepAlias = subProperty.at(0).isLower();
1030 isDeepAlias = resolveDeepAlias(
1031 m_compiler, targetObject, property, subProperty, propIdx,
1032 targetProperty->propType(), m_propertyCaches, m_idToObjectIndex);
1035 *error = qQmlCompileError(
1036 alias->referenceLocation(),
1037 QQmlComponentAndAliasResolverBase::tr(
1038 "Invalid alias target location: %1")
1039 .arg(subProperty.toString()));
1044 int valueTypeIndex =
1045 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
1046 if (valueTypeIndex == -1) {
1047 *error = qQmlCompileError(
1048 alias->referenceLocation(),
1049 QQmlComponentAndAliasResolverBase::tr(
1050 "Invalid alias target location: %1")
1051 .arg(subProperty.toString()));
1054 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
1056 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
1061 if (!appendAliasToPropertyCache(
1062 &component, alias, objectIndex, aliasIndex, propIdx.toEncoded(),
1063 resolvedTargetObjectId, aliasCacheCreator, error)) {
1068 if (numSkippedAliases == aliasIndex)
1069 return NoAliasResolved;
1071 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
1072 return AllAliasesResolved;
1074 return SomeAliasesResolved;
1079 , qmlObjects(typeCompiler->qmlObjects())
1080 , propertyCaches(typeCompiler->propertyCaches())
1081 , customParsers(typeCompiler->customParserCache())
1082 , _seenObjectWithId(
false)
1088 for (
int i = 0; i < qmlObjects->size(); ++i) {
1089 if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
1090 && !scanObject(i, ScopeDeferred::False)) {
1094 return scanObject(0, ScopeDeferred::False);
1098 int objectIndex, ScopeDeferred scopeDeferred)
1102 QmlIR::Object *obj = qmlObjects->at(objectIndex);
1103 if (obj->idNameIndex != 0)
1104 _seenObjectWithId =
true;
1106 if (obj->flags & Object::IsComponent) {
1107 Q_ASSERT(obj->bindingCount() == 1);
1108 const Binding *componentBinding = obj->firstBinding();
1109 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1111 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1114 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1118 QString defaultPropertyName;
1119 const QQmlPropertyData *defaultProperty =
nullptr;
1120 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1121 const QQmlPropertyCache *cache = propertyCache->parent().data();
1122 defaultPropertyName = cache->defaultPropertyName();
1123 defaultProperty = cache->defaultProperty();
1125 defaultPropertyName = propertyCache->defaultPropertyName();
1126 defaultProperty = propertyCache->defaultProperty();
1129 QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
1131 QQmlPropertyResolver propertyResolver(propertyCache);
1133 QStringList deferredPropertyNames;
1134 QStringList immediatePropertyNames;
1136 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1137 const int deferredNamesIndex = mo->indexOfClassInfo(
"DeferredPropertyNames");
1138 const int immediateNamesIndex = mo->indexOfClassInfo(
"ImmediatePropertyNames");
1139 if (deferredNamesIndex != -1) {
1140 if (immediateNamesIndex != -1) {
1142 "ImmediatePropertyNames on the same type."));
1144 const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
1145 deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1146 }
else if (immediateNamesIndex != -1) {
1147 const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
1148 immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1151 if (immediatePropertyNames.isEmpty())
1152 immediatePropertyNames.append(QString());
1156 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
1157 QString name = stringAt(binding->propertyNameIndex);
1160 if (binding->type() == Binding::Type_AttachedProperty) {
1161 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1162 binding->setFlag(Binding::IsCustomParserBinding);
1163 obj->flags |= Object::HasCustomParserBindings;
1166 }
else if (QQmlSignalNames::isHandlerName(name)
1167 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1168 obj->flags |= Object::HasCustomParserBindings;
1169 binding->setFlag(Binding::IsCustomParserBinding);
1174 const bool hasPropertyData = [&]() {
1175 if (name.isEmpty()) {
1176 name = defaultPropertyName;
1177 if (defaultProperty)
1179 }
else if (name.constData()->isUpper()) {
1184 bool notInRevision =
false;
1185 if (propertyResolver.property(
1186 name, ¬InRevision, QQmlPropertyResolver::CheckRevision)) {
1194 const Binding::Flags bindingFlags = binding->flags();
1195 if (bindingFlags & Binding::IsSignalHandlerExpression
1196 || bindingFlags & Binding::IsSignalHandlerObject
1197 || bindingFlags & Binding::IsPropertyObserver) {
1204 obj->flags |= Object::HasCustomParserBindings;
1205 binding->setFlag(Binding::IsCustomParserBinding);
1209 bool seenSubObjectWithId =
false;
1210 bool isExternal =
false;
1211 if (binding->type() >= Binding::Type_Object) {
1212 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1213 isExternal = !isOwnProperty && binding->isGroupProperty();
1214 if (isOwnProperty || isExternal) {
1215 qSwap(_seenObjectWithId, seenSubObjectWithId);
1216 const bool subObjectValid = scanObject(
1217 binding->value.objectIndex,
1218 (isExternal || scopeDeferred == ScopeDeferred::True)
1219 ? ScopeDeferred::True
1220 : ScopeDeferred::False);
1221 qSwap(_seenObjectWithId, seenSubObjectWithId);
1222 if (!subObjectValid)
1224 _seenObjectWithId |= seenSubObjectWithId;
1228 bool isDeferred =
false;
1229 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1230 if (seenSubObjectWithId) {
1232 "to a deferred property."));
1234 if (isExternal || !disableInternalDeferredProperties())
1236 }
else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1237 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
1238 if (isExternal || !disableInternalDeferredProperties())
1243 if (binding->type() >= Binding::Type_Object) {
1244 if (isExternal && !isDeferred && !customParser) {
1246 binding, tr(
"Cannot assign to non-existent property \"%1\"").arg(name));
1251 binding->setFlag(Binding::IsDeferredBinding);
1252 obj->flags |= Object::HasDeferredBindings;
1269 for (
int i = 0; i < qmlObjects.size(); ++i)
1270 mergeDefaultProperties(i);
1275 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1279 QmlIR::Object *object = qmlObjects.at(objectIndex);
1281 QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
1282 QmlIR::Binding *bindingsToReinsert =
nullptr;
1283 QmlIR::Binding *tail =
nullptr;
1285 QmlIR::Binding *previousBinding =
nullptr;
1286 QmlIR::Binding *binding = object->firstBinding();
1288 if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
1289 previousBinding = binding;
1290 binding = binding->next;
1294 QmlIR::Binding *toReinsert = binding;
1295 binding = object->unlinkBinding(previousBinding, binding);
1298 bindingsToReinsert = toReinsert;
1301 tail->next = toReinsert;
1304 tail->next =
nullptr;
1307 binding = bindingsToReinsert;
1309 QmlIR::Binding *toReinsert = binding;
1310 binding = binding->next;
1311 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)
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 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)
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()