5#include <private/qqmlcomponentandaliasresolver_p.h>
6#include <private/qqmlengine_p.h>
7#include <private/qqmlirbuilder_p.h>
8#include <private/qqmlirloader_p.h>
9#include <private/qqmlpropertycachecreator_p.h>
10#include <private/qqmlpropertyvalidator_p.h>
11#include <private/qqmlscriptblob_p.h>
12#include <private/qqmlscriptdata_p.h>
13#include <private/qqmltypecompiler_p.h>
14#include <private/qqmltypedata_p.h>
15#include <private/qqmltypeloaderqmldircontent_p.h>
17#include <QtCore/qloggingcategory.h>
18#include <QtCore/qcryptographichash.h>
26QString QQmlTypeData::TypeReference::qualifiedName()
const
29 if (!prefix.isEmpty()) {
30 result = prefix + QLatin1Char(
'.');
32 result.append(type.qmlTypeName());
36QQmlTypeData::QQmlTypeData(
const QUrl &url, QQmlTypeLoader *manager)
37 : QQmlNotifyingBlob(url, QmlFile, manager),
38 m_typesResolved(
false), m_implicitImportLoaded(
false)
43QQmlTypeData::~QQmlTypeData()
46 m_compositeSingletons.clear();
47 m_resolvedTypes.clear();
50QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit()
const
52 return m_compiledData.data();
55QQmlType QQmlTypeData::qmlType(
const QString &inlineComponentName)
const
57 if (inlineComponentName.isEmpty())
59 return m_inlineComponentData[inlineComponentName].qmlType;
62bool QQmlTypeData::tryLoadFromDiskCache()
64 assertTypeLoaderThread();
66 if (!m_backupSourceCode.isCacheable())
69 if (!m_typeLoader->readCacheFile())
72 auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
75 if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
76 qCDebug(DBG_DISK_CACHE) <<
"Error loading" << urlString() <<
"from disk cache:" << error;
81 if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
86 return loadFromDiskCache(unit);
89bool QQmlTypeData::loadFromDiskCache(
const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
91 assertTypeLoaderThread();
93 m_compiledData = unit;
95 QList<QV4::CompiledData::InlineComponent> ics;
96 for (
int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
97 auto object = m_compiledData->objectAt(i);
98 m_typeReferences.collectFromObject(object);
99 const auto inlineComponentTable = object->inlineComponentTable();
100 for (
auto i = 0; i != object->nInlineComponents; ++i) {
101 ics.push_back(inlineComponentTable[i]);
105 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
110 if (!finalUrl().scheme().isEmpty()) {
111 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String(
"qmldir")));
112 if (!QQmlImports::isLocal(qmldirUrl)) {
113 if (!loadImplicitImport())
117 for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
118 const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
119 if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(
".")
120 && import->qualifierIndex == 0
121 && !import->version.hasMajorVersion()
122 && !import->version.hasMinorVersion()) {
123 QList<QQmlError> errors;
124 auto pendingImport = std::make_shared<PendingImport>(
125 this, import, QQmlImports::ImportNoFlag);
126 pendingImport->precedence = QQmlImportInstance::Implicit;
127 if (!fetchQmldir(qmldirUrl, std::move(pendingImport), 1, &errors)) {
137 for (
int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
138 const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
139 QList<QQmlError> errors;
140 if (!addImport(import, {}, &errors)) {
141 Q_ASSERT(errors.size());
142 QQmlError error(errors.takeFirst());
143 error.setUrl(m_importCache->baseUrl());
144 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(import->location.line()));
145 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(import->location.column()));
146 errors.prepend(error);
152 for (
auto&& ic: ics) {
153 QString
const nameString = m_compiledData->stringAt(ic.nameIndex);
154 auto importUrl = finalUrl();
155 importUrl.setFragment(nameString);
156 auto import =
new QQmlImportInstance();
157 m_importCache->addInlineComponentImport(import, nameString, importUrl);
164void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::allocateNamedObjects(
165 const QV4::CompiledData::Object *object)
const
171bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::markAsComponent(
int index)
const
173 return m_compiler->objectAt(index)->hasFlag(QV4::CompiledData::Object::IsComponent);
177void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::setObjectId(
int index)
const
185void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveGeneralizedGroupProperty(
186 const CompiledObject &component, CompiledBinding *binding)
189 for (
int i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
190 const int candidateIndex = component.namedObjectsInComponentTable()[i];
191 if (m_compiler->objectAt(candidateIndex)->idNameIndex == binding->propertyNameIndex) {
192 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(candidateIndex));
201typename QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::AliasResolutionResult
202QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliasesInObject(
203 const CompiledObject &component,
int objectIndex,
204 QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> *aliasCacheCreator,
207 const CompiledObject *obj = m_compiler->objectAt(objectIndex);
209 const auto doAppendAlias = [&](
const QV4::CompiledData::Alias *alias,
int encodedIndex,
210 int resolvedTargetObjectId) {
211 return appendAliasToPropertyCache(
212 &component, alias, objectIndex, aliasIndex++, encodedIndex,
213 resolvedTargetObjectId, aliasCacheCreator, error);
216 const auto handleDeepAlias = [&](
217 const QV4::CompiledData::Alias *alias,
const QQmlPropertyCache::ConstPtr &propertyCache,
218 int coreIndex, QStringView subProperty,
int resolvedTargetObjectId)
220 const QQmlPropertyResolver resolver = QQmlPropertyResolver(propertyCache);
221 const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
223 return DeepAliasResult::NoProperty;
226 alias, QQmlPropertyIndex(coreIndex, actualProperty->coreIndex()).toEncoded(),
227 resolvedTargetObjectId)) {
228 return DeepAliasResult::Success;
231 return DeepAliasResult::CannotAppend;
234 for (
auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
235 if (resolvedAliases.contains(alias)) {
240 int targetObjectIndex = -1;
241 for (
int i = 0, end = component.namedObjectsInComponentCount(); i < end; ++i) {
242 const int candidateIndex = component.namedObjectsInComponentTable()[i];
243 if (m_compiler->objectAt(candidateIndex)->idNameIndex == alias->idIndex()) {
244 targetObjectIndex = candidateIndex;
248 if (targetObjectIndex == -1) {
249 *error = qQmlCompileError(
250 alias->referenceLocation(),
251 tr(
"Invalid alias reference. Unable to find id \"%1\"")
252 .arg(stringAt(alias->idIndex())));
255 const QV4::CompiledData::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
256 const int resolvedTargetObjectId = targetObject->objectId();
258 QStringView property;
259 QStringView subProperty;
261 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
262 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
263 if (propertySeparator != -1) {
264 property = QStringView{aliasPropertyValue}.left(propertySeparator);
265 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
267 property = QStringView(aliasPropertyValue);
270 if (property.isEmpty()) {
271 if (doAppendAlias(alias, -1, resolvedTargetObjectId))
273 return SomeAliasesResolved;
276 Q_ASSERT(!property.isEmpty());
277 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
278 Q_ASSERT(targetCache);
280 const QQmlPropertyResolver resolver(targetCache);
281 const QQmlPropertyData *targetProperty = resolver.property(property.toString());
283 return SomeAliasesResolved;
285 const int coreIndex = targetProperty->coreIndex();
286 if (subProperty.isEmpty()) {
288 alias, QQmlPropertyIndex(coreIndex).toEncoded(), resolvedTargetObjectId)) {
291 return SomeAliasesResolved;
294 if (
const QMetaObject *valueTypeMetaObject
295 = QQmlMetaType::metaObjectForValueType(targetProperty->propType())) {
296 const int valueTypeIndex = valueTypeMetaObject->indexOfProperty(
297 subProperty.toString().toUtf8().constData());
298 if (valueTypeIndex == -1)
299 return SomeAliasesResolved;
302 alias, QQmlPropertyIndex(coreIndex, valueTypeIndex).toEncoded(),
303 resolvedTargetObjectId)) {
307 return SomeAliasesResolved;
310 Q_ASSERT(subProperty.at(0).isLower());
312 bool foundDeepAliasInBindings =
false;
313 for (
auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
314 if (m_compiler->stringAt(it->propertyNameIndex) != property)
317 switch (handleDeepAlias(
318 alias, m_propertyCaches->at(it->value.objectIndex), coreIndex, subProperty,
319 resolvedTargetObjectId)) {
320 case DeepAliasResult::NoProperty:
322 case DeepAliasResult::CannotAppend:
323 return SomeAliasesResolved;
324 case DeepAliasResult::Success:
325 foundDeepAliasInBindings =
true;
332 if (foundDeepAliasInBindings)
335 const QQmlPropertyCache::ConstPtr typeCache
336 = QQmlMetaType::propertyCacheForType(targetProperty->propType());
338 return SomeAliasesResolved;
340 switch (handleDeepAlias(alias, typeCache, coreIndex, subProperty, resolvedTargetObjectId)) {
341 case DeepAliasResult::NoProperty:
342 case DeepAliasResult::CannotAppend:
343 return SomeAliasesResolved;
344 case DeepAliasResult::Success:
349 return AllAliasesResolved;
352QQmlError QQmlTypeData::createTypeAndPropertyCaches(
353 const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
354 const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
356 assertTypeLoaderThread();
358 Q_ASSERT(m_compiledData);
359 m_compiledData->typeNameCache = typeNameCache;
360 m_compiledData->resolvedTypes = resolvedTypeCache;
361 m_compiledData->inlineComponentData = m_inlineComponentData;
362 m_compiledData->qmlType = m_qmlType;
364 QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
367 QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(
368 &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, m_typeLoader,
369 m_compiledData.data(), m_importCache.data(), typeClassName());
371 QQmlError error = propertyCacheCreator.verifyNoICCycle();
375 QQmlPropertyCacheCreatorBase::IncrementalResult result;
377 result = propertyCacheCreator.buildMetaObjectsIncrementally();
378 if (result.error.isValid()) {
381 QQmlComponentAndAliasResolver resolver(
382 m_compiledData.data(), &m_compiledData->propertyCaches);
383 if (
const QQmlError error = resolver.resolve(result.processedRoot);
387 pendingGroupPropertyBindings.resolveMissingPropertyCaches(
388 &m_compiledData->propertyCaches);
389 pendingGroupPropertyBindings.clear();
392 }
while (result.canResume);
395 pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches);
401using InlineComponentData = QV4::CompiledData::InlineComponentData;
403template<
typename ObjectContainer>
405 const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
407 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) {
408 Q_ASSERT(icData->empty());
409 for (
int i = 0; i != container->objectCount(); ++i) {
410 auto root = container->objectAt(i);
411 for (
auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
414 InlineComponentData icDatum(
415 QQmlMetaType::findOrCreateFactualInlineComponentType(
416 baseUrl, container->stringAt(it->nameIndex), compilationUnit),
417 int(it->objectIndex),
int(it->nameIndex));
419 icData->insert(container->stringAt(it->nameIndex), icDatum);
425bool QQmlTypeData::checkScripts()
428 for (
int ii = 0; ii < m_scripts.size(); ++ii) {
429 const ScriptReference &script = m_scripts.at(ii);
430 Q_ASSERT(script.script->isCompleteOrError());
431 if (script.script->isError()) {
434 QQmlTypeLoader::tr(
"Script %1 unavailable").arg(script.script->urlString()));
441void QQmlTypeData::createError(
const TypeReference &type,
const QString &message)
443 createError(type, message, type.typeData ? type.typeData->errors() : QList<QQmlError>());
446void QQmlTypeData::createError(
const ScriptReference &script,
const QString &message)
448 createError(script, message, script.script ? script.script->errors() : QList<QQmlError>());
451bool QQmlTypeData::checkDependencies()
454 for (
auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end();
456 const TypeReference &type = *it;
457 Q_ASSERT(!type.typeData
458 || type.typeData->isCompleteOrError()
459 || type.type.isInlineComponentType());
461 if (type.typeData && type.typeData->isError()) {
462 const QString &typeName = stringAt(it.key());
463 createError(type, QQmlTypeLoader::tr(
"Type %1 unavailable").arg(typeName));
467 if (!type.selfReference && type.type.isInlineComponentType()) {
468 const QString icName = type.type.elementName();
469 Q_ASSERT(!icName.isEmpty());
472 if (type.typeData && type.typeData->compilationUnit()->inlineComponentId(icName) >= 0)
475 const QString typeName = stringAt(it.key());
476 const qsizetype lastDot = typeName.lastIndexOf(u'.');
479 QQmlTypeLoader::tr(
"Type %1 has no inline component type called %2")
480 .arg(QStringView{typeName}.left(lastDot), icName));
488bool QQmlTypeData::checkCompositeSingletons()
491 for (
int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
492 const TypeReference &type = m_compositeSingletons.at(ii);
493 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
494 if (type.typeData && type.typeData->isError()) {
495 QString typeName = type.type.qmlTypeName();
496 createError(type, QQmlTypeLoader::tr(
"Type %1 unavailable").arg(typeName));
504void QQmlTypeData::createQQmlType()
506 if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
507 const bool isSingleton = m_document
508 ? m_document.data()->isSingleton()
509 : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
510 m_qmlType = QQmlMetaType::findCompositeType(
511 url(), m_compiledData, isSingleton
512 ? QQmlMetaType::Singleton
513 : QQmlMetaType::NonSingleton);
514 m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
518bool QQmlTypeData::rebuildFromSource()
522 m_typeReferences.clear();
524 m_namespaces.clear();
525 m_compositeSingletons.clear();
527 m_resolvedTypes.clear();
528 m_typesResolved =
false;
530 m_qmlType = QQmlType();
531 m_typeClassName.clear();
533 m_inlineComponentData.clear();
534 m_compiledData.reset();
536 m_implicitImportLoaded =
false;
538 m_importCache.adopt(
new QQmlImports);
539 m_unresolvedImports.clear();
541 if (!loadFromSource())
544 continueLoadFromIR();
552 if (!checkDependencies())
555 if (!checkCompositeSingletons())
560 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
564void QQmlTypeData::done()
566 assertTypeLoaderThread();
568 auto cleanup = qScopeGuard([
this]{
569 m_backupSourceCode = SourceCodeData();
571 m_typeReferences.clear();
573 const auto encounteredErrors = errors();
574 for (
const QQmlError &e : encounteredErrors)
575 qCDebug(DBG_DISK_CACHE) << e.toString();
576 m_compiledData.reset();
579 m_resolvedTypes.clear();
580 m_compositeSingletons.clear();
591 if (!checkDependencies())
594 if (!checkCompositeSingletons())
600 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
602 setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
604 QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
605 QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
608 const bool verifyCaches = !m_compiledData
609 || (m_compiledData->resolvedTypes.isEmpty() && !m_compiledData->typeNameCache);
612 QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
613 if (error.isValid()) {
615 qDeleteAll(resolvedTypeCache);
620 const auto dependencyHasher = [&resolvedTypeCache,
this]() {
621 return typeLoader()->hashDependencies(&resolvedTypeCache, m_compositeSingletons);
625 if (m_document.isNull() && verifyCaches) {
626 const QQmlError error = createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
627 if (error.isValid() || !m_compiledData->verifyChecksum(dependencyHasher)) {
629 if (error.isValid()) {
630 qCDebug(DBG_DISK_CACHE)
631 <<
"Failed to create property caches for"
632 << m_compiledData->fileName()
633 <<
"because" << error.description();
635 qCDebug(DBG_DISK_CACHE)
636 <<
"Checksum mismatch for cached version of"
637 << m_compiledData->fileName();
640 resolvedTypeCache.clear();
641 typeNameCache.reset();
643 if (!rebuildFromSource())
646 const QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
647 if (error.isValid()) {
649 qDeleteAll(resolvedTypeCache);
655 if (!m_document.isNull()) {
656 Q_ASSERT(verifyCaches);
658 compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
664 m_compiledData->inlineComponentData = m_inlineComponentData;
667 QQmlPropertyValidator validator(typeLoader(), m_importCache.data(), m_compiledData);
668 QList<QQmlError> errors = validator.validate();
669 if (!errors.isEmpty()) {
675 m_compiledData->finalizeCompositeType(qmlType());
679 QQmlType type = QQmlMetaType::qmlType(finalUrl());
680 if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
681 if (!type.isValid()) {
683 error.setDescription(QQmlTypeLoader::tr(
"No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
686 }
else if (!type.isCompositeSingleton()) {
688 error.setDescription(QQmlTypeLoader::tr(
"pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
695 if (type.isValid() && type.isCompositeSingleton()) {
696 QString typeName = type.qmlTypeName();
697 setError(QQmlTypeLoader::tr(
"qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
705 m_compiledData->dependentScripts.reserve(m_scripts.size());
706 for (
int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
707 const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
709 QStringView qualifier(script.qualifier);
710 QString enclosingNamespace;
712 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char(
'.'));
713 if (lastDotIndex != -1) {
714 enclosingNamespace = qualifier.left(lastDotIndex).toString();
715 qualifier = qualifier.mid(lastDotIndex+1);
718 m_compiledData->typeNameCache->add(
719 qualifier.toString(), scriptIndex, enclosingNamespace);
720 QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
721 m_compiledData->dependentScripts << scriptData;
726bool QQmlTypeData::loadImplicitImport()
728 assertTypeLoaderThread();
730 m_implicitImportLoaded =
true;
732 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
737 QList<QQmlError> implicitImportErrors;
739 m_importCache->addImplicitImport(typeLoader(), &localQmldir, &implicitImportErrors);
745 if (!localQmldir.isEmpty()) {
746 const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
747 const QList<QQmlDirParser::Import> moduleImports
748 = QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
750 loadDependentImports(moduleImports, QString(), QTypeRevision(),
751 QQmlImportInstance::Implicit + 1, QQmlImports::ImportNoFlag,
752 &implicitImportErrors);
755 if (!implicitImportErrors.isEmpty()) {
756 setError(implicitImportErrors);
763void QQmlTypeData::dataReceived(
const SourceCodeData &data)
765 assertTypeLoaderThread();
767 m_backupSourceCode = data;
769 if (tryLoadFromDiskCache())
775 if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
776 if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
777 setError(QQmlTypeLoader::tr(
"File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
778 else if (!m_backupSourceCode.exists())
779 setError(QQmlTypeLoader::tr(
"No such file or directory"));
781 setError(QQmlTypeLoader::tr(
"File is empty"));
785 if (!loadFromSource())
788 continueLoadFromIR();
791void QQmlTypeData::initializeFromCachedUnit(
const QQmlPrivate::CachedQmlUnit *unit)
793 assertTypeLoaderThread();
795 if (unit->qmlData->qmlUnit()->nObjects == 0) {
796 setError(QQmlTypeLoader::tr(
"Cached QML Unit has no objects"));
801 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
802 QQmlIRLoader loader(unit->qmlData, m_document.data());
804 m_document->javaScriptCompilationUnit
805 = QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
806 new QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions),
807 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
808 continueLoadFromIR();
811bool QQmlTypeData::loadFromSource()
813 assertTypeLoaderThread();
816 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
817 m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
818 QmlIR::IRBuilder compiler;
821 const QString source = m_backupSourceCode.readAll(&sourceError);
822 if (!sourceError.isEmpty()) {
823 setError(sourceError);
827 if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
828 QList<QQmlError> errors;
829 errors.reserve(compiler.errors.size());
830 for (
const QQmlJS::DiagnosticMessage &msg : std::as_const(compiler.errors)) {
833 e.setLine(qmlConvertSourceCoordinate<quint32,
int>(msg.loc.startLine));
834 e.setColumn(qmlConvertSourceCoordinate<quint32,
int>(msg.loc.startColumn));
835 e.setDescription(msg.message);
844void QQmlTypeData::restoreIR(
const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
846 assertTypeLoaderThread();
849 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
850 QQmlIRLoader loader(unit->unitData(), m_document.data());
852 m_document->javaScriptCompilationUnit = unit;
853 continueLoadFromIR();
856void QQmlTypeData::continueLoadFromIR()
858 assertTypeLoaderThread();
860 for (
auto const& object: std::as_const(m_document->objects)) {
861 for (
auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
862 QString
const nameString = m_document->stringAt(it->nameIndex);
863 auto importUrl = finalUrl();
864 importUrl.setFragment(nameString);
865 auto import =
new QQmlImportInstance();
866 m_importCache->addInlineComponentImport(import, nameString, importUrl);
870 m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
871 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
876 if (!finalUrl().scheme().isEmpty()) {
877 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String(
"qmldir")));
878 if (!QQmlImports::isLocal(qmldirUrl)) {
879 if (!loadImplicitImport())
882 auto implicitImport = std::make_shared<PendingImport>();
883 implicitImport->uri = QLatin1String(
".");
884 implicitImport->version = QTypeRevision();
885 QList<QQmlError> errors;
887 if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
894 QList<QQmlError> errors;
896 for (
const QV4::CompiledData::Import *import : std::as_const(m_document->imports)) {
897 if (!addImport(import, {}, &errors)) {
898 Q_ASSERT(errors.size());
903 QQmlError error = errors.first();
904 error.setUrl(m_importCache->baseUrl());
905 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(import->location.line()));
906 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(import->location.column()));
913void QQmlTypeData::allDependenciesDone()
915 assertTypeLoaderThread();
917 QQmlTypeLoader::Blob::allDependenciesDone();
919 if (!m_typesResolved)
923QString QQmlTypeData::stringAt(
int index)
const
926 return m_compiledData->stringAt(index);
927 return m_document->jsGenerator.stringTable.stringForIndex(index);
930void QQmlTypeData::compile(
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
931 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
932 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
934 assertTypeLoaderThread();
936 Q_ASSERT(m_compiledData.isNull());
938 const bool typeRecompilation = m_document
939 && m_document->javaScriptCompilationUnit
940 && m_document->javaScriptCompilationUnit->unitData()
941 && (m_document->javaScriptCompilationUnit->unitData()->flags
942 & QV4::CompiledData::Unit::PendingTypeCompilation);
944 QQmlTypeCompiler compiler(
945 typeLoader(),
this, m_document.data(), resolvedTypeCache, dependencyHasher);
946 auto compilationUnit = compiler.compile();
947 if (!compilationUnit) {
948 qDeleteAll(*resolvedTypeCache);
949 resolvedTypeCache->clear();
950 setError(compiler.compilationErrors());
954 const bool trySaveToDisk = m_typeLoader->writeCacheFile() && !typeRecompilation;
957 if (compilationUnit->saveToDisk(url(), &errorString)) {
959 if (!compilationUnit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
963 qCDebug(DBG_DISK_CACHE) <<
"Error saving cached version of"
964 << compilationUnit->fileName() <<
"to disk:" << errorString;
968 m_compiledData = std::move(compilationUnit);
969 m_compiledData->typeNameCache = typeNameCache;
970 m_compiledData->resolvedTypes = *resolvedTypeCache;
971 m_compiledData->propertyCaches = std::move(*compiler.propertyCaches());
972 Q_ASSERT(m_compiledData->propertyCaches.count()
973 >=
static_cast<
int>(m_compiledData->objectCount()));
976bool QQmlTypeData::resolveTypes()
978 assertTypeLoaderThread();
980 Q_ASSERT(!m_typesResolved);
983 QList<QQmlError> errors;
984 auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
985 for ( ; it != end; ++it) {
986 const PendingImportPtr &import = *it;
987 if (import->priority != 0)
992 if (registerPendingTypes(import))
997 error.setDescription(QQmlTypeLoader::tr(
"module \"%1\" is not installed").arg(import->uri));
998 error.setUrl(m_importCache->baseUrl());
999 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(
1000 import->location.line()));
1001 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(
1002 import->location.column()));
1003 errors.prepend(error);
1006 if (errors.size()) {
1012 if (!m_implicitImportLoaded && !loadImplicitImport())
1016 const auto resolvedScripts = m_importCache->resolvedScripts();
1017 for (
const QQmlImports::ScriptReference &script : resolvedScripts) {
1018 QQmlRefPointer<QQmlScriptBlob> blob
1019 = typeLoader()->getScript(script.location, script.fileName);
1020 addDependency(blob.data());
1022 ScriptReference ref;
1024 if (!script.qualifier.isEmpty())
1026 ref.qualifier = script.qualifier + QLatin1Char(
'.') + script.nameSpace;
1028 m_namespaces.insert(script.qualifier);
1030 ref.qualifier = script.nameSpace;
1038 const auto resolvedCompositeSingletons = m_importCache->resolvedCompositeSingletons();
1039 for (
const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
1042 if (!csRef.prefix.isEmpty()) {
1043 typeName = csRef.prefix + QLatin1Char(
'.') + csRef.typeName;
1045 m_namespaces.insert(csRef.prefix);
1047 typeName = csRef.typeName;
1050 QTypeRevision version = csRef.version;
1051 if (!resolveType(typeName, version, ref, -1, -1,
true, QQmlType::CompositeSingletonType))
1054 if (ref.type.isCompositeSingleton()) {
1055 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1056 if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
1057 qCDebug(lcCycle) <<
"Possible cyclic dependency detected between"
1058 << ref.typeData->urlString() <<
"and" << urlString();
1061 addDependency(ref.typeData.data());
1062 ref.prefix = csRef.prefix;
1064 m_compositeSingletons << ref;
1068 for (
auto unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
1069 unresolvedRef != end; ++unresolvedRef) {
1073 const bool reportErrors = unresolvedRef->errorWhenNotFound;
1075 QTypeRevision version;
1077 const QString name = stringAt(unresolvedRef.key());
1079 bool *selfReferenceDetection = unresolvedRef->needsCreation ?
nullptr : &ref.selfReference;
1081 if (!resolveType(name, version, ref, unresolvedRef->location.line(),
1082 unresolvedRef->location.column(), reportErrors,
1083 QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
1086 if (ref.selfReference) {
1088 }
else if (ref.type.isComposite()) {
1089 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1090 addDependency(ref.typeData.data());
1091 }
else if (ref.type.isInlineComponentType()) {
1092 QUrl containingTypeUrl = ref.type.sourceUrl();
1093 Q_ASSERT(!containingTypeUrl.isEmpty());
1094 if (QQmlMetaType::equalBaseUrls(finalUrl(), containingTypeUrl)) {
1095 ref.selfReference =
true;
1097 containingTypeUrl.setFragment(QString());
1098 auto typeData = typeLoader()->getType(containingTypeUrl);
1099 Q_ASSERT(typeData.data() !=
this);
1100 ref.typeData = typeData;
1101 addDependency(typeData.data());
1105 ref.version = version;
1106 ref.location = unresolvedRef->location;
1107 ref.needsCreation = unresolvedRef->needsCreation;
1108 m_resolvedTypes.insert(unresolvedRef.key(), ref);
1111 m_typesResolved =
true;
1115QQmlError QQmlTypeData::buildTypeResolutionCaches(
1116 QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
1117 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache)
const
1119 assertTypeLoaderThread();
1121 typeNameCache->adopt(
new QQmlTypeNameCache(m_importCache));
1123 for (
const QString &ns: m_namespaces)
1124 (*typeNameCache)->add(ns);
1127 for (
const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
1128 (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
1130 m_importCache->populateCache(typeNameCache->data());
1132 for (
auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
1133 auto ref = std::make_unique<QV4::ResolvedTypeReference>();
1134 QQmlType qmlType = resolvedType->type;
1135 ref->setType(qmlType);
1136 ref->setIsSelfReference(resolvedType->selfReference);
1137 if (resolvedType->typeData) {
1138 if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
1139 return qQmlCompileError(resolvedType->location, tr(
"Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
1141 const auto compilationUnit = resolvedType->typeData->compilationUnit();
1142 if (qmlType.isInlineComponentType()) {
1144 QString icName = qmlType.elementName();
1145 Q_ASSERT(!icName.isEmpty());
1147 ref->setTypePropertyCache(compilationUnit->propertyCaches.at(
1148 compilationUnit->inlineComponentId(icName)));
1149 Q_ASSERT(ref->type().isInlineComponentType());
1151 ref->setTypePropertyCache(compilationUnit->rootPropertyCache());
1153 if (!resolvedType->selfReference)
1154 ref->setCompilationUnit(compilationUnit);
1155 }
else if (qmlType.isInlineComponentType()) {
1160 Q_ASSERT(resolvedType->selfReference);
1161 Q_ASSERT(ref->isSelfReference());
1162 }
else if (qmlType.isValid() && !resolvedType->selfReference) {
1163 Q_ASSERT(ref->type().isValid());
1165 if (resolvedType->needsCreation && !qmlType.isCreatable()) {
1166 QString reason = qmlType.noCreationReason();
1167 if (reason.isEmpty())
1168 reason = tr(
"Element is not creatable.");
1169 return qQmlCompileError(resolvedType->location, reason);
1172 if (qmlType.containsRevisionedAttributes()) {
1174 Q_ASSERT(qmlType.metaObject());
1175 ref->setTypePropertyCache(
1176 QQmlMetaType::propertyCache(qmlType, resolvedType->version));
1179 ref->setVersion(resolvedType->version);
1180 ref->doDynamicTypeCheck();
1181 resolvedTypeCache->insert(resolvedType.key(), ref.release());
1187bool QQmlTypeData::resolveType(
const QString &typeName, QTypeRevision &version,
1188 TypeReference &ref,
int lineNumber,
int columnNumber,
1189 bool reportErrors, QQmlType::RegistrationType registrationType,
1190 bool *typeRecursionDetected)
1192 assertTypeLoaderThread();
1194 QQmlImportNamespace *typeNamespace =
nullptr;
1195 QList<QQmlError> errors;
1197 bool typeFound = m_importCache->resolveType(
1198 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors, registrationType,
1199 typeRecursionDetected);
1200 if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
1202 if (loadImplicitImport()) {
1205 typeFound = m_importCache->resolveType(
1206 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
1207 registrationType, typeRecursionDetected);
1213 if ((!typeFound || typeNamespace) && reportErrors) {
1218 if (typeNamespace) {
1219 error.setDescription(QQmlTypeLoader::tr(
"Namespace %1 cannot be used as a type").arg(typeName));
1221 if (errors.size()) {
1222 error = errors.takeFirst();
1226 error.setDescription(QQmlTypeLoader::tr(
"Unreported error adding script import to import database"));
1228 error.setUrl(m_importCache->baseUrl());
1229 error.setDescription(QQmlTypeLoader::tr(
"%1 %2").arg(typeName, error.description()));
1232 if (lineNumber != -1)
1233 error.setLine(lineNumber);
1234 if (columnNumber != -1)
1235 error.setColumn(columnNumber);
1237 errors.prepend(error);
1245void QQmlTypeData::scriptImported(
1246 const QQmlRefPointer<QQmlScriptBlob> &blob,
const QV4::CompiledData::Location &location,
1247 const QString &nameSpace,
const QString &qualifier)
1249 assertTypeLoaderThread();
1251 ScriptReference ref;
1253 ref.location = location;
1254 ref.qualifier = qualifier.isEmpty() ? nameSpace : qualifier + QLatin1Char(
'.') + nameSpace;
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")