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
5
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>
13
14#define COMPILE_EXCEPTION(token, desc)
15 {
16 recordError((token)->location, desc);
17 return false;
18 }
19
21
22DEFINE_BOOL_CONFIG_OPTION(
23 disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
24
25Q_LOGGING_CATEGORY(lcQmlTypeCompiler, "qt.qml.typecompiler");
26
27QQmlTypeCompiler::QQmlTypeCompiler(
28 QQmlTypeLoader *typeLoader, QQmlTypeData *typeData, QmlIR::Document *parsedQML,
29 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
30 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
31 : resolvedTypes(resolvedTypeCache)
32 , loader(typeLoader)
33 , dependencyHasher(dependencyHasher)
34 , document(parsedQML)
35 , typeData(typeData)
36{
37}
38
40{
41 // Build property caches and VME meta object data
42
43 for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
44 it != end; ++it) {
45 QQmlCustomParser *customParser = (*it)->type().customParser();
46 if (customParser)
47 customParsers.insert(it.key(), customParser);
48 }
49
50 QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
51
52
53 {
54 QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(
55 &m_propertyCaches, &pendingGroupPropertyBindings,
56 loader, this, imports(), typeData->typeClassName());
57 QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
58 if (cycleError.isValid()) {
59 recordError(cycleError);
60 return nullptr;
61 }
62 QQmlPropertyCacheCreatorBase::IncrementalResult result;
63 do {
64 result = propertyCacheBuilder.buildMetaObjectsIncrementally();
65 const QQmlError &error = result.error;
66 if (error.isValid()) {
67 recordError(error);
68 return nullptr;
69 } else {
70 // Resolve component boundaries and aliases
71
72 QQmlComponentAndAliasResolver resolver(this, &m_propertyCaches);
73 if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
74 recordError(error);
75 return nullptr;
76 }
77 pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
78 pendingGroupPropertyBindings.clear(); // anything that can be processed is now processed
79 }
80 } while (result.canResume);
81 }
82
83 {
86 }
87
88 {
89 SignalHandlerResolver converter(this);
91 return nullptr;
92 }
93
94 {
95 QQmlEnumTypeResolver enumResolver(this);
96 if (!enumResolver.resolveEnumBindings())
97 return nullptr;
98 }
99
100 {
103 }
104
105 {
106 QQmlAliasAnnotator annotator(this);
108 }
109
110 {
111 QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
112 if (!deferredAndCustomParserBindingScanner.scanObject())
113 return nullptr;
114 }
115
116 if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
117 // Compile JS binding expressions and signal handlers if necessary
118 {
119 // We can compile script strings ahead of time, but they must be compiled
120 // without type optimizations as their scope is always entirely dynamic.
122 sss.scan();
123 }
124
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());
132 return nullptr;
133 }
134 }
135 document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
136 }
137
138 // Generate QML compiled type data structures
139
140 QmlIR::QmlUnitGenerator qmlGenerator;
141 qmlGenerator.generate(*document, dependencyHasher);
142
143 if (!errors.isEmpty())
144 return nullptr;
145
146 return std::move(document->javaScriptCompilationUnit);
147}
148
149void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
150{
151 QQmlError error;
152 error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
153 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
154 error.setDescription(description);
155 error.setUrl(url());
156 errors << error;
157}
158
159void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message)
160{
161 QQmlError error;
162 error.setDescription(message.message);
163 error.setLine(qmlConvertSourceCoordinate<quint32, int>(message.loc.startLine));
164 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(message.loc.startColumn));
165 error.setUrl(url());
166 errors << error;
167}
168
169void QQmlTypeCompiler::recordError(const QQmlError &e)
170{
171 QQmlError error = e;
172 error.setUrl(url());
173 errors << error;
174}
175
177{
178 return document->stringAt(idx);
179}
180
181int QQmlTypeCompiler::registerString(const QString &str)
182{
183 return document->jsGenerator.registerString(str);
184}
185
186int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
187{
188 return document->jsGenerator.registerConstant(v);
189}
190
192{
193 return document->javaScriptCompilationUnit->unitData();
194}
195
196const QQmlImports *QQmlTypeCompiler::imports() const
197{
198 return typeData->imports();
199}
200
202{
203 return &document->objects;
204}
205
207{
208 return &m_propertyCaches;
209}
210
212{
213 return &m_propertyCaches;
214}
215
217{
218 return document->jsParserEngine.pool();
219}
220
222{
223 return document->jsParserEngine.newStringRef(string);
224}
225
227{
228 return &document->jsGenerator.stringTable;
229}
230
231QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const
232{
233 return object->bindingAsString(document, scriptIndex);
234}
235
236void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, QTypeRevision version)
237{
238 const quint32 moduleIdx = registerString(module);
239 const quint32 qualifierIdx = registerString(qualifier);
240
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)
246 return;
247 }
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);
255}
256
257QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
258{
259 return typeData->qmlType(inlineComponentName);
260}
261
263 : compiler(typeCompiler)
264{
265}
266
267SignalHandlerResolver::SignalHandlerResolver(QQmlTypeCompiler *typeCompiler)
268 : QQmlCompilePass(typeCompiler)
269 , typeLoader(typeCompiler->typeLoader())
270 , qmlObjects(*typeCompiler->qmlObjects())
271 , imports(typeCompiler->imports())
272 , customParsers(typeCompiler->customParserCache())
273 , propertyCaches(typeCompiler->propertyCaches())
274{
275}
276
278{
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);
282 if (!cache)
283 continue;
284 if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
285 if (!(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers))
286 continue;
287 }
288 const QString elementName = stringAt(obj->inheritedTypeNameIndex);
289 if (!resolveSignalHandlerExpressions(obj, elementName, cache))
290 return false;
291 }
292 return true;
293}
294
295bool SignalHandlerResolver::resolveSignalHandlerExpressions(
296 const QmlIR::Object *obj, const QString &typeName,
297 const QQmlPropertyCache::ConstPtr &propertyCache,
298 QQmlPropertyResolver::RevisionCheck checkRevision)
299{
300 // map from signal name defined in qml itself to list of parameters
301 QHash<QString, QStringList> customSignals;
302
303 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
304 const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
305 // Attached property?
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();
311 if (!type.isValid())
312 imports->resolveType(typeLoader, bindingPropertyName, &type, nullptr, nullptr);
313
314 const QMetaObject *attachedType = type.attachedPropertiesType(typeLoader);
315 if (!attachedType)
316 COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
317 QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
318
319 // Ignore revisions of signals on attached objects. They are not unqualified.
321 attachedObj, bindingPropertyName, cache,
322 QQmlPropertyResolver::IgnoreRevision)) {
323 return false;
324 }
325
326 continue;
327 }
328
329 QString qPropertyName;
330 QString signalName;
331 if (auto propertyName =
332 QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
333 qPropertyName = *propertyName;
334 signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
335 } else {
336 signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
337 .value_or(QString());
338 }
339 if (signalName.isEmpty())
340 continue;
341
342 QQmlPropertyResolver resolver(propertyCache);
343
344 bool notInRevision = false;
345 const QQmlPropertyData *const signal
346 = resolver.signal(signalName, &notInRevision, checkRevision);
347 const QQmlPropertyData *const signalPropertyData
348 = resolver.property(signalName, /*notInRevision ptr*/nullptr, checkRevision);
349 const QQmlPropertyData *const qPropertyData = !qPropertyName.isEmpty()
350 ? resolver.property(qPropertyName, nullptr, checkRevision)
351 : nullptr;
352 QString finalSignalHandlerPropertyName = signalName;
353 QV4::CompiledData::Binding::Flag flag
354 = QV4::CompiledData::Binding::IsSignalHandlerExpression;
355
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);
361
362 bool unnamedParameter = false;
363
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));
367 if (param.isEmpty())
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));
373 }
374 }
375 } else if (isPropertyObserver) {
376 finalSignalHandlerPropertyName = qPropertyName;
377 flag = QV4::CompiledData::Binding::IsPropertyObserver;
378 } else {
379 if (notInRevision) {
380 // Try assinging it as a property later
381 if (signalPropertyData)
382 continue;
383
384 const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
385
386 auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
387 const QQmlType type = typeRef ? typeRef->type() : QQmlType();
388 if (type.isValid()) {
389 COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.")
390 .arg(typeName, originalPropertyName, type.module())
391 .arg(type.version().majorVersion())
392 .arg(type.version().minorVersion()));
393 } else {
395 binding,
396 tr("\"%1.%2\" is not available due to component versioning.")
397 .arg(typeName, originalPropertyName));
398 }
399 }
400
401 // Try to look up the signal parameter names in the object itself
402
403 // build cache if necessary
404 if (customSignals.isEmpty()) {
405 for (const QmlIR::Signal *signal = obj->firstSignal(); signal; signal = signal->next) {
406 const QString &signalName = stringAt(signal->nameIndex);
407 customSignals.insert(signalName, signal->parameterStringList(compiler->stringPool()));
408 }
409
410 for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
411 const QString propName = stringAt(property->nameIndex());
412 customSignals.insert(propName, QStringList());
413 }
414 }
415
416 QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
417 if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
418 entry = customSignals.constFind(qPropertyName);
419
420 if (entry == customSignals.constEnd()) {
421 // Can't find even a custom signal, then just don't do anything and try
422 // keeping the binding as a regular property assignment.
423 continue;
424 }
425 }
426
427 // Binding object to signal means connect the signal to the object's default method.
428 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
429 binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
430 continue;
431 }
432
433 if (bindingType != QV4::CompiledData::Binding::Type_Script) {
434 if (bindingType < QV4::CompiledData::Binding::Type_Script) {
435 COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
436 } else {
437 COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
438 }
439 }
440
441 binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
442 binding->setFlag(flag);
443 }
444 return true;
445}
446
447QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
448 : QQmlCompilePass(typeCompiler)
449 , qmlObjects(*typeCompiler->qmlObjects())
450 , propertyCaches(typeCompiler->propertyCaches())
451 , imports(typeCompiler->imports())
452{
453}
454
456{
457 for (int i = 0; i < qmlObjects.size(); ++i) {
458 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
459 if (!propertyCache)
460 continue;
461 const QmlIR::Object *obj = qmlObjects.at(i);
462
463 QQmlPropertyResolver resolver(propertyCache);
464
465 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
466 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
467 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
468 || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
469 || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
470 continue;
471
472 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
473 continue;
474
475 const QString propertyName = stringAt(binding->propertyNameIndex);
476 bool notInRevision = false;
477 const QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
478 if (!pd || pd->isQList())
479 continue;
480
481 if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
482 continue;
483
484 if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
485 return false;
486 }
487 }
488
489 return true;
490}
491
492bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView, int enumValue, bool)
493{
494 binding->setType(QV4::CompiledData::Binding::Type_Number);
495 binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
496// binding->setNumberValueInternal((double)enumValue);
497 binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
498 return true;
499}
500
501bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(
502 const QmlIR::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
503 const QQmlPropertyData *prop, QmlIR::Binding *binding)
504{
505 bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
506 if (!prop->isEnum() && !isIntProp)
507 return true;
508
509 if (!prop->isWritable()
510 && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
511 COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property")
512 .arg(stringAt(binding->propertyNameIndex)));
513 }
514
515 Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
516 const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
517 if (!string.constData()->isUpper())
518 return true;
519
520 // reject any "complex" expression (even simple arithmetic)
521 // we do this by excluding everything that is not part of a
522 // valid identifier or a dot
523 for (const QChar &c : string)
524 if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
525 return true;
526
527 // we support one or two '.' in the enum phrase:
528 // * <TypeName>.<EnumValue>
529 // * <TypeName>.<ScopedEnumName>.<EnumValue>
530
531 int dot = string.indexOf(QLatin1Char('.'));
532 if (dot == -1 || dot == string.size()-1)
533 return true;
534
535 int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
536 if (dot2 != -1 && dot2 != string.size()-1) {
537 if (!string.at(dot+1).isUpper())
538 return true;
539 if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
540 return true;
541 }
542
543 QHashedStringRef typeName(string.constData(), dot);
544 const bool isQtObject = (typeName == QLatin1String("Qt"));
545 const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
546 // ### consider supporting scoped enums in Qt namespace
547 const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
548
549 if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
550 // Allow enum assignment to ints.
551 bool ok;
552 int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
553 if (ok) {
554 if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
555 return false;
556 }
557 return true;
558 }
559 QQmlType type;
560 imports->resolveType(compiler->typeLoader(), typeName, &type, nullptr, nullptr);
561
562 if (!type.isValid() && !isQtObject)
563 return true;
564
565 int value = 0;
566 bool ok = false;
567
568 auto *tr = resolvedType(obj->inheritedTypeNameIndex);
569
570 // When these two match, we can short cut the search, unless...
571 bool useFastPath = type.isValid() && tr && tr->type() == type;
572 QMetaProperty mprop;
573 QMetaEnum menum;
574 if (useFastPath) {
575 mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
576 menum = mprop.enumerator();
577 // ...the enumerator merely comes from a related metaobject, but the enum scope does not match
578 // the typename we resolved
579 if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
580 useFastPath = false;;
581 }
582 if (useFastPath) {
583 QByteArray enumName = enumValue.toUtf8();
584 if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
585 return true;
586
587 if (mprop.isFlagType()) {
588 value = menum.keysToValue(enumName.constData(), &ok);
589 } else {
590 value = menum.keyToValue(enumName.constData(), &ok);
591 }
592 } else {
593 // Otherwise we have to search the whole type
594 if (type.isValid()) {
595 if (!scopedEnumName.isEmpty()) {
596 value = type.scopedEnumValue(
597 compiler->typeLoader(), scopedEnumName, enumValue, &ok);
598 } else {
599 value = type.enumValue(compiler->typeLoader(), QHashedStringRef(enumValue), &ok);
600 }
601 } else {
602 QByteArray enumName = enumValue.toUtf8();
603 const QMetaObject *metaObject = &Qt::staticMetaObject;
604 for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
605 QMetaEnum e = metaObject->enumerator(ii);
606 value = e.keyToValue(enumName.constData(), &ok);
607 }
608 }
609 }
610
611 if (!ok)
612 return true;
613
614 return assignEnumToBinding(binding, enumValue, value, isQtObject);
615}
616
617int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, QStringView enumName, QStringView enumValue, bool *ok) const
618{
619 Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
620 *ok = false;
621
622 if (scope != QLatin1String("Qt")) {
623 QQmlType type;
624 imports->resolveType(compiler->typeLoader(), scope, &type, nullptr, nullptr);
625 if (!type.isValid())
626 return -1;
627 if (!enumName.isEmpty())
628 return type.scopedEnumValue(compiler->typeLoader(), enumName, enumValue, ok);
629 return type.enumValue(
630 compiler->typeLoader(),
631 QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
632 }
633
634 const QMetaObject *mo = &Qt::staticMetaObject;
635 int i = mo->enumeratorCount();
636 const QByteArray ba = enumValue.toUtf8();
637 while (i--) {
638 int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
639 if (*ok)
640 return v;
641 }
642 return -1;
643}
644
651
653{
654 scanObjectRecursively(/*root object*/0);
655 for (int i = 0; i < qmlObjects.size(); ++i)
656 if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
657 scanObjectRecursively(i);
658}
659
660void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
661{
662 const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
663 if (!annotateScriptBindings)
664 annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
665 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
666 switch (binding->type()) {
667 case QV4::CompiledData::Binding::Type_Script:
668 if (annotateScriptBindings) {
669 binding->stringIndex = compiler->registerString(
670 compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
671 }
672 break;
673 case QV4::CompiledData::Binding::Type_Object:
674 case QV4::CompiledData::Binding::Type_AttachedProperty:
675 case QV4::CompiledData::Binding::Type_GroupProperty:
676 scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
677 break;
678 default:
679 break;
680 }
681 }
682}
683
690
692{
693 for (int i = 0; i < qmlObjects.size(); ++i) {
694 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
695 if (!propertyCache)
696 continue;
697
698 const QmlIR::Object *obj = qmlObjects.at(i);
699
700 QQmlPropertyResolver resolver(propertyCache);
701 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
702
703 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
704 if (!binding->isValueBinding())
705 continue;
706 bool notInRevision = false;
707 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
708 if (pd && pd->isAlias())
709 binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
710 }
711 }
712}
713
721
723{
724 const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
725 for (int i = 0; i < qmlObjects.size(); ++i) {
726 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
727 if (!propertyCache)
728 continue;
729
730 const QmlIR::Object *obj = qmlObjects.at(i);
731
732 QQmlPropertyResolver resolver(propertyCache);
733 const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
734
735 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
736 if (binding->type() != QV4::CompiledData::Binding::Type_Script)
737 continue;
738 bool notInRevision = false;
739 const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
740 if (!pd || pd->propType() != scriptStringMetaType)
741 continue;
742
743 QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
744 binding->stringIndex = compiler->registerString(script);
745 }
746 }
747}
748
749template<>
750void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
751 QmlIR::Object *object) const
752{
753 object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
754}
755
756template<>
757bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(int index) const
758{
759 m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
760 return true;
761}
762
763template<>
764void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(int index) const
765{
766 m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
767}
768
769template<>
770bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlIR::Binding *binding)
771{
772 QQmlJS::MemoryPool *pool = m_compiler->memoryPool();
773 QList<QmlIR::Object *> *qmlObjects = m_compiler->qmlObjects();
774
775 // emulate "import QML 1.0" and then wrap the component in "QML.Component {}"
776 QQmlType componentType = QQmlMetaType::qmlType(
777 &QQmlComponent::staticMetaObject, QStringLiteral("QML"),
778 QTypeRevision::fromVersion(1, 0));
779 Q_ASSERT(componentType.isValid());
780 const QString qualifier = QStringLiteral("QML");
781
782 m_compiler->addImport(componentType.module(), qualifier, componentType.version());
783
784 QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
785 syntheticComponent->init(
786 pool,
787 m_compiler->registerString(
788 qualifier + QLatin1Char('.') + componentType.elementName()),
789 m_compiler->registerString(QString()), binding->valueLocation);
790 syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
791
792 if (!m_compiler->resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
793 auto typeRef = new QV4::ResolvedTypeReference;
794 typeRef->setType(componentType);
795 typeRef->setVersion(componentType.version());
796 m_compiler->resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
797 }
798
799 qmlObjects->append(syntheticComponent);
800 const int componentIndex = qmlObjects->size() - 1;
801 // Keep property caches symmetric
802 QQmlPropertyCache::ConstPtr componentCache
803 = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
804 m_propertyCaches->append(componentCache);
805
806 QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
807 *syntheticBinding = *binding;
808
809 // The synthetic binding inside Component has no name. It's just "Component { Foo {} }".
810 syntheticBinding->propertyNameIndex = 0;
811
812 syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
813 QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
814 Q_ASSERT(error.isEmpty());
815 Q_UNUSED(error);
816
817 binding->value.objectIndex = componentIndex;
818
819 m_componentRoots.append(componentIndex);
820 return true;
821}
822
823template<>
824void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
825 const CompiledObject &component, CompiledBinding *binding)
826{
827 Q_UNUSED(component);
828 // We cannot make it fail here. It might be a custom-parsed property
829 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
830 if (targetObjectIndex != -1)
831 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
832}
833
834template<>
835typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
836QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
837 const CompiledObject &component, int objectIndex,
838 QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> *aliasCacheCreator, QQmlError *error)
839{
840 // TODO: This method should not modify the aliases themselves. Rather, all information
841 // needed for handling them later should be stored in the property cache.
842 // Some of the information calculated here could be calculated already at compile time.
843 // See QTBUG-136572.
844
845 Q_UNUSED(component);
846
847 const QmlIR::Object * const obj = m_compiler->objectAt(objectIndex);
848 if (!obj->aliasCount())
849 return AllAliasesResolved;
850
851 int aliasIndex = 0;
852 int numSkippedAliases = 0;
853 bool hasUnresolvedLocalAliases = false;
854
855 for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
856 if (resolvedAliases.contains(alias)) {
857 ++numSkippedAliases;
858 continue;
859 }
860
861
862 const int idIndex = alias->idIndex();
863 const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
864 if (targetObjectIndex == -1) {
865 *error = qQmlCompileError(
866 alias->referenceLocation,
867 QQmlComponentAndAliasResolverBase::tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
868 break;
869 }
870
871 const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
872 Q_ASSERT(targetObject->id >= 0);
873 alias->setTargetObjectId(targetObject->id);
874 alias->setIsAliasToLocalAlias(false);
875
876 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
877
878 QStringView property;
879 QStringView subProperty;
880
881 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
882 if (propertySeparator != -1) {
883 property = QStringView{aliasPropertyValue}.left(propertySeparator);
884 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
885 } else
886 property = QStringView(aliasPropertyValue);
887
888 QQmlPropertyIndex propIdx;
889
890 if (property.isEmpty()) {
891 alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
892 } else {
893 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
894 if (!targetCache) {
895 *error = qQmlCompileError(
896 alias->referenceLocation,
897 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
898 break;
899 }
900
901 QQmlPropertyResolver resolver(targetCache);
902
903 const QQmlPropertyData *targetProperty = resolver.property(
904 property.toString(), nullptr, QQmlPropertyResolver::IgnoreRevision);
905
906 // If it's an alias that we haven't resolved yet, try again later.
907 if (!targetProperty) {
908 bool aliasPointsToOtherAlias = false;
909 int localAliasIndex = 0;
910 auto targetAlias = targetObject->aliasesBegin();
911 for (const auto end = targetObject->aliasesEnd(); targetAlias != end;
912 ++targetAlias, ++localAliasIndex) {
913 if (stringAt(targetAlias->nameIndex()) == property) {
914 aliasPointsToOtherAlias = true;
915 break;
916 }
917 }
918 if (aliasPointsToOtherAlias) {
919 if (targetObjectIndex != objectIndex) {
920 // Don't continue, yet. We need to respect the order of objects.
921 alias->setIdIndex(idIndex);
922 return aliasIndex == numSkippedAliases
923 ? NoAliasResolved
924 : SomeAliasesResolved;
925 }
926
927 if (resolvedAliases.contains(targetAlias)) {
928 // Target already resolved. We can set the alias right away.
929 alias->localAliasIndex = localAliasIndex;
930 alias->setIsAliasToLocalAlias(true);
931 if (!appendAliasToPropertyCache(
932 &component, alias, objectIndex, aliasIndex, -1,
933 aliasCacheCreator, error)) {
934 break;
935 }
936 continue;
937 }
938
939 // Target isn't resolved yet, but it's in the same object.
940 // Continue with the other aliases.
941 alias->setIdIndex(idIndex);
942 // Try again later and resolve the target alias first.
943 ++numSkippedAliases;
944 hasUnresolvedLocalAliases = true;
945 continue;
946 }
947 }
948
949 if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
950 *error = qQmlCompileError(
951 alias->referenceLocation,
952 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
953 break;
954 }
955
956 propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
957
958 if (!subProperty.isEmpty()) {
959 const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
960 if (!valueTypeMetaObject) {
961 // could be a deep alias
962 bool isDeepAlias = subProperty.at(0).isLower();
963 if (isDeepAlias) {
964 isDeepAlias = false;
965 for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
966 auto binding = *it;
967 if (m_compiler->stringAt(binding.propertyNameIndex) == property) {
968 resolver = QQmlPropertyResolver(m_propertyCaches->at(binding.value.objectIndex));
969 const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
970 if (actualProperty) {
971 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
972 isDeepAlias = true;
973 }
974 }
975 }
976 }
977 if (!isDeepAlias) {
978 *error = qQmlCompileError(
979 alias->referenceLocation,
980 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
981 break;
982 }
983 } else {
984
985 int valueTypeIndex =
986 valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
987 if (valueTypeIndex == -1) {
988 *error = qQmlCompileError(
989 alias->referenceLocation,
990 QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
991 break;
992 }
993 Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
994
995 propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex);
996 }
997 } else {
998 if (targetProperty->isQObject())
999 alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
1000 }
1001 }
1002
1003 if (!appendAliasToPropertyCache(
1004 &component, alias, objectIndex, aliasIndex, propIdx.toEncoded(),
1005 aliasCacheCreator, error)) {
1006 break;
1007 }
1008 }
1009
1010 if (numSkippedAliases == aliasIndex)
1011 return NoAliasResolved;
1012
1013 if (aliasIndex == obj->aliasCount() && !hasUnresolvedLocalAliases)
1014 return AllAliasesResolved;
1015
1016 return SomeAliasesResolved;
1017}
1018
1019QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
1020 : QQmlCompilePass(typeCompiler)
1021 , qmlObjects(typeCompiler->qmlObjects())
1022 , propertyCaches(typeCompiler->propertyCaches())
1023 , customParsers(typeCompiler->customParserCache())
1024 , _seenObjectWithId(false)
1025{
1026}
1027
1029{
1030 for (int i = 0; i < qmlObjects->size(); ++i) {
1031 if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
1032 && !scanObject(i, ScopeDeferred::False)) {
1033 return false;
1034 }
1035 }
1036 return scanObject(/*root object*/0, ScopeDeferred::False);
1037}
1038
1040 int objectIndex, ScopeDeferred scopeDeferred)
1041{
1042 using namespace QV4::CompiledData;
1043
1044 QmlIR::Object *obj = qmlObjects->at(objectIndex);
1045 if (obj->idNameIndex != 0)
1046 _seenObjectWithId = true;
1047
1048 if (obj->flags & Object::IsComponent) {
1049 Q_ASSERT(obj->bindingCount() == 1);
1050 const Binding *componentBinding = obj->firstBinding();
1051 Q_ASSERT(componentBinding->type() == Binding::Type_Object);
1052 // Components are separate from their surrounding scope. They cannot be deferred.
1053 return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
1054 }
1055
1056 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1057 if (!propertyCache)
1058 return true;
1059
1060 QString defaultPropertyName;
1061 const QQmlPropertyData *defaultProperty = nullptr;
1062 if (obj->indexOfDefaultPropertyOrAlias != -1) {
1063 const QQmlPropertyCache *cache = propertyCache->parent().data();
1064 defaultPropertyName = cache->defaultPropertyName();
1065 defaultProperty = cache->defaultProperty();
1066 } else {
1067 defaultPropertyName = propertyCache->defaultPropertyName();
1068 defaultProperty = propertyCache->defaultProperty();
1069 }
1070
1071 QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
1072
1073 QQmlPropertyResolver propertyResolver(propertyCache);
1074
1075 QStringList deferredPropertyNames;
1076 QStringList immediatePropertyNames;
1077 {
1078 const QMetaObject *mo = propertyCache->firstCppMetaObject();
1079 const int deferredNamesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
1080 const int immediateNamesIndex = mo->indexOfClassInfo("ImmediatePropertyNames");
1081 if (deferredNamesIndex != -1) {
1082 if (immediateNamesIndex != -1) {
1083 COMPILE_EXCEPTION(obj, tr("You cannot define both DeferredPropertyNames and "
1084 "ImmediatePropertyNames on the same type."));
1085 }
1086 const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
1087 deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1088 } else if (immediateNamesIndex != -1) {
1089 const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
1090 immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
1091
1092 // If the property contains an empty string, all properties shall be deferred.
1093 if (immediatePropertyNames.isEmpty())
1094 immediatePropertyNames.append(QString());
1095 }
1096 }
1097
1098 for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
1099 QString name = stringAt(binding->propertyNameIndex);
1100
1101 if (customParser) {
1102 if (binding->type() == Binding::Type_AttachedProperty) {
1103 if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
1104 binding->setFlag(Binding::IsCustomParserBinding);
1105 obj->flags |= Object::HasCustomParserBindings;
1106 continue;
1107 }
1108 } else if (QQmlSignalNames::isHandlerName(name)
1109 && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
1110 obj->flags |= Object::HasCustomParserBindings;
1111 binding->setFlag(Binding::IsCustomParserBinding);
1112 continue;
1113 }
1114 }
1115
1116 const bool hasPropertyData = [&]() {
1117 if (name.isEmpty()) {
1118 name = defaultPropertyName;
1119 if (defaultProperty)
1120 return true;
1121 } else if (name.constData()->isUpper()) {
1122 // Upper case names cannot be custom-parsed unless they are attached properties
1123 // and the custom parser explicitly accepts them. See above for that case.
1124 return false;
1125 } else {
1126 bool notInRevision = false;
1127 if (propertyResolver.property(
1128 name, &notInRevision, QQmlPropertyResolver::CheckRevision)) {
1129 return true;
1130 }
1131 }
1132
1133 if (!customParser)
1134 return false;
1135
1136 const Binding::Flags bindingFlags = binding->flags();
1137 if (bindingFlags & Binding::IsSignalHandlerExpression
1138 || bindingFlags & Binding::IsSignalHandlerObject
1139 || bindingFlags & Binding::IsPropertyObserver) {
1140 // These signal handlers cannot be custom-parsed. We have already established
1141 // that the signal exists.
1142 return false;
1143 }
1144
1145 // If the property isn't found, we may want to custom-parse the binding.
1146 obj->flags |= Object::HasCustomParserBindings;
1147 binding->setFlag(Binding::IsCustomParserBinding);
1148 return false;
1149 }();
1150
1151 bool seenSubObjectWithId = false;
1152 bool isExternal = false;
1153 if (binding->type() >= Binding::Type_Object) {
1154 const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
1155 isExternal = !isOwnProperty && binding->isGroupProperty();
1156 if (isOwnProperty || isExternal) {
1157 qSwap(_seenObjectWithId, seenSubObjectWithId);
1158 const bool subObjectValid = scanObject(
1159 binding->value.objectIndex,
1160 (isExternal || scopeDeferred == ScopeDeferred::True)
1161 ? ScopeDeferred::True
1162 : ScopeDeferred::False);
1163 qSwap(_seenObjectWithId, seenSubObjectWithId);
1164 if (!subObjectValid)
1165 return false;
1166 _seenObjectWithId |= seenSubObjectWithId;
1167 }
1168 }
1169
1170 bool isDeferred = false;
1171 if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
1172 if (seenSubObjectWithId) {
1173 COMPILE_EXCEPTION(binding, tr("You cannot assign an id to an object assigned "
1174 "to a deferred property."));
1175 }
1176 if (isExternal || !disableInternalDeferredProperties())
1177 isDeferred = true;
1178 } else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
1179 if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
1180 if (isExternal || !disableInternalDeferredProperties())
1181 isDeferred = true;
1182 }
1183 }
1184
1185 if (binding->type() >= Binding::Type_Object) {
1186 if (isExternal && !isDeferred && !customParser) {
1188 binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
1189 }
1190 }
1191
1192 if (isDeferred) {
1193 binding->setFlag(Binding::IsDeferredBinding);
1194 obj->flags |= Object::HasDeferredBindings;
1195 }
1196 }
1197
1198 return true;
1199}
1200
1208
1210{
1211 for (int i = 0; i < qmlObjects.size(); ++i)
1212 mergeDefaultProperties(i);
1213}
1214
1215void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
1216{
1217 QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
1218 if (!propertyCache)
1219 return;
1220
1221 QmlIR::Object *object = qmlObjects.at(objectIndex);
1222
1223 QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
1224 QmlIR::Binding *bindingsToReinsert = nullptr;
1225 QmlIR::Binding *tail = nullptr;
1226
1227 QmlIR::Binding *previousBinding = nullptr;
1228 QmlIR::Binding *binding = object->firstBinding();
1229 while (binding) {
1230 if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) {
1231 previousBinding = binding;
1232 binding = binding->next;
1233 continue;
1234 }
1235
1236 QmlIR::Binding *toReinsert = binding;
1237 binding = object->unlinkBinding(previousBinding, binding);
1238
1239 if (!tail) {
1240 bindingsToReinsert = toReinsert;
1241 tail = toReinsert;
1242 } else {
1243 tail->next = toReinsert;
1244 tail = tail->next;
1245 }
1246 tail->next = nullptr;
1247 }
1248
1249 binding = bindingsToReinsert;
1250 while (binding) {
1251 QmlIR::Binding *toReinsert = binding;
1252 binding = binding->next;
1253 object->insertSorted(toReinsert);
1254 }
1255}
1256
1257QT_END_NAMESPACE
QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler)
QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompiler)
QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
Combined button and popup list for selecting options.
Definition qjsvalue.h:24
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
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