Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmltypecompiler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
6
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>
14
15#include <QtCore/qtyperevision.h>
16
17#define COMPILE_EXCEPTION(token, desc)
18 {
19 recordError((token)->location, desc);
20 return false;
21 }
22
24
25DEFINE_BOOL_CONFIG_OPTION(
26 disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
27
28Q_LOGGING_CATEGORY(lcQmlTypeCompiler, "qt.qml.typecompiler");
29
30QQmlTypeCompiler::QQmlTypeCompiler(
31 QQmlTypeLoader *typeLoader, QQmlTypeData *typeData, QmlIR::Document *parsedQML,
32 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
33 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
34 : resolvedTypes(resolvedTypeCache)
35 , loader(typeLoader)
36 , dependencyHasher(dependencyHasher)
37 , document(parsedQML)
38 , typeData(typeData)
39{
40}
41
43{
44 // Build property caches and VME meta object data
45
46 for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
47 it != end; ++it) {
48 QQmlCustomParser *customParser = (*it)->type().customParser();
49 if (customParser)
50 customParsers.insert(it.key(), customParser);
51 }
52
53 QQmlPendingGroupedPropertyBindings pendingGroupedPropertyBindings;
54
55
56 {
57 QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(
58 &m_propertyCaches, &pendingGroupedPropertyBindings,
59 loader, this, imports(), typeData->typeClassName());
60 QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
61 if (cycleError.isValid()) {
62 recordError(cycleError);
63 return nullptr;
64 }
65 QQmlPropertyCacheCreatorBase::IncrementalResult result;
66 do {
67 result = propertyCacheBuilder.buildMetaObjectsIncrementally();
68 const QQmlError &error = result.error;
69 if (error.isValid()) {
70 recordError(error);
71 return nullptr;
72 } else {
73 // Resolve component boundaries and aliases
74
75 QQmlComponentAndAliasResolver resolver(this, &m_propertyCaches);
76 if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
77 recordError(error);
78 return nullptr;
79 }
80 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
81 pendingGroupedPropertyBindings.clear(); // anything that can be processed is now processed
82 }
83 } while (result.canResume);
84 }
85
86 {
89 }
90
91 Q_ASSERT(!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData());
92 {
93 // Compile JS binding expressions and signal handlers
94 {
95 // We can compile script strings ahead of time, but they must be compiled
96 // without type optimizations as their scope is always entirely dynamic.
98 sss.scan();
99 }
100
101 Q_ASSERT(document->jsModule.fileName == typeData->urlString());
102 Q_ASSERT(document->jsModule.finalUrl == typeData->finalUrlString());
103 QmlIR::JSCodeGen v4CodeGenerator(document);
104 for (QmlIR::Object *object : std::as_const(document->objects)) {
105 if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
106 Q_ASSERT(v4CodeGenerator.hasError());
107 recordError(v4CodeGenerator.error());
108 return nullptr;
109 }
110 }
111 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
112 }
113
114 // Generate QML compiled type data structures
115
116 QmlIR::QmlUnitGenerator qmlGenerator;
117 qmlGenerator.generate(*document, dependencyHasher);
118
119 if (!errors.isEmpty())
120 return nullptr;
121
122 copyComponentsAndIds();
123 return std::move(document->javaScriptCompilationUnit);
124}
125
126void QQmlTypeCompiler::copyComponentsAndIds()
127{
128 using namespace QV4::CompiledData;
129 CompilationUnit *unit = document->javaScriptCompilationUnit.data();
130 unit->allocateRuntimeData();
131 for (int i = 0, count = document->objects.size(); i < count; ++i) {
132 const QmlIR::Object *object = document->objects.at(i);
133
134 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(i);
135 if (object->isComponent)
136 runtimeObject->flags |= RuntimeObject::IsComponent;
137 runtimeObject->objectId = object->id;
138
139 // Invalidates runtimeObject since the whole runtime data may be re-allocated.
140 std::copy(object->namedObjectsInComponent.begin(), object->namedObjectsInComponent.end(),
141 unit->allocateNamedObjectsInComponent(i, object->namedObjectsInComponent.size()));
142 }
143}
144
145void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
146{
147 QQmlError error;
148 error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
149 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
150 error.setDescription(description);
151 error.setUrl(url());
152 errors << error;
153}
154
155void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message)
156{
157 QQmlError error;
158 error.setDescription(message.message);
159 error.setLine(qmlConvertSourceCoordinate<quint32, int>(message.loc.startLine));
160 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(message.loc.startColumn));
161 error.setUrl(url());
162 errors << error;
163}
164
165void QQmlTypeCompiler::recordError(const QQmlError &e)
166{
167 QQmlError error = e;
168 error.setUrl(url());
169 errors << error;
170}
171
173{
174 return document->stringAt(idx);
175}
176
177int QQmlTypeCompiler::registerString(const QString &str)
178{
179 return document->jsGenerator.registerString(str);
180}
181
182int QQmlTypeCompiler::resolvedIndex(int index) const
183{
184 if (index < objectCount())
185 return index;
186 const auto *p = m_propertyCaches.at(index)->defaultProperty();
187 Q_ASSERT(p && p->isComponentWrapper());
188 return p->wrappedObjectIndex();
189}
190
192{
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)
197 return i;
198 }
199 return -1;
200}
201
203{
204 return document->javaScriptCompilationUnit->unitData();
205}
206
207const QQmlImports *QQmlTypeCompiler::imports() const
208{
209 return typeData->imports();
210}
211
213{
214 return &document->objects;
215}
216
218{
219 return &m_propertyCaches;
220}
221
223{
224 return &m_propertyCaches;
225}
226
228{
229 return document->jsParserEngine.pool();
230}
231
233{
234 return document->jsParserEngine.newStringRef(string);
235}
236
238{
239 return &document->jsGenerator.stringTable;
240}
241
242QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
243{
244 return object->bindingAsString(document, scriptIndex);
245}
246
247void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, QTypeRevision version)
248{
249 const quint32 moduleIdx = registerString(module);
250 const quint32 qualifierIdx = registerString(qualifier);
251
252 for (int i = 0, count = document->imports.size(); i < count; ++i) {
253 const QV4::CompiledData::Import *existingImport = document->imports.at(i);
254 if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
255 && existingImport->uriIndex == moduleIdx
256 && existingImport->qualifierIndex == qualifierIdx)
257 return;
258 }
259 auto pool = memoryPool();
260 QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
261 import->type = QV4::CompiledData::Import::ImportLibrary;
262 import->version = version;
263 import->uriIndex = moduleIdx;
264 import->qualifierIndex = qualifierIdx;
265 document->imports.append(import);
266}
267
268QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
269{
270 return typeData->qmlType(inlineComponentName);
271}
272
274 : compiler(typeCompiler)
275{
276}
277
284
286{
287 scanObjectRecursively(/*root object*/0);
288 for (int i = 0; i < qmlObjects.size(); ++i)
289 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
290 scanObjectRecursively(i);
291}
292
293void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
294{
295 const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
296 if (!annotateScriptBindings)
297 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
298 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
299 switch (binding->type()) {
300 case QV4::CompiledData::Binding::Type_Script:
301 if (annotateScriptBindings) {
302 binding->stringIndex = compiler->registerString(
303 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
304 }
305 break;
306 case QV4::CompiledData::Binding::Type_Object:
307 case QV4::CompiledData::Binding::Type_AttachedProperty:
308 case QV4::CompiledData::Binding::Type_GroupedProperty:
309 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
310 break;
311 default:
312 break;
313 }
314 }
315}
316
324
326{
327 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
328 for (int i = 0; i < qmlObjects.size(); ++i) {
329 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
330 if (!propertyCache)
331 continue;
332
333 const QmlIR::Object *obj = qmlObjects.at(i);
334
335 QQmlPropertyResolver resolver(propertyCache);
336 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
337
338 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
339 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
340 continue;
341 bool notInRevision = false;
342 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
343 if (!pd || pd->propType() != scriptStringMetaType)
344 continue;
345
346 QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
347 binding->stringIndex = compiler->registerString(script);
348 }
349 }
350}
351
352template<>
353void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(int componentRoot) const
354{
355 m_compiler->objectAt(componentRoot)
356 ->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
357}
358
359template<>
360bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(int index) const
361{
362 m_compiler->qmlObjects()->at(index)->isComponent = true;
363 return true;
364}
365
366template<>
367bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::isComponentBoundary(int index) const
368{
369 return m_compiler->objectAt(index)->isComponent;
370}
371
372template<>
373void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(int index) const
374{
375 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
376}
377
378template<>
379void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupedProperty(
380 CompiledBinding *binding)
381{
382 // We cannot make it fail here. It might be a custom-parsed property
383 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
384 if (targetObjectIndex != -1)
385 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
386}
387
388/*!
389 \internal
390
391 Attempts to resolve a "deep alias" — an alias whose sub-property path
392 goes through a QObject property, an inline component binding, or another
393 alias. For example: \c{alias foo: target.groupedProp.innerProp}
394
395 First searches the target object's bindings and aliases for \a property,
396 then looks up \a subProperty on the bound/aliased object's property cache.
397 If no binding or alias matches, falls back to looking up \a subProperty
398 on the declared type's property cache.
399
400 On success, updates \a propIdx with the resolved value-type index and
401 returns \c true.
402*/
404 QQmlTypeCompiler *compiler, const QmlIR::Object *targetObject,
405 QStringView property, QStringView subProperty,
406 QQmlPropertyIndex &propIdx, QMetaType targetPropertyType,
407 const QQmlPropertyCacheVector *propertyCaches,
408 const QMap<int, int> &idToObjectIndex)
409{
410 for (auto it = targetObject->bindingsBegin(), end = targetObject->bindingsEnd();
411 it != end; ++it) {
412 auto binding = *it;
413 if (compiler->stringAt(binding.propertyNameIndex) != property)
414 continue;
415 const auto &cache = propertyCaches->at(binding.value.objectIndex);
416 if (!cache)
417 continue;
418 QQmlPropertyResolver resolver(cache);
419 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
420 if (!pd)
421 continue;
422 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
423 return true;
424 }
425
426 for (auto it = targetObject->aliasesBegin(), end = targetObject->aliasesEnd();
427 it != end; ++it) {
428 auto innerAlias = *it;
429 if (compiler->stringAt(innerAlias.nameIndex()) != property)
430 continue;
431 const int innerObjectIndex = idToObjectIndex.value(innerAlias.idIndex(), -1);
432 if (innerObjectIndex == -1)
433 continue;
434 const auto &cache = propertyCaches->at(innerObjectIndex);
435 if (!cache)
436 continue;
437 QQmlPropertyResolver resolver(cache);
438 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
439 if (!pd)
440 continue;
441 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
442 return true;
443 }
444
445 const QQmlPropertyCache::ConstPtr typeCache
446 = QQmlMetaType::propertyCacheForType(targetPropertyType);
447 if (typeCache) {
448 const QQmlPropertyResolver resolver(typeCache);
449 const QQmlPropertyData *pd = resolver.property(subProperty.toString());
450 if (pd) {
451 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), pd->coreIndex());
452 return true;
453 }
454 }
455
456 return false;
457}
458
459template<>
460typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
461QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
462 int objectIndex, QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator,
463 QQmlError *error)
464{
465
466 const QmlIR::Object *obj = m_compiler->objectAt(objectIndex);
467 if (!obj->aliasCount())
468 return AllAliasesResolved;
469
470 int aliasIndex = 0;
471 int numSkippedAliases = 0;
472 bool hasUnresolvedLocalAliases = false;
473
474 for (const QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
475 if (resolvedAliases.contains(alias)) {
476 ++numSkippedAliases;
477 continue;
478 }
479
480
481 const int idIndex = alias->idIndex();
482 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
483 if (targetObjectIndex == -1) {
484 *error = qQmlCompileError(
485 alias->referenceLocation(),
486 QQmlComponentAndAliasResolverBase::tr(
487 "Invalid alias reference. Unable to find id \"%1\"")
488 .arg(stringAt(idIndex)));
489 break;
490 }
491
492 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
493 Q_ASSERT(targetObject->id >= 0);
494 const int resolvedTargetObjectId = targetObject->id;
495
496 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
497
498 QStringView property;
499 QStringView subProperty;
500
501 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
502 if (propertySeparator != -1) {
503 property = QStringView{aliasPropertyValue}.left(propertySeparator);
504 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
505 } else
506 property = QStringView(aliasPropertyValue);
507
508 QQmlPropertyIndex propIdx;
509
510 if (property.isEmpty()) {
511 // Alias points to object. No need to resolve properties.
512 } else {
513 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
514 if (!targetCache) {
515 *error = qQmlCompileError(
516 alias->referenceLocation(),
517 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1")
518 .arg(property.toString()));
519 break;
520 }
521
522 QQmlPropertyResolver resolver(targetCache);
523
524 const QQmlPropertyData *targetProperty = resolver.property(
525 property.toString(), nullptr, QQmlPropertyResolver::IgnoreRevision);
526
527 // If it's an alias that we haven't resolved yet, try again later.
528 if (!targetProperty) {
529 bool aliasPointsToOtherAlias = false;
530 auto targetAlias = targetObject->aliasesBegin();
531 for (const auto end = targetObject->aliasesEnd(); targetAlias != end;
532 ++targetAlias) {
533 if (stringAt(targetAlias->nameIndex()) == property) {
534 aliasPointsToOtherAlias = true;
535 break;
536 }
537 }
538 if (aliasPointsToOtherAlias) {
539 if (targetObjectIndex != objectIndex) {
540 // Don't continue, yet. We need to respect the order of objects.
541 return aliasIndex == numSkippedAliases
542 ? NoAliasResolved
543 : SomeAliasesResolved;
544 }
545
546 if (resolvedAliases.contains(targetAlias)) {
547 // Target already resolved. We can set the alias right away.
548 if (!appendAliasToPropertyCache(
549 alias, objectIndex, aliasIndex, -1,
550 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator,
551 error)) {
552 break;
553 }
554 continue;
555 }
556
557 // Target isn't resolved yet, but it's in the same object.
558 // Continue with the other aliases.
559 // Try again later and resolve the target alias first.
560 ++numSkippedAliases;
561 hasUnresolvedLocalAliases = true;
562 continue;
563 }
564 }
565
566 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
567 *error = qQmlCompileError(
568 alias->referenceLocation(),
569 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1")
570 .arg(property.toString()));
571 break;
572 }
573
574 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
575
576 if (!subProperty.isEmpty()) {
577 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
578 if (!valueTypeMetaObject) {
579 // could be a deep alias
580 bool isDeepAlias = subProperty.at(0).isLower();
581 if (isDeepAlias) {
582 isDeepAlias = resolveDeepAlias(
583 m_compiler, targetObject, property, subProperty, propIdx,
584 targetProperty->propType(), m_propertyCaches, m_idToObjectIndex);
585 }
586 if (!isDeepAlias) {
587 *error = qQmlCompileError(
588 alias->referenceLocation(),
589 QQmlComponentAndAliasResolverBase::tr(
590 "Invalid alias target location: %1")
591 .arg(subProperty.toString()));
592 break;
593 }
594 } else {
595
596 int valueTypeIndex =
597 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
598 if (valueTypeIndex == -1) {
599 *error = qQmlCompileError(
600 alias->referenceLocation(),
601 QQmlComponentAndAliasResolverBase::tr(
602 "Invalid alias target location: %1")
603 .arg(subProperty.toString()));
604 break;
605 }
606 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
607
608 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
609 }
610 }
611 }
612
613 if (!appendAliasToPropertyCache(
614 alias, objectIndex, aliasIndex, propIdx.toEncoded(),
615 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator, error)) {
616 break;
617 }
618 }
619
620 if (numSkippedAliases == aliasIndex)
621 return NoAliasResolved;
622
623 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
624 return AllAliasesResolved;
625
626 return SomeAliasesResolved;
627}
628
629namespace {
630
631class RuntimeDataBuilder
632{
633public:
634 RuntimeDataBuilder(QV4::CompiledData::CompilationUnit *unit, QQmlTypeLoader *typeLoader,
635 const QQmlImports *imports)
636 : unit(unit), typeLoader(typeLoader), imports(imports)
637 {
638 }
639
640 QList<QQmlError> build()
641 {
642 // Units compiled from source already have their component boundaries and ids.
643 if (!unit->runtimeData)
644 unit->allocateRuntimeData();
645
646 for (int i = 0, count = unit->objectCount(); i < count; ++i) {
647 if (!classifySignalHandlers(i))
648 return errors;
649 }
650
651 for (int i = 0, count = unit->objectCount(); i < count; ++i) {
652 if (unit->objectAt(i)->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
653 if (!scanObject(i, ScopeDeferred::False))
654 return errors;
655 }
656 }
657 scanObject(/*root object*/0, ScopeDeferred::False);
658 if (!errors.isEmpty())
659 return errors;
660
661 for (int i = 0, count = unit->objectCount(); i < count; ++i) {
662 classifyBindingsToAliases(i);
663 computeBindingOrder(i);
664 foldEnums(i);
665 }
666 return errors;
667 }
668
669private:
670 enum class ScopeDeferred : bool { False, True };
671
672 bool isValueBinding(int objectIndex, int bindingIndex) const
673 {
674 switch (unit->objectAt(objectIndex)->bindingTable()[bindingIndex].type()) {
675 case QV4::CompiledData::Binding::Type_AttachedProperty:
676 case QV4::CompiledData::Binding::Type_GroupedProperty:
677 return false;
678 default:
679 return !unit->bindingIsSignalHandler(objectIndex, bindingIndex);
680 }
681 }
682
683 bool classifySignalHandlers(int objectIndex)
684 {
685 const QQmlPropertyCache::ConstPtr cache = unit->propertyCaches.at(objectIndex);
686 if (!cache)
687 return true;
688
689 const QV4::CompiledData::Object *obj = unit->objectAt(objectIndex);
690 if (const QV4::ResolvedTypeReference *typeRef
691 = unit->resolvedType(obj->inheritedTypeNameIndex)) {
692 if (QQmlCustomParser *customParser = typeRef->type().customParser()) {
693 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
694 return true;
695 }
696 }
697
698 return classifySignalHandlers(
699 objectIndex, unit->stringAt(obj->inheritedTypeNameIndex), cache,
700 QQmlPropertyResolver::CheckRevision);
701 }
702
703 bool classifySignalHandlers(
704 int objectIndex, const QString &typeName,
705 const QQmlPropertyCache::ConstPtr &propertyCache,
706 QQmlPropertyResolver::RevisionCheck checkRevision)
707 {
708 using namespace QV4::CompiledData;
709
710 const Object *obj = unit->objectAt(objectIndex);
711 RuntimeBinding *runtimeBindings
712 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
713 QSet<QString> customSignals;
714
715 const Binding *binding = obj->bindingTable();
716 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
717 // Attached objects are visited twice: Once via the attached property and once on their
718 // own.
719 if (unit->bindingIsSignalHandler(objectIndex, i))
720 continue;
721
722 const QString bindingPropertyName = unit->stringAt(binding->propertyNameIndex);
723 const Binding::Type bindingType = binding->type();
724
725 if (bindingType == Binding::Type_AttachedProperty) {
726 const QV4::ResolvedTypeReference *typeRef
727 = unit->resolvedType(binding->propertyNameIndex);
728 QQmlType type = typeRef ? typeRef->type() : QQmlType();
729 if (!type.isValid())
730 imports->resolveType(typeLoader, bindingPropertyName, &type, nullptr, nullptr);
731 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
732 if (!attachedType) {
733 return recordError(binding->location,
734 QQmlTypeCompiler::tr("Non-existent attached object"));
735 }
736
737 // Ignore revisions of signals on attached objects. They are not unqualified.
738 if (!classifySignalHandlers(binding->value.objectIndex, bindingPropertyName,
739 QQmlMetaType::propertyCache(attachedType),
740 QQmlPropertyResolver::IgnoreRevision)) {
741 return false;
742 }
743 continue;
744 }
745
746 const QString qPropertyName
747 = QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)
748 .value_or(QString());
749 const QString signalName
750 = QQmlSignalNames::anyHandlerNameToSignalName(bindingPropertyName)
751 .value_or(QString());
752 if (signalName.isEmpty())
753 continue;
754
755 QQmlPropertyResolver resolver(propertyCache);
756 bool notInRevision = false;
757 const QQmlPropertyData *const signal
758 = resolver.signal(signalName, &notInRevision, checkRevision);
759 const QQmlPropertyData *const signalPropertyData
760 = resolver.property(signalName, nullptr, checkRevision);
761 const QQmlPropertyData *const qPropertyData = !qPropertyName.isEmpty()
762 ? resolver.property(qPropertyName, nullptr, checkRevision)
763 : nullptr;
764
765 RuntimeBinding::Flag flag = RuntimeBinding::IsSignalHandlerExpression;
766 const bool isPropertyObserver
767 = !signalPropertyData && qPropertyData && qPropertyData->notifiesViaBindable();
768 if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
769 int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
770 sigIndex = propertyCache->originalClone(sigIndex);
771 bool unnamedParameter = false;
772 const QList<QByteArray> parameterNames
773 = propertyCache->signalParameterNames(sigIndex);
774 for (const QByteArray &parameterName : parameterNames) {
775 const QString param = QString::fromUtf8(parameterName);
776 if (param.isEmpty()) {
777 unnamedParameter = true;
778 } else if (unnamedParameter) {
779 return recordError(
780 binding->location,
781 QQmlTypeCompiler::tr("Signal uses unnamed parameter followed by "
782 "named parameter."));
783 } else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
784 return recordError(
785 binding->location,
786 QQmlTypeCompiler::tr("Signal parameter \"%1\" hides global "
787 "variable.").arg(param));
788 }
789 }
790 } else if (isPropertyObserver) {
791 flag = RuntimeBinding::IsPropertyObserver;
792 } else {
793 if (notInRevision) {
794 // Try assigning it as a property later
795 if (signalPropertyData)
796 continue;
797
798 if (const QV4::ResolvedTypeReference *typeRef
799 = unit->resolvedType(obj->inheritedTypeNameIndex);
800 typeRef && typeRef->type().isValid()) {
801 const QQmlType type = typeRef->type();
802 return recordError(
803 binding->location,
804 QQmlTypeCompiler::tr("\"%1.%2\" is not available in %3 %4.%5.")
805 .arg(typeName, bindingPropertyName, type.module())
806 .arg(type.version().majorVersion())
807 .arg(type.version().minorVersion()));
808 }
809 return recordError(
810 binding->location,
811 QQmlTypeCompiler::tr("\"%1.%2\" is not available due to component "
812 "versioning.").arg(typeName, bindingPropertyName));
813 }
814
815 // Try to look up the signal parameter names in the object itself
816
817 // build cache if necessary
818 if (customSignals.isEmpty()) {
819 for (int s = 0, sc = obj->signalCount(); s < sc; ++s)
820 customSignals.insert(unit->stringAt(obj->signalAt(s)->nameIndex));
821 const Property *properties = obj->propertyTable();
822 for (int p = 0, pc = obj->propertyCount(); p < pc; ++p)
823 customSignals.insert(unit->stringAt(properties[p].nameIndex()));
824 }
825
826 // if not found, it's not a signal handler but a regular property assignment
827 if (!customSignals.contains(signalName)
828 && (qPropertyName.isEmpty() || !customSignals.contains(qPropertyName))) {
829 continue;
830 }
831 }
832
833 // Binding object to signal means connect the signal to the object's default method.
834 if (bindingType == Binding::Type_Object) {
835 runtimeBindings[i].flags |= RuntimeBinding::IsSignalHandlerObject;
836 continue;
837 }
838
839 if (bindingType != Binding::Type_Script) {
840 return recordError(
841 binding->location,
842 bindingType < Binding::Type_Script
843 ? QQmlTypeCompiler::tr("Cannot assign a value to a signal "
844 "(expecting a script to be run)")
845 : QQmlTypeCompiler::tr("Incorrectly specified signal assignment"));
846 }
847
848 runtimeBindings[i].flags |= flag;
849 }
850 return true;
851 }
852
853 void foldEnums(int objectIndex)
854 {
855 using namespace QV4::CompiledData;
856 const Object *obj = unit->objectAt(objectIndex);
857 RuntimeBinding *runtimeBindings
858 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
859 const Binding *binding = obj->bindingTable();
860 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
861 if (binding->type() != Binding::Type_Script
862 || unit->bindingIsSignalHandler(objectIndex, i)) {
863 continue;
864 }
865
866 if (const std::optional<int> value = evaluateQualifiedEnum(objectIndex, binding)) {
867 runtimeBindings[i].flags |= RuntimeBinding::IsFoldedEnum;
868 runtimeBindings[i].enumValue = *value;
869 }
870 }
871 }
872
873 std::optional<int> evaluateQualifiedEnum(int objectIndex,
874 const QV4::CompiledData::Binding *binding)
875 {
876 const QQmlPropertyCache::ConstPtr cache = unit->propertyCaches.at(objectIndex);
877 if (!cache)
878 return std::nullopt;
879
880 QQmlPropertyResolver resolver(cache);
881 bool notInRevision = false;
882 const QQmlPropertyData *prop =
883 resolver.property(unit->stringAt(binding->propertyNameIndex), &notInRevision);
884 if (!prop || prop->isQList())
885 return std::nullopt;
886 const bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
887 if (!prop->isEnum() && !isIntProp)
888 return std::nullopt;
889
890 if (!prop->isWritable()
891 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
892 recordError(binding->location,
893 QQmlTypeCompiler::tr(
894 "Invalid property assignment: \"%1\" is a read-only property")
895 .arg(unit->stringAt(binding->propertyNameIndex)));
896 return std::nullopt;
897 }
898
899 const QString string = unit->stringAt(binding->stringIndex);
900 if (string.isEmpty() || !string.constData()->isUpper())
901 return std::nullopt;
902
903 const int dot = string.indexOf(u'.');
904 if (dot == -1 || dot == string.size() - 1)
905 return std::nullopt;
906 const int dot2 = string.indexOf(u'.', dot + 1);
907 if (dot2 != -1 && dot2 != string.size() - 1) {
908 if (!string.at(dot + 1).isUpper())
909 return std::nullopt;
910 if (string.indexOf(u'.', dot2 + 1) != -1)
911 return std::nullopt;
912 }
913
914 const QHashedStringRef typeName(string.constData(), dot);
915 const QStringView scopedEnumName =
916 (dot2 != -1 ? QStringView{ string }.mid(dot + 1, dot2 - dot - 1) : QStringView());
917 const QStringView enumValue = QStringView{ string }.mid(dot2 != -1 ? dot2 + 1 : dot + 1);
918
919 if (isIntProp)
920 return evaluateEnum(typeName.toString(), scopedEnumName, enumValue);
921
922 QQmlType type;
923 imports->resolveType(typeLoader, typeName, &type, nullptr, nullptr);
924 if (!type.isValid())
925 return std::nullopt;
926
927 QV4::ResolvedTypeReference *tr =
928 unit->resolvedType(unit->objectAt(objectIndex)->inheritedTypeNameIndex);
929 bool useFastPath = type.isValid() && tr && tr->type() == type;
930 QMetaProperty mprop;
931 QMetaEnum menum;
932 if (useFastPath) {
933 mprop = cache->firstCppMetaObject()->property(prop->coreIndex());
934 menum = mprop.enumerator();
935 if (!menum.isScoped() && scopedEnumName.isEmpty()
936 && typeName != QString::fromUtf8(menum.scope())) {
937 useFastPath = false;
938 }
939 }
940
941 int value = 0;
942 bool ok = false;
943 if (useFastPath) {
944 const QByteArray enumName = enumValue.toUtf8();
945 if (menum.isScoped() && !scopedEnumName.isEmpty()
946 && enumName != scopedEnumName.toUtf8()) {
947 return std::nullopt;
948 }
949 value = mprop.isFlagType() ? menum.keysToValue(enumName.constData(), &ok)
950 : menum.keyToValue(enumName.constData(), &ok);
951 } else {
952 value = scopedEnumName.isEmpty()
953 ? type.enumValue(typeLoader, enumValue, &ok)
954 : type.scopedEnumValue(typeLoader, scopedEnumName, enumValue, &ok);
955 }
956 return ok ? std::optional<int>(value) : std::nullopt;
957 }
958
959 std::optional<int> evaluateEnum(const QString &scope, QStringView enumName,
960 QStringView enumValue)
961 {
962 bool ok = false;
963 QQmlType type;
964 imports->resolveType(typeLoader, scope, &type, nullptr, nullptr);
965 if (!type.isValid())
966 return std::nullopt;
967
968 const int value = enumName.isEmpty()
969 ? type.enumValue(typeLoader,
970 QHashedStringRef(enumValue.constData(), enumValue.size()), &ok)
971 : type.scopedEnumValue(typeLoader, enumName, enumValue, &ok);
972 return ok ? std::optional<int>(value) : std::nullopt;
973 }
974
975 void classifyBindingsToAliases(int objectIndex)
976 {
977 using namespace QV4::CompiledData;
978 const QQmlPropertyCache::ConstPtr propertyCache = unit->propertyCaches.at(objectIndex);
979 if (!propertyCache)
980 return;
981
982 const Object *obj = unit->objectAt(objectIndex);
983 RuntimeBinding *runtimeBindings
984 = unit->runtimeDataForWrite()->objectAt(objectIndex)->bindingTable();
985 QQmlPropertyResolver resolver(propertyCache);
986 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
987 ? propertyCache->parent()->defaultProperty()
988 : propertyCache->defaultProperty();
989
990 const Binding *binding = obj->bindingTable();
991 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
992 if (!isValueBinding(objectIndex, i))
993 continue;
994 bool notInRevision = false;
995 const QQmlPropertyData *pd = binding->propertyNameIndex != 0
996 ? resolver.property(unit->stringAt(binding->propertyNameIndex), &notInRevision)
997 : defaultProperty;
998 if (pd && pd->isAlias())
999 runtimeBindings[i].flags |= RuntimeBinding::IsBindingToAlias;
1000 }
1001 }
1002
1003 void computeBindingOrder(int objectIndex)
1004 {
1005 using namespace QV4::CompiledData;
1006 const Object *obj = unit->objectAt(objectIndex);
1007 const Binding *bindings = obj->bindingTable();
1008 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(objectIndex);
1009 const RuntimeBinding *runtimeBindings = runtimeObject->bindingTable();
1010 const auto isAlias = [&](quint32 b) {
1011 return runtimeBindings[b].flags & RuntimeBinding::IsBindingToAlias;
1012 };
1013
1014 RuntimeBindingIndex *order = runtimeObject->bindingOrder();
1015 uint n = 0;
1016 const auto collect = [&](auto predicate) {
1017 for (quint16 b = 0; b < obj->nBindings; ++b) {
1018 if (predicate(b))
1019 order[n++] = b;
1020 }
1021 };
1022 collect([&](quint16 b) { return isValueBinding(objectIndex, b) && !isAlias(b); });
1023 collect([&](quint16 b) { return unit->bindingIsSignalHandler(objectIndex, b); });
1024 collect([&](quint16 b) { return bindings[b].isAttachedProperty(); });
1025 collect([&](quint16 b) { return bindings[b].isGroupedProperty(); });
1026 collect([&](quint16 b) { return isValueBinding(objectIndex, b) && isAlias(b); });
1027 Q_ASSERT(n == obj->nBindings);
1028 }
1029
1030 bool recordError(const QV4::CompiledData::Location &location, const QString &description)
1031 {
1032 QQmlError error;
1033 error.setUrl(unit->finalUrl());
1034 error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
1035 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
1036 error.setDescription(description);
1037 errors.append(error);
1038 return false;
1039 }
1040
1041 bool deferredAndImmediatePropertyNames(
1042 const QV4::CompiledData::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
1043 QStringList *deferredPropertyNames, QStringList *immediatePropertyNames)
1044 {
1045 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1046 const int deferredNamesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
1047 const int immediateNamesIndex = mo->indexOfClassInfo("ImmediatePropertyNames");
1048
1049 if (deferredNamesIndex != -1) {
1050 if (immediateNamesIndex != -1) {
1051 return recordError(obj->location,
1052 QQmlTypeCompiler::tr("You cannot define both DeferredPropertyNames "
1053 "and ImmediatePropertyNames on the same type."));
1054 }
1055 *deferredPropertyNames
1056 = QString::fromUtf8(mo->classInfo(deferredNamesIndex).value()).split(u',');
1057 } else if (immediateNamesIndex != -1) {
1058 *immediatePropertyNames
1059 = QString::fromUtf8(mo->classInfo(immediateNamesIndex).value()).split(u',');
1060 // If the property contains an empty string, all properties shall be deferred.
1061 if (immediatePropertyNames->isEmpty())
1062 immediatePropertyNames->append(QString());
1063 }
1064 return true;
1065 }
1066
1067 bool scanObject(int objectIndex, ScopeDeferred scopeDeferred)
1068 {
1069 using namespace QV4::CompiledData;
1070
1071 if (objectIndex >= unit->objectCount())
1072 return scanObject(unit->resolvedIndex(objectIndex), scopeDeferred);
1073
1074 const Object *obj = unit->objectAt(objectIndex);
1075 if (obj->idNameIndex != 0)
1076 seenObjectWithId = true;
1077
1078 if (unit->objectIsComponent(objectIndex)) {
1079 Q_ASSERT(obj->nBindings == 1);
1080 const Binding *componentBinding = obj->bindingTable();
1081 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1082 // A Component is separate from its surrounding scope. Its contents cannot be deferred.
1083 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1084 }
1085
1086 const QQmlPropertyCache::ConstPtr propertyCache = unit->propertyCaches.at(objectIndex);
1087 if (!propertyCache)
1088 return true;
1089
1090 QString defaultPropertyName;
1091 const QQmlPropertyData *defaultProperty = nullptr;
1092 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1093 const QQmlPropertyCache *parentCache = propertyCache->parent().data();
1094 defaultPropertyName = parentCache->defaultPropertyName();
1095 defaultProperty = parentCache->defaultProperty();
1096 } else {
1097 defaultPropertyName = propertyCache->defaultPropertyName();
1098 defaultProperty = propertyCache->defaultProperty();
1099 }
1100
1101 QStringList deferredPropertyNames;
1102 QStringList immediatePropertyNames;
1103 if (!deferredAndImmediatePropertyNames(
1104 obj, propertyCache, &deferredPropertyNames, &immediatePropertyNames)) {
1105 return false;
1106 }
1107
1108 QQmlCustomParser *customParser = nullptr;
1109 if (const QV4::ResolvedTypeReference *typeRef
1110 = unit->resolvedType(obj->inheritedTypeNameIndex)) {
1111 const QQmlType type = typeRef->type();
1112 if (type.isValid())
1113 customParser = type.customParser();
1114 }
1115
1116 QQmlPropertyResolver propertyResolver(propertyCache);
1117
1118 RuntimeObject *runtimeObject = unit->runtimeDataForWrite()->objectAt(objectIndex);
1119
1120 const Binding *binding = obj->bindingTable();
1121 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1122 QString name = unit->stringAt(binding->propertyNameIndex);
1123
1124 const auto markCustomParser = [&]() {
1125 runtimeObject->flags |= RuntimeObject::HasCustomParserBindings;
1126 runtimeObject->bindingTable()[i].flags |= RuntimeBinding::IsCustomParserBinding;
1127 };
1128
1129 if (customParser) {
1130 if (binding->type() == Binding::Type_AttachedProperty) {
1131 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1132 markCustomParser();
1133 continue;
1134 }
1135 } else if (QQmlSignalNames::isHandlerName(name)
1136 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1137 markCustomParser();
1138 continue;
1139 }
1140 }
1141
1142 const bool hasPropertyData = [&]() {
1143 if (name.isEmpty()) {
1144 name = defaultPropertyName;
1145 if (defaultProperty)
1146 return true;
1147 } else if (name.constData()->isUpper()) {
1148 // Upper case names cannot be custom-parsed unless they are attached properties
1149 // and the custom parser explicitly accepts them. See above for that case.
1150 return false;
1151 } else {
1152 bool notInRevision = false;
1153 if (propertyResolver.property(
1154 name, &notInRevision, QQmlPropertyResolver::CheckRevision)) {
1155 return true;
1156 }
1157 }
1158
1159 if (!customParser)
1160 return false;
1161
1162 // These signal handlers cannot be custom-parsed. The signal exists.
1163 if (unit->bindingIsSignalHandler(objectIndex, i))
1164 return false;
1165
1166 // If the property isn't found, we may want to custom-parse the binding.
1167 markCustomParser();
1168 return false;
1169 }();
1170
1171 bool seenSubObjectWithId = false;
1172 bool isExternal = false;
1173 if (binding->type() >= Binding::Type_Object) {
1174 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1175 isExternal = !isOwnProperty && binding->isGroupedProperty();
1176 if (isOwnProperty || isExternal) {
1177 qSwap(seenObjectWithId, seenSubObjectWithId);
1178
1179 // Implicit component wrappers are scope boundaries.
1180 const bool isImplicitComponent = unit->implicitComponentForObject(
1181 binding->value.objectIndex) != -1;
1182 const ScopeDeferred objectScope =
1183 !isImplicitComponent
1184 && (isExternal || scopeDeferred == ScopeDeferred::True)
1185 ? ScopeDeferred::True
1186 : ScopeDeferred::False;
1187 const bool subObjectValid = scanObject(binding->value.objectIndex, objectScope);
1188 qSwap(seenObjectWithId, seenSubObjectWithId);
1189 seenObjectWithId |= seenSubObjectWithId;
1190 if (!subObjectValid)
1191 return false;
1192 }
1193 }
1194
1195 bool isDeferred = false;
1196 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1197 if (seenSubObjectWithId) {
1198 return recordError(binding->location,
1199 QQmlTypeCompiler::tr("You cannot assign an id to an object "
1200 "assigned to a deferred property."));
1201 }
1202 if (isExternal || !disableInternalDeferredProperties())
1203 isDeferred = true;
1204 } else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1205 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupedProperty) {
1206 if (isExternal || !disableInternalDeferredProperties())
1207 isDeferred = true;
1208 }
1209 }
1210
1211 if (binding->type() >= Binding::Type_Object && isExternal && !isDeferred
1212 && !customParser) {
1213 return recordError(
1214 binding->location,
1215 QQmlTypeCompiler::tr("Cannot assign to non-existent property \"%1\"")
1216 .arg(name));
1217 }
1218
1219 if (isDeferred) {
1220 runtimeObject->bindingTable()[i].flags |= RuntimeBinding::IsDeferredBinding;
1221 runtimeObject->flags |= RuntimeObject::HasDeferredBindings;
1222 if (binding->type() == Binding::Type_AttachedProperty
1223 || binding->type() == Binding::Type_GroupedProperty) {
1224 unit->runtimeDataForWrite()->objectAt(binding->value.objectIndex)->flags
1225 |= RuntimeObject::PopulatedByDeferredBinding;
1226 }
1227 }
1228 }
1229
1230 return true;
1231 }
1232
1233 QV4::CompiledData::CompilationUnit *unit;
1234 QQmlTypeLoader *typeLoader;
1235 const QQmlImports *imports;
1236 QList<QQmlError> errors;
1237 bool seenObjectWithId = false;
1238};
1239
1240} // namespace
1241
1242QList<QQmlError> QQmlTypeCompiler::computeRuntimeData(
1243 QV4::CompiledData::CompilationUnit *unit, QQmlTypeLoader *typeLoader,
1244 const QQmlImports *imports)
1245{
1246 return RuntimeDataBuilder(unit, typeLoader, imports).build();
1247}
1248
1249QT_END_NAMESPACE
QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
\inmodule QtCore
Combined button and popup list for selecting options.
Definition qjsvalue.h:24
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool resolveDeepAlias(QQmlTypeCompiler *compiler, const QmlIR::Object *targetObject, QStringView property, QStringView subProperty, QQmlPropertyIndex &propIdx, QMetaType targetPropertyType, const QQmlPropertyCacheVector *propertyCaches, const QMap< int, int > &idToObjectIndex)
QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
QQmlTypeCompiler * compiler
int implicitComponentForObject(int childIndex) const
void recordError(const QQmlJS::DiagnosticMessage &message)
const QV4::CompiledData::Unit * qmlUnit() const
QQmlType qmlTypeForComponent(const QString &inlineComponentName=QString()) const
QList< QmlIR::Object * > * qmlObjects() const
QQmlPropertyCacheVector * propertyCaches()
QQmlJS::MemoryPool * memoryPool()
void recordError(const QQmlError &e)
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const
const QQmlPropertyCacheVector * propertyCaches() const
int registerString(const QString &str)
const QV4::Compiler::StringTableGenerator * stringPool() const
void recordError(const QV4::CompiledData::Location &location, const QString &description)
QStringView newStringRef(const QString &string)
int resolvedIndex(int index) const
void addImport(const QString &module, const QString &qualifier, QTypeRevision version)
QQmlRefPointer< QV4::CompiledData::CompilationUnit > compile()
QString stringAt(int idx) const
const QQmlImports * imports() const