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 const auto sourceChecksum = [
this]() {
return m_backupSourceCode.checksum(); };
76 if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), sourceChecksum,
78 qCDebug(DBG_DISK_CACHE) <<
"Error loading" << urlString() <<
"from disk cache:" << error;
83 if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
88 return loadFromDiskCache(unit);
91bool QQmlTypeData::loadFromDiskCache(
const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
93 assertTypeLoaderThread();
95 m_compiledData = unit;
97 QList<QV4::CompiledData::InlineComponent> ics;
98 for (
int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
99 auto object = m_compiledData->objectAt(i);
100 m_typeReferences.collectFromObject(object);
101 const auto inlineComponentTable = object->inlineComponentTable();
102 for (
auto i = 0; i != object->nInlineComponents; ++i) {
103 ics.push_back(inlineComponentTable[i]);
107 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
112 if (!finalUrl().scheme().isEmpty()) {
113 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String(
"qmldir")));
114 if (!QQmlImports::isLocal(qmldirUrl)) {
115 if (!loadImplicitImport())
119 for (quint32 i = 0, count = m_compiledData->importCount(); i < count; ++i) {
120 const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
121 if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(
".")
122 && import->qualifierIndex == 0
123 && !import->version.hasMajorVersion()
124 && !import->version.hasMinorVersion()) {
125 QList<QQmlError> errors;
126 auto pendingImport = std::make_shared<PendingImport>(
127 this, import, QQmlImports::ImportNoFlag);
128 pendingImport->precedence = QQmlImportInstance::Implicit;
129 if (!fetchQmldir(qmldirUrl, std::move(pendingImport), 1, &errors)) {
139 for (
int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
140 const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
141 QList<QQmlError> errors;
142 if (!addImport(import, {}, &errors)) {
143 Q_ASSERT(errors.size());
144 QQmlError error(errors.takeFirst());
145 error.setUrl(m_importCache->baseUrl());
146 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(import->location.line()));
147 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(import->location.column()));
148 errors.prepend(error);
154 for (
auto&& ic: ics) {
155 QString
const nameString = m_compiledData->stringAt(ic.nameIndex);
156 auto importUrl = finalUrl();
157 importUrl.setFragment(nameString);
158 auto import =
new QQmlImportInstance();
159 m_importCache->addInlineComponentImport(import, nameString, importUrl);
166void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::allocateNamedObjects(
167 const QV4::CompiledData::Object *object)
const
173bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::markAsComponent(
int index)
const
175 return m_compiler->objectAt(index)->hasFlag(QV4::CompiledData::Object::IsComponent);
179void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::setObjectId(
int index)
const
187void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveGeneralizedGroupedProperty(
188 const CompiledObject &component, CompiledBinding *binding)
191 for (
int i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
192 const int candidateIndex = component.namedObjectsInComponentTable()[i];
193 if (m_compiler->objectAt(candidateIndex)->idNameIndex == binding->propertyNameIndex) {
194 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(candidateIndex));
203typename QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::AliasResolutionResult
204QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliasesInObject(
205 const CompiledObject &component,
int objectIndex,
206 QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> *aliasCacheCreator,
209 const CompiledObject *obj = m_compiler->objectAt(objectIndex);
211 const auto doAppendAlias = [&](
const QV4::CompiledData::Alias *alias,
int encodedIndex,
212 int resolvedTargetObjectId,
int targetObjectIndex) {
213 return appendAliasToPropertyCache(
214 alias, objectIndex, aliasIndex++, encodedIndex,
215 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator, error);
218 const auto handleDeepAlias = [&](
219 const QV4::CompiledData::Alias *alias,
const QQmlPropertyCache::ConstPtr &propertyCache,
220 int coreIndex, QStringView subProperty,
int resolvedTargetObjectId,
int targetObjectIndex)
222 const QQmlPropertyResolver resolver = QQmlPropertyResolver(propertyCache);
223 const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
225 return DeepAliasResult::NoProperty;
228 alias, QQmlPropertyIndex(coreIndex, actualProperty->coreIndex()).toEncoded(),
229 resolvedTargetObjectId, targetObjectIndex)) {
230 return DeepAliasResult::Success;
233 return DeepAliasResult::CannotAppend;
236 for (
auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
237 if (resolvedAliases.contains(alias)) {
242 int targetObjectIndex = -1;
243 for (
int i = 0, end = component.namedObjectsInComponentCount(); i < end; ++i) {
244 const int candidateIndex = component.namedObjectsInComponentTable()[i];
245 if (m_compiler->objectAt(candidateIndex)->idNameIndex == alias->idIndex()) {
246 targetObjectIndex = candidateIndex;
250 if (targetObjectIndex == -1) {
251 *error = qQmlCompileError(
252 alias->referenceLocation(),
253 tr(
"Invalid alias reference. Unable to find id \"%1\"")
254 .arg(stringAt(alias->idIndex())));
257 const QV4::CompiledData::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
258 const int resolvedTargetObjectId = targetObject->objectId();
260 QStringView property;
261 QStringView subProperty;
263 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
264 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char(
'.'));
265 if (propertySeparator != -1) {
266 property = QStringView{aliasPropertyValue}.left(propertySeparator);
267 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
269 property = QStringView(aliasPropertyValue);
272 if (property.isEmpty()) {
273 if (doAppendAlias(alias, -1, resolvedTargetObjectId, targetObjectIndex))
275 return SomeAliasesResolved;
278 Q_ASSERT(!property.isEmpty());
279 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
280 Q_ASSERT(targetCache);
282 const QQmlPropertyResolver resolver(targetCache);
283 const QQmlPropertyData *targetProperty = resolver.property(property.toString());
285 return SomeAliasesResolved;
287 const int coreIndex = targetProperty->coreIndex();
288 if (subProperty.isEmpty()) {
290 alias, QQmlPropertyIndex(coreIndex).toEncoded(), resolvedTargetObjectId,
291 targetObjectIndex)) {
294 return SomeAliasesResolved;
297 if (
const QMetaObject *valueTypeMetaObject
298 = QQmlMetaType::metaObjectForValueType(targetProperty->propType())) {
299 const int valueTypeIndex = valueTypeMetaObject->indexOfProperty(
300 subProperty.toString().toUtf8().constData());
301 if (valueTypeIndex == -1)
302 return SomeAliasesResolved;
305 alias, QQmlPropertyIndex(coreIndex, valueTypeIndex).toEncoded(),
306 resolvedTargetObjectId, targetObjectIndex)) {
310 return SomeAliasesResolved;
313 Q_ASSERT(subProperty.at(0).isLower());
315 bool foundDeepAliasInBindings =
false;
316 for (
auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
317 if (m_compiler->stringAt(it->propertyNameIndex) != property)
320 const QQmlPropertyCache::ConstPtr bindingCache
321 = m_propertyCaches->at(it->value.objectIndex);
325 switch (handleDeepAlias(
326 alias, bindingCache, coreIndex, subProperty, resolvedTargetObjectId,
327 targetObjectIndex)) {
328 case DeepAliasResult::NoProperty:
330 case DeepAliasResult::CannotAppend:
331 return SomeAliasesResolved;
332 case DeepAliasResult::Success:
333 foundDeepAliasInBindings =
true;
340 if (foundDeepAliasInBindings)
343 const QQmlPropertyCache::ConstPtr typeCache
344 = QQmlMetaType::propertyCacheForType(targetProperty->propType());
346 return SomeAliasesResolved;
348 switch (handleDeepAlias(alias, typeCache, coreIndex, subProperty, resolvedTargetObjectId,
349 targetObjectIndex)) {
350 case DeepAliasResult::NoProperty:
351 case DeepAliasResult::CannotAppend:
352 return SomeAliasesResolved;
353 case DeepAliasResult::Success:
358 return AllAliasesResolved;
361QQmlError QQmlTypeData::createTypeAndPropertyCaches(
362 const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
363 const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
365 assertTypeLoaderThread();
367 Q_ASSERT(m_compiledData);
368 m_compiledData->typeNameCache = typeNameCache;
369 m_compiledData->resolvedTypes = resolvedTypeCache;
370 m_compiledData->inlineComponentData = m_inlineComponentData;
371 m_compiledData->qmlType = m_qmlType;
373 QQmlPendingGroupedPropertyBindings pendingGroupedPropertyBindings;
376 QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(
377 &m_compiledData->propertyCaches, &pendingGroupedPropertyBindings, m_typeLoader,
378 m_compiledData.data(), m_importCache.data(), typeClassName());
380 QQmlError error = propertyCacheCreator.verifyNoICCycle();
384 QQmlPropertyCacheCreatorBase::IncrementalResult result;
386 result = propertyCacheCreator.buildMetaObjectsIncrementally();
387 if (result.error.isValid()) {
390 QQmlComponentAndAliasResolver resolver(
391 m_compiledData.data(), &m_compiledData->propertyCaches);
392 if (
const QQmlError error = resolver.resolve(result.processedRoot);
396 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(
397 &m_compiledData->propertyCaches);
398 pendingGroupedPropertyBindings.clear();
401 }
while (result.canResume);
404 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches);
410using InlineComponentData = QV4::CompiledData::InlineComponentData;
412template<
typename ObjectContainer>
414 const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
416 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) {
417 Q_ASSERT(icData->empty());
418 for (
int i = 0; i != container->objectCount(); ++i) {
419 auto root = container->objectAt(i);
420 for (
auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
423 InlineComponentData icDatum(
424 QQmlMetaType::findOrCreateFactualInlineComponentType(
425 baseUrl, container->stringAt(it->nameIndex), compilationUnit),
426 int(it->objectIndex),
int(it->nameIndex));
428 icData->insert(container->stringAt(it->nameIndex), icDatum);
434bool QQmlTypeData::checkScripts()
437 for (
int ii = 0; ii < m_scripts.size(); ++ii) {
438 const ScriptReference &script = m_scripts.at(ii);
439 Q_ASSERT(script.script->isCompleteOrError());
440 if (script.script->isError()) {
443 QQmlTypeLoader::tr(
"Script %1 unavailable").arg(script.script->urlString()));
450void QQmlTypeData::createError(
const TypeReference &type,
const QString &message)
452 createError(type, message, type.typeData ? type.typeData->errors() : QList<QQmlError>());
455void QQmlTypeData::createError(
const ScriptReference &script,
const QString &message)
457 createError(script, message, script.script ? script.script->errors() : QList<QQmlError>());
460bool QQmlTypeData::checkDependencies()
463 for (
auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end();
465 const TypeReference &type = *it;
466 Q_ASSERT(!type.typeData
467 || type.typeData->isCompleteOrError()
468 || type.type.isInlineComponent());
470 if (type.typeData && type.typeData->isError()) {
471 const QString &typeName = stringAt(it.key());
472 createError(type, QQmlTypeLoader::tr(
"Type %1 unavailable").arg(typeName));
476 if (!type.selfReference && type.type.isInlineComponent()) {
477 const QString icName = type.type.elementName();
478 Q_ASSERT(!icName.isEmpty());
481 if (type.typeData && type.typeData->compilationUnit()->inlineComponentId(icName) >= 0)
484 const QString typeName = stringAt(it.key());
485 const qsizetype lastDot = typeName.lastIndexOf(u'.');
488 QQmlTypeLoader::tr(
"Type %1 has no inline component type called %2")
489 .arg(QStringView{typeName}.left(lastDot), icName));
497bool QQmlTypeData::checkCompositeSingletons()
500 for (
int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
501 const TypeReference &type = m_compositeSingletons.at(ii);
502 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
503 if (type.typeData && type.typeData->isError()) {
504 QString typeName = type.type.qmlTypeName();
505 createError(type, QQmlTypeLoader::tr(
"Type %1 unavailable").arg(typeName));
513void QQmlTypeData::createQQmlType()
515 if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
516 const bool isSingleton = m_document
517 ? m_document.data()->isSingleton()
518 : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
519 m_qmlType = QQmlMetaType::findCompositeType(
520 url(), m_compiledData, isSingleton
521 ? QQmlMetaType::Singleton
522 : QQmlMetaType::NonSingleton);
523 m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
527bool QQmlTypeData::rebuildFromSource()
531 m_typeReferences.clear();
533 m_namespaces.clear();
534 m_compositeSingletons.clear();
536 m_resolvedTypes.clear();
537 m_typesResolved =
false;
539 m_qmlType = QQmlType();
540 m_typeClassName.clear();
542 m_inlineComponentData.clear();
543 m_compiledData.reset();
545 m_implicitImportLoaded =
false;
547 m_importCache.adopt(
new QQmlImports);
548 m_unresolvedImports.clear();
550 if (!loadFromSource())
553 continueLoadFromIR();
561 if (!checkDependencies())
564 if (!checkCompositeSingletons())
569 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
573void QQmlTypeData::done()
575 assertTypeLoaderThread();
577 auto cleanup = qScopeGuard([
this]{
578 m_backupSourceCode = SourceCodeData();
580 m_typeReferences.clear();
582 const auto encounteredErrors = errors();
583 for (
const QQmlError &e : encounteredErrors)
584 qCDebug(DBG_DISK_CACHE) << e.toString();
585 m_compiledData.reset();
588 m_resolvedTypes.clear();
589 m_compositeSingletons.clear();
600 if (!checkDependencies())
603 if (!checkCompositeSingletons())
609 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
611 setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
613 QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
614 QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
617 const bool verifyCaches = !m_compiledData
618 || (m_compiledData->resolvedTypes.isEmpty() && !m_compiledData->typeNameCache);
621 QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
622 if (error.isValid()) {
624 qDeleteAll(resolvedTypeCache);
629 const auto dependencyHasher = [&resolvedTypeCache,
this]() {
630 return typeLoader()->hashDependencies(&resolvedTypeCache, m_compositeSingletons);
634 if (m_document.isNull() && verifyCaches) {
635 const QQmlError error = createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
636 if (error.isValid() || !m_compiledData->verifyChecksum(dependencyHasher)) {
638 if (error.isValid()) {
639 qCDebug(DBG_DISK_CACHE)
640 <<
"Failed to create property caches for"
641 << m_compiledData->fileName()
642 <<
"because" << error.description();
644 qCDebug(DBG_DISK_CACHE)
645 <<
"Checksum mismatch for cached version of"
646 << m_compiledData->fileName();
649 resolvedTypeCache.clear();
650 typeNameCache.reset();
652 if (!rebuildFromSource())
655 const QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
656 if (error.isValid()) {
658 qDeleteAll(resolvedTypeCache);
664 if (!m_document.isNull()) {
665 Q_ASSERT(verifyCaches);
667 compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
673 m_compiledData->inlineComponentData = m_inlineComponentData;
676 QQmlPropertyValidator validator(typeLoader(), m_importCache.data(), m_compiledData);
677 QList<QQmlError> errors = validator.validate();
678 if (!errors.isEmpty()) {
684 m_compiledData->finalizeCompositeType(qmlType());
688 QQmlType type = QQmlMetaType::qmlType(finalUrl());
689 if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
690 if (!type.isValid()) {
692 error.setDescription(QQmlTypeLoader::tr(
"No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
695 }
else if (!type.isCompositeSingleton()) {
697 error.setDescription(QQmlTypeLoader::tr(
"pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
704 if (type.isValid() && type.isCompositeSingleton()) {
705 QString typeName = type.qmlTypeName();
706 setError(QQmlTypeLoader::tr(
"qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
714 m_compiledData->dependentScripts.reserve(m_scripts.size());
715 for (
int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
716 const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
718 QStringView qualifier(script.qualifier);
719 QString enclosingNamespace;
721 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char(
'.'));
722 if (lastDotIndex != -1) {
723 enclosingNamespace = qualifier.left(lastDotIndex).toString();
724 qualifier = qualifier.mid(lastDotIndex+1);
727 m_compiledData->typeNameCache->add(
728 qualifier.toString(), scriptIndex, enclosingNamespace);
729 QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
730 m_compiledData->dependentScripts << scriptData;
735bool QQmlTypeData::loadImplicitImport()
737 assertTypeLoaderThread();
739 m_implicitImportLoaded =
true;
741 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
746 QList<QQmlError> implicitImportErrors;
748 m_importCache->addImplicitImport(typeLoader(), &localQmldir, &implicitImportErrors);
754 if (!localQmldir.isEmpty()) {
755 const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
756 const QList<QQmlDirParser::Import> moduleImports
757 = QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
759 loadDependentImports(moduleImports, QString(), QTypeRevision(),
760 QQmlImportInstance::Implicit + 1, QQmlImports::ImportNoFlag,
761 &implicitImportErrors);
764 if (!implicitImportErrors.isEmpty()) {
765 setError(implicitImportErrors);
772void QQmlTypeData::dataReceived(
const SourceCodeData &data)
774 assertTypeLoaderThread();
776 m_backupSourceCode = data;
778 if (tryLoadFromDiskCache())
784 if (!m_backupSourceCode.exists()) {
785 if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
786 setError(QQmlTypeLoader::tr(
"File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
788 setError(QQmlTypeLoader::tr(
"No such file or directory"));
792 if (!loadFromSource())
795 continueLoadFromIR();
798void QQmlTypeData::initializeFromCachedUnit(
const QQmlPrivate::CachedQmlUnit *unit)
800 assertTypeLoaderThread();
802 if (unit->qmlData->qmlUnit()->nObjects == 0) {
803 setError(QQmlTypeLoader::tr(
"Cached QML Unit has no objects"));
808 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
809 QQmlIRLoader loader(unit->qmlData, m_document.data());
811 m_document->javaScriptCompilationUnit
812 = QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
813 new QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions, unit->validateLookupSignatures),
814 QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
815 continueLoadFromIR();
818bool QQmlTypeData::loadFromSource()
820 assertTypeLoaderThread();
823 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
824 m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
825 QmlIR::IRBuilder compiler;
828 const QString source = m_backupSourceCode.readAll(&sourceError);
829 if (!sourceError.isEmpty()) {
830 setError(sourceError);
834 if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
835 QList<QQmlError> errors;
836 errors.reserve(compiler.errors.size());
837 for (
const QQmlJS::DiagnosticMessage &msg : std::as_const(compiler.errors)) {
840 e.setLine(qmlConvertSourceCoordinate<quint32,
int>(msg.loc.startLine));
841 e.setColumn(qmlConvertSourceCoordinate<quint32,
int>(msg.loc.startColumn));
842 e.setDescription(msg.message);
851void QQmlTypeData::restoreIR(
const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
853 assertTypeLoaderThread();
856 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
857 QQmlIRLoader loader(unit->unitData(), m_document.data());
859 m_document->javaScriptCompilationUnit = unit;
860 continueLoadFromIR();
863void QQmlTypeData::continueLoadFromIR()
865 assertTypeLoaderThread();
867 for (
auto const& object: std::as_const(m_document->objects)) {
868 for (
auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
869 QString
const nameString = m_document->stringAt(it->nameIndex);
870 auto importUrl = finalUrl();
871 importUrl.setFragment(nameString);
872 auto import =
new QQmlImportInstance();
873 m_importCache->addInlineComponentImport(import, nameString, importUrl);
877 m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
878 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
883 if (!finalUrl().scheme().isEmpty()) {
884 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String(
"qmldir")));
885 if (!QQmlImports::isLocal(qmldirUrl)) {
886 if (!loadImplicitImport())
889 auto implicitImport = std::make_shared<PendingImport>();
890 implicitImport->uri = QLatin1String(
".");
891 implicitImport->version = QTypeRevision();
892 QList<QQmlError> errors;
894 if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
901 QList<QQmlError> errors;
903 for (
const QV4::CompiledData::Import *import : std::as_const(m_document->imports)) {
904 if (!addImport(import, {}, &errors)) {
905 Q_ASSERT(errors.size());
910 QQmlError error = errors.first();
911 error.setUrl(m_importCache->baseUrl());
912 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(import->location.line()));
913 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(import->location.column()));
920void QQmlTypeData::allDependenciesDone()
922 assertTypeLoaderThread();
924 QQmlTypeLoader::Blob::allDependenciesDone();
926 if (!m_typesResolved)
930QString QQmlTypeData::stringAt(
int index)
const
933 return m_compiledData->stringAt(index);
934 return m_document->jsGenerator.stringTable.stringForIndex(index);
937void QQmlTypeData::compile(
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
938 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
939 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
941 assertTypeLoaderThread();
943 Q_ASSERT(m_compiledData.isNull());
945 const bool typeRecompilation = m_document
946 && m_document->javaScriptCompilationUnit
947 && m_document->javaScriptCompilationUnit->unitData()
948 && (m_document->javaScriptCompilationUnit->unitData()->flags
949 & QV4::CompiledData::Unit::PendingTypeCompilation);
951 QQmlTypeCompiler compiler(
952 typeLoader(),
this, m_document.data(), resolvedTypeCache, dependencyHasher);
953 auto compilationUnit = compiler.compile();
954 if (!compilationUnit) {
955 qDeleteAll(*resolvedTypeCache);
956 resolvedTypeCache->clear();
957 setError(compiler.compilationErrors());
961 const bool trySaveToDisk = m_backupSourceCode.isCacheable()
962 && m_typeLoader->writeCacheFile()
963 && !typeRecompilation;
967 QByteArray cachedChecksum;
968 const auto sourceChecksum = [&]() {
969 if (cachedChecksum.isEmpty())
970 cachedChecksum = m_backupSourceCode.checksum();
971 return cachedChecksum;
974 if (compilationUnit->saveToDisk(url(), sourceChecksum, &errorString)) {
976 if (!compilationUnit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(),
977 sourceChecksum, &error)) {
979 qCDebug(DBG_DISK_CACHE)
980 <<
"Error re-loading cached version of" << compilationUnit->fileName()
981 <<
"from disk:" << errorString;
984 qCDebug(DBG_DISK_CACHE) <<
"Error saving cached version of"
985 << compilationUnit->fileName() <<
"to disk:" << errorString;
989 m_compiledData = std::move(compilationUnit);
990 m_compiledData->typeNameCache = typeNameCache;
991 m_compiledData->resolvedTypes = *resolvedTypeCache;
992 m_compiledData->propertyCaches = std::move(*compiler.propertyCaches());
993 Q_ASSERT(m_compiledData->propertyCaches.count()
994 >=
static_cast<
int>(m_compiledData->objectCount()));
997bool QQmlTypeData::resolveTypes()
999 assertTypeLoaderThread();
1001 Q_ASSERT(!m_typesResolved);
1004 QList<QQmlError> errors;
1005 auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
1006 for ( ; it != end; ++it) {
1007 const PendingImportPtr &import = *it;
1008 if (import->priority != 0)
1013 if (registerPendingTypes(import))
1018 error.setDescription(QQmlTypeLoader::tr(
"module \"%1\" is not installed").arg(import->uri));
1019 error.setUrl(m_importCache->baseUrl());
1020 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(
1021 import->location.line()));
1022 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(
1023 import->location.column()));
1024 errors.prepend(error);
1027 if (errors.size()) {
1033 if (!m_implicitImportLoaded && !loadImplicitImport())
1037 const auto resolvedScripts = m_importCache->resolvedScripts();
1038 for (
const QQmlImports::ScriptReference &script : resolvedScripts) {
1039 QQmlRefPointer<QQmlScriptBlob> blob
1040 = typeLoader()->getScript(script.location, script.fileName);
1041 addDependency(blob.data());
1043 ScriptReference ref;
1045 if (!script.qualifier.isEmpty())
1047 ref.qualifier = script.qualifier + QLatin1Char(
'.') + script.nameSpace;
1049 m_namespaces.insert(script.qualifier);
1051 ref.qualifier = script.nameSpace;
1059 const auto resolvedCompositeSingletons = m_importCache->resolvedCompositeSingletons();
1060 for (
const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
1063 if (!csRef.prefix.isEmpty()) {
1064 typeName = csRef.prefix + QLatin1Char(
'.') + csRef.typeName;
1066 m_namespaces.insert(csRef.prefix);
1068 typeName = csRef.typeName;
1071 QTypeRevision version = csRef.version;
1072 if (!resolveType(typeName, version, ref, -1, -1,
true, QQmlType::CompositeSingletonType))
1075 if (ref.type.isCompositeSingleton()) {
1076 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1077 if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
1078 qCDebug(lcCycle) <<
"Possible cyclic dependency detected between"
1079 << ref.typeData->urlString() <<
"and" << urlString();
1082 addDependency(ref.typeData.data());
1083 ref.prefix = csRef.prefix;
1085 m_compositeSingletons << ref;
1089 for (
auto unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
1090 unresolvedRef != end; ++unresolvedRef) {
1094 const bool reportErrors = unresolvedRef->errorWhenNotFound;
1096 QTypeRevision version;
1098 const QString name = stringAt(unresolvedRef.key());
1100 bool *selfReferenceDetection = unresolvedRef->needsCreation ?
nullptr : &ref.selfReference;
1102 if (!resolveType(name, version, ref, unresolvedRef->location.line(),
1103 unresolvedRef->location.column(), reportErrors,
1104 QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
1107 if (ref.selfReference) {
1109 }
else if (ref.type.isInlineComponent()) {
1110 QUrl containingTypeUrl = ref.type.sourceUrl();
1111 Q_ASSERT(!containingTypeUrl.isEmpty());
1112 if (QQmlMetaType::equalBaseUrls(finalUrl(), containingTypeUrl)) {
1113 ref.selfReference =
true;
1115 containingTypeUrl.setFragment(QString());
1116 auto typeData = typeLoader()->getType(containingTypeUrl);
1117 Q_ASSERT(typeData.data() !=
this);
1118 ref.typeData = typeData;
1119 addDependency(typeData.data());
1121 }
else if (ref.type.isComposite()) {
1122 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1123 addDependency(ref.typeData.data());
1126 ref.version = version;
1127 ref.location = unresolvedRef->location;
1128 ref.needsCreation = unresolvedRef->needsCreation;
1129 m_resolvedTypes.insert(unresolvedRef.key(), ref);
1132 m_typesResolved =
true;
1136QQmlError QQmlTypeData::buildTypeResolutionCaches(
1137 QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
1138 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache)
const
1140 assertTypeLoaderThread();
1142 typeNameCache->adopt(
new QQmlTypeNameCache(m_importCache));
1144 for (
const QString &ns: m_namespaces)
1145 (*typeNameCache)->add(ns);
1148 for (
const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
1149 (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
1151 m_importCache->populateCache(typeNameCache->data());
1153 for (
auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
1154 auto ref = std::make_unique<QV4::ResolvedTypeReference>();
1155 QQmlType qmlType = resolvedType->type;
1156 ref->setType(qmlType);
1157 ref->setIsSelfReference(resolvedType->selfReference);
1158 if (resolvedType->typeData) {
1159 if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
1160 return qQmlCompileError(resolvedType->location, tr(
"Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
1162 const auto compilationUnit = resolvedType->typeData->compilationUnit();
1163 if (qmlType.isInlineComponent()) {
1165 QString icName = qmlType.elementName();
1166 Q_ASSERT(!icName.isEmpty());
1168 ref->setTypePropertyCache(compilationUnit->propertyCaches.at(
1169 compilationUnit->inlineComponentId(icName)));
1170 Q_ASSERT(ref->type().isInlineComponent());
1172 ref->setTypePropertyCache(compilationUnit->rootPropertyCache());
1174 if (!resolvedType->selfReference)
1175 ref->setCompilationUnit(compilationUnit);
1176 }
else if (qmlType.isInlineComponent()) {
1181 Q_ASSERT(resolvedType->selfReference);
1182 Q_ASSERT(ref->isSelfReference());
1183 }
else if (qmlType.isValid() && !resolvedType->selfReference) {
1184 Q_ASSERT(ref->type().isValid());
1186 if (resolvedType->needsCreation && !qmlType.isCreatable()) {
1187 QString reason = qmlType.noCreationReason();
1188 if (reason.isEmpty())
1189 reason = tr(
"Element is not creatable.");
1190 return qQmlCompileError(resolvedType->location, reason);
1193 if (qmlType.containsRevisionedAttributes()) {
1195 Q_ASSERT(qmlType.metaObject());
1196 ref->setTypePropertyCache(
1197 QQmlMetaType::propertyCache(qmlType, resolvedType->version));
1200 ref->setVersion(resolvedType->version);
1201 ref->doDynamicTypeCheck();
1202 resolvedTypeCache->insert(resolvedType.key(), ref.release());
1208bool QQmlTypeData::resolveType(
const QString &typeName, QTypeRevision &version,
1209 TypeReference &ref,
int lineNumber,
int columnNumber,
1210 bool reportErrors, QQmlType::RegistrationType registrationType,
1211 bool *typeRecursionDetected)
1213 assertTypeLoaderThread();
1215 QQmlImportNamespace *typeNamespace =
nullptr;
1216 QList<QQmlError> errors;
1218 bool typeFound = m_importCache->resolveType(
1219 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors, registrationType,
1220 typeRecursionDetected);
1221 if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
1223 if (loadImplicitImport()) {
1226 typeFound = m_importCache->resolveType(
1227 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
1228 registrationType, typeRecursionDetected);
1234 if ((!typeFound || typeNamespace) && reportErrors) {
1239 if (typeNamespace) {
1240 error.setDescription(QQmlTypeLoader::tr(
"Namespace %1 cannot be used as a type").arg(typeName));
1242 if (errors.size()) {
1243 error = errors.takeFirst();
1247 error.setDescription(QQmlTypeLoader::tr(
"Unreported error adding script import to import database"));
1249 error.setUrl(m_importCache->baseUrl());
1250 error.setDescription(QQmlTypeLoader::tr(
"%1 %2").arg(typeName, error.description()));
1253 if (lineNumber != -1)
1254 error.setLine(lineNumber);
1255 if (columnNumber != -1)
1256 error.setColumn(columnNumber);
1258 errors.prepend(error);
1266void QQmlTypeData::scriptImported(
1267 const QQmlRefPointer<QQmlScriptBlob> &blob,
const QV4::CompiledData::Location &location,
1268 const QString &nameSpace,
const QString &qualifier)
1270 assertTypeLoaderThread();
1272 ScriptReference ref;
1274 ref.location = location;
1275 ref.qualifier = qualifier.isEmpty() ? nameSpace : qualifier + QLatin1Char(
'.') + nameSpace;
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")