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
qqmltypedata.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#include <private/qqmlcomponentandaliasresolver_p.h>
6#include <private/qqmlengine_p.h>
7#include <private/qqmlirbuilder_p.h>
8#include <private/qqmlpropertycachecreator_p.h>
9#include <private/qqmlpropertyvalidator_p.h>
10#include <private/qqmlscriptblob_p.h>
11#include <private/qqmlscriptdata_p.h>
12#include <private/qqmltypecompiler_p.h>
13#include <private/qqmltypedata_p.h>
14#include <private/qqmltypeloaderqmldircontent_p.h>
15
16#include <QtCore/qloggingcategory.h>
17#include <QtCore/qcryptographichash.h>
18
19#include <memory>
20
22
23Q_LOGGING_CATEGORY(lcCycle, "qt.qml.typeresolution.cycle", QtWarningMsg)
24
25QString QQmlTypeData::TypeReference::qualifiedName() const
26{
27 QString result;
28 if (!prefix.isEmpty()) {
29 result = prefix + QLatin1Char('.');
30 }
31 result.append(type.qmlTypeName());
32 return result;
33}
34
35QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager)
36 : QQmlNotifyingBlob(url, QmlFile, manager),
37 m_typesResolved(false), m_implicitImportLoaded(false)
38{
39
40}
41
42QQmlTypeData::~QQmlTypeData()
43{
44 m_scripts.clear();
45 m_compositeSingletons.clear();
46 m_resolvedTypes.clear();
47}
48
49QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
50{
51 return m_compiledData.data();
52}
53
54QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
55{
56 if (inlineComponentName.isEmpty())
57 return m_qmlType;
58 return m_inlineComponentData[inlineComponentName].qmlType;
59}
60
61bool QQmlTypeData::tryLoadFromDiskCache()
62{
63 assertTypeLoaderThread();
64
65 if (!m_backupSourceCode.isCacheable())
66 return false;
67
68 if (!m_typeLoader->readCacheFile())
69 return false;
70
71 auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
72 {
73 QString error;
74 const auto sourceChecksum = [this]() { return m_backupSourceCode.checksum(); };
75 if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), sourceChecksum,
76 &error)) {
77 qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error;
78 return false;
79 }
80 }
81
82 // qmlcachegen stores the build time URLs in the unit.
83 if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation)
84 unit->setUnitData(unit->unitData(), nullptr, urlString(), finalUrlString());
85
86 return loadFromDiskCache(unit);
87}
88
89bool QQmlTypeData::loadFromDiskCache(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
90{
91 assertTypeLoaderThread();
92
93 m_compiledData = unit;
94
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]);
102 }
103 }
104
105 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
106
107 // For remote URLs, we don't delay the loading of the implicit import
108 // because the loading probably requires an asynchronous fetch of the
109 // qmldir (so we can't load it just in time).
110 if (!finalUrl().scheme().isEmpty()) {
111 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
112 if (!QQmlImports::isLocal(qmldirUrl)) {
113 if (!loadImplicitImport())
114 return false;
115
116 // find the implicit import
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)) {
128 setError(errors);
129 return false;
130 }
131 break;
132 }
133 }
134 }
135 }
136
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); // put it back on the list after filling out information.
147 setError(errors);
148 return false;
149 }
150 }
151
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);
158 }
159
160 return true;
161}
162
163template<>
164void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::allocateNamedObjects(
165 int componentRoot) const
166{
167 quint32_le *namedObjects
168 = m_compiler->allocateNamedObjectsInComponent(componentRoot, m_idToObjectIndex.size());
169 for (const int objectIndex : m_idToObjectIndex)
170 *namedObjects++ = objectIndex;
171}
172
173template<>
174bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::markAsComponent(int index) const
175{
176 m_compiler->runtimeDataForWrite()->objectAt(index)->flags
177 |= QV4::CompiledData::RuntimeObject::IsComponent;
178 return true;
179}
180
181template<>
182bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::isComponentBoundary(
183 int index) const
184{
185 return m_compiler->objectIsComponent(index);
186}
187
188template<>
189void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::setObjectId(int index) const
190{
191 m_compiler->runtimeDataForWrite()->objectAt(index)->objectId = m_idToObjectIndex.size();
192}
193
194template<>
195void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveGeneralizedGroupedProperty(
196 CompiledBinding *binding)
197{
198 // We cannot make it fail here. It might be a custom-parsed property
199 const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
200 if (targetObjectIndex != -1)
201 m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
202}
203
205
206template<>
207typename QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::AliasResolutionResult
208QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliasesInObject(
209 int objectIndex,
210 QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> *aliasCacheCreator,
211 QQmlError *error)
212{
213 const CompiledObject *obj = m_compiler->objectAt(objectIndex);
214 int aliasIndex = 0;
215 const auto doAppendAlias = [&](const QV4::CompiledData::Alias *alias, int encodedIndex,
216 int resolvedTargetObjectId, int targetObjectIndex) {
217 return appendAliasToPropertyCache(
218 alias, objectIndex, aliasIndex++, encodedIndex,
219 resolvedTargetObjectId, targetObjectIndex, aliasCacheCreator, error);
220 };
221
222 const auto handleDeepAlias = [&](
223 const QV4::CompiledData::Alias *alias, const QQmlPropertyCache::ConstPtr &propertyCache,
224 int coreIndex, QStringView subProperty, int resolvedTargetObjectId, int targetObjectIndex)
225 {
226 const QQmlPropertyResolver resolver = QQmlPropertyResolver(propertyCache);
227 const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
228 if (!actualProperty)
229 return DeepAliasResult::NoProperty;
230
231 if (doAppendAlias(
232 alias, QQmlPropertyIndex(coreIndex, actualProperty->coreIndex()).toEncoded(),
233 resolvedTargetObjectId, targetObjectIndex)) {
234 return DeepAliasResult::Success;
235 }
236
237 return DeepAliasResult::CannotAppend;
238 };
239
240 for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
241 if (resolvedAliases.contains(alias)) {
242 ++aliasIndex;
243 continue;
244 }
245
246 const int targetObjectIndex = m_idToObjectIndex.value(alias->idIndex(), -1);
247 if (targetObjectIndex == -1) {
248 *error = qQmlCompileError(
249 alias->referenceLocation(),
250 tr("Invalid alias reference. Unable to find id \"%1\"")
251 .arg(stringAt(alias->idIndex())));
252 break;
253 }
254 const QV4::CompiledData::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
255 const int resolvedTargetObjectId = m_compiler->objectId(targetObjectIndex);
256
257 QStringView property;
258 QStringView subProperty;
259
260 const QString aliasPropertyValue = stringAt(alias->propertyNameIndex());
261 const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
262 if (propertySeparator != -1) {
263 property = QStringView{aliasPropertyValue}.left(propertySeparator);
264 subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
265 } else {
266 property = QStringView(aliasPropertyValue);
267 }
268
269 if (property.isEmpty()) {
270 if (doAppendAlias(alias, -1, resolvedTargetObjectId, targetObjectIndex))
271 continue;
272 return SomeAliasesResolved;
273 }
274
275 Q_ASSERT(!property.isEmpty());
276 QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
277 Q_ASSERT(targetCache);
278
279 const QQmlPropertyResolver resolver(targetCache);
280 const QQmlPropertyData *targetProperty = resolver.property(property.toString());
281 if (!targetProperty)
282 return SomeAliasesResolved;
283
284 const int coreIndex = targetProperty->coreIndex();
285 if (subProperty.isEmpty()) {
286 if (doAppendAlias(
287 alias, QQmlPropertyIndex(coreIndex).toEncoded(), resolvedTargetObjectId,
288 targetObjectIndex)) {
289 continue;
290 }
291 return SomeAliasesResolved;
292 }
293
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;
300
301 if (doAppendAlias(
302 alias, QQmlPropertyIndex(coreIndex, valueTypeIndex).toEncoded(),
303 resolvedTargetObjectId, targetObjectIndex)) {
304 continue;
305 }
306
307 return SomeAliasesResolved;
308 }
309
310 Q_ASSERT(subProperty.at(0).isLower());
311
312 bool foundDeepAliasInBindings = false;
313 for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
314 if (m_compiler->stringAt(it->propertyNameIndex) != property)
315 continue;
316
317 const QQmlPropertyCache::ConstPtr bindingCache
318 = m_propertyCaches->at(it->value.objectIndex);
319 if (!bindingCache)
320 continue;
321
322 switch (handleDeepAlias(
323 alias, bindingCache, coreIndex, subProperty, resolvedTargetObjectId,
324 targetObjectIndex)) {
325 case DeepAliasResult::NoProperty:
326 continue;
327 case DeepAliasResult::CannotAppend:
328 return SomeAliasesResolved;
329 case DeepAliasResult::Success:
330 foundDeepAliasInBindings = true;
331 break;
332 }
333
334 break;
335 }
336
337 if (foundDeepAliasInBindings)
338 continue;
339
340 const QQmlPropertyCache::ConstPtr typeCache
341 = QQmlMetaType::propertyCacheForType(targetProperty->propType());
342 if (!typeCache)
343 return SomeAliasesResolved;
344
345 switch (handleDeepAlias(alias, typeCache, coreIndex, subProperty, resolvedTargetObjectId,
346 targetObjectIndex)) {
347 case DeepAliasResult::NoProperty:
348 case DeepAliasResult::CannotAppend:
349 return SomeAliasesResolved;
350 case DeepAliasResult::Success:
351 break;
352 }
353 }
354
355 return AllAliasesResolved;
356}
357
358QQmlError QQmlTypeData::createTypeAndPropertyCaches(
359 const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
360 const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
361{
362 assertTypeLoaderThread();
363
364 Q_ASSERT(m_compiledData);
365 m_compiledData->typeNameCache = typeNameCache;
366 m_compiledData->resolvedTypes = resolvedTypeCache;
367 m_compiledData->inlineComponentData = m_inlineComponentData;
368 m_compiledData->qmlType = m_qmlType;
369
370 m_compiledData->allocateRuntimeData();
371
372 QQmlPendingGroupedPropertyBindings pendingGroupedPropertyBindings;
373
374 {
375 QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(
376 &m_compiledData->propertyCaches, &pendingGroupedPropertyBindings, m_typeLoader,
377 m_compiledData.data(), m_importCache.data(), typeClassName());
378
379 QQmlError error = propertyCacheCreator.verifyNoICCycle();
380 if (error.isValid())
381 return error;
382
383 QQmlPropertyCacheCreatorBase::IncrementalResult result;
384 do {
385 result = propertyCacheCreator.buildMetaObjectsIncrementally();
386 if (result.error.isValid()) {
387 return result.error;
388 } else {
389 QQmlComponentAndAliasResolver resolver(
390 m_compiledData.data(), &m_compiledData->propertyCaches);
391 if (const QQmlError error = resolver.resolve(result.processedRoot);
392 error.isValid()) {
393 return error;
394 }
395 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(
396 &m_compiledData->propertyCaches);
397 pendingGroupedPropertyBindings.clear(); // anything that can be processed is now processed
398 }
399
400 } while (result.canResume);
401 }
402
403 pendingGroupedPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches);
404 return QQmlError();
405}
406
407// local helper function for inline components
408namespace {
409using InlineComponentData = QV4::CompiledData::InlineComponentData;
410
411template<typename ObjectContainer>
412void setupICs(
413 const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
414 const QUrl &baseUrl,
415 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) {
416 Q_ASSERT(icData->empty());
417 for (int i = 0; i != container->objectCount(); ++i) {
418 auto root = container->objectAt(i);
419 for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
420 // We cannot re-use a previously finalized inline component type here. We need our own.
421 // We can and should re-use speculative type references, though.
422 InlineComponentData icDatum(
423 QQmlMetaType::findOrCreateFactualInlineComponentType(
424 baseUrl, container->stringAt(it->nameIndex), compilationUnit),
425 int(it->objectIndex), int(it->nameIndex));
426
427 icData->insert(container->stringAt(it->nameIndex), icDatum);
428 }
429 }
430};
431}
432
433bool QQmlTypeData::checkScripts()
434{
435 // Check all script dependencies for errors
436 for (int ii = 0; ii < m_scripts.size(); ++ii) {
437 const ScriptReference &script = m_scripts.at(ii);
438 Q_ASSERT(script.script->isCompleteOrError());
439 if (script.script->isError()) {
440 createError(
441 script,
442 QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
443 return false;
444 }
445 }
446 return true;
447}
448
449void QQmlTypeData::createError(const TypeReference &type, const QString &message)
450{
451 createError(type, message, type.typeData ? type.typeData->errors() : QList<QQmlError>());
452}
453
454void QQmlTypeData::createError(const ScriptReference &script, const QString &message)
455{
456 createError(script, message, script.script ? script.script->errors() : QList<QQmlError>());
457}
458
459bool QQmlTypeData::checkDependencies()
460{
461 // Check all type dependencies for errors
462 for (auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end();
463 it != end; ++it) {
464 const TypeReference &type = *it;
465 Q_ASSERT(!type.typeData
466 || type.typeData->isCompleteOrError()
467 || type.type.isInlineComponent());
468
469 if (type.typeData && type.typeData->isError()) {
470 const QString &typeName = stringAt(it.key());
471 createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
472 return false;
473 }
474
475 if (!type.selfReference && type.type.isInlineComponent()) {
476 const QString icName = type.type.elementName();
477 Q_ASSERT(!icName.isEmpty());
478
479 // We have a CU here. Check if the inline component exists.
480 if (type.typeData && type.typeData->compilationUnit()->inlineComponentId(icName) >= 0)
481 return true;
482
483 const QString typeName = stringAt(it.key());
484 const qsizetype lastDot = typeName.lastIndexOf(u'.');
485 createError(
486 type,
487 QQmlTypeLoader::tr("Type %1 has no inline component type called %2")
488 .arg(QStringView{typeName}.left(lastDot), icName));
489 return false;
490 }
491 }
492
493 return true;
494}
495
496bool QQmlTypeData::checkCompositeSingletons()
497{
498 // Check all composite singleton type dependencies for errors
499 for (int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
500 const TypeReference &type = m_compositeSingletons.at(ii);
501 Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
502 if (type.typeData && type.typeData->isError()) {
503 QString typeName = type.type.qmlTypeName();
504 createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
505 return false;
506 }
507 }
508
509 return true;
510}
511
512void QQmlTypeData::createQQmlType()
513{
514 if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
515 const bool isSingleton = m_document
516 ? m_document.data()->isSingleton()
517 : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
518 m_qmlType = QQmlMetaType::findCompositeType(
519 url(), m_compiledData, isSingleton
520 ? QQmlMetaType::Singleton
521 : QQmlMetaType::NonSingleton);
522 m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
523 }
524}
525
526bool QQmlTypeData::rebuildFromSource()
527{
528 // Clear and re-build everything.
529
530 m_typeReferences.clear();
531 m_scripts.clear();
532 m_namespaces.clear();
533 m_compositeSingletons.clear();
534
535 m_resolvedTypes.clear();
536 m_typesResolved = false;
537
538 m_qmlType = QQmlType();
539 m_typeClassName.clear();
540
541 m_inlineComponentData.clear();
542 m_compiledData.reset();
543
544 m_implicitImportLoaded = false;
545
546 m_importCache.adopt(new QQmlImports);
547 m_unresolvedImports.clear();
548
549 if (!loadFromSource())
550 return false;
551
552 continueLoadFromIR();
553
554 if (!resolveTypes())
555 return false;
556
557 if (!checkScripts())
558 return false;
559
560 if (!checkDependencies())
561 return false;
562
563 if (!checkCompositeSingletons())
564 return false;
565
566 createQQmlType();
567
568 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
569 return true;
570}
571
572void QQmlTypeData::done()
573{
574 assertTypeLoaderThread();
575
576 auto cleanup = qScopeGuard([this]{
577 m_backupSourceCode = SourceCodeData();
578 m_document.reset();
579 m_typeReferences.clear();
580 if (isError()) {
581 const auto encounteredErrors = errors();
582 for (const QQmlError &e : encounteredErrors)
583 qCDebug(DBG_DISK_CACHE) << e.toString();
584 m_compiledData.reset();
585 // Clear resolved types, scripts, and composite singletons to break
586 // potential circular references (e.g., A depends on B, B depends on A)
587 m_resolvedTypes.clear();
588 m_compositeSingletons.clear();
589 m_scripts.clear();
590 }
591 });
592
593 if (isError())
594 return;
595
596 if (!checkScripts())
597 return;
598
599 if (!checkDependencies())
600 return;
601
602 if (!checkCompositeSingletons())
603 return;
604
605 createQQmlType();
606
607 if (m_document)
608 setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
609 else
610 setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
611
612 QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
613 QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
614
615 // If we've pulled the CU from the memory cache, we don't need to do any verification.
616 const bool verifyCaches = !m_compiledData
617 || (m_compiledData->resolvedTypes.isEmpty() && !m_compiledData->typeNameCache);
618
619 if (verifyCaches) {
620 QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
621 if (error.isValid()) {
622 setError(error);
623 qDeleteAll(resolvedTypeCache);
624 return;
625 }
626 }
627
628 const auto dependencyHasher = [&resolvedTypeCache, this]() {
629 return typeLoader()->hashDependencies(&resolvedTypeCache, m_compositeSingletons);
630 };
631
632 // verify if any dependencies changed if we're using a cache
633 if (m_document.isNull() && verifyCaches) {
634 // qmlcachegen doesn't know the dependencies. It doesn't store anything that depends on them.
635 const bool hasDependencyChecksum = !(m_compiledData->unitData()->flags
636 & QV4::CompiledData::Unit::PendingTypeCompilation);
637 const QQmlError error = createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
638 if (error.isValid()
639 || (hasDependencyChecksum && !m_compiledData->verifyChecksum(dependencyHasher))) {
640
641 if (error.isValid()) {
642 qCDebug(DBG_DISK_CACHE)
643 << "Failed to create property caches for"
644 << m_compiledData->fileName()
645 << "because" << error.description();
646 } else {
647 qCDebug(DBG_DISK_CACHE)
648 << "Checksum mismatch for cached version of"
649 << m_compiledData->fileName();
650 }
651
652 resolvedTypeCache.clear();
653 typeNameCache.reset();
654
655 if (!rebuildFromSource())
656 return;
657
658 const QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
659 if (error.isValid()) {
660 setError(error);
661 qDeleteAll(resolvedTypeCache);
662 return;
663 }
664 }
665 }
666
667 if (!m_document.isNull()) {
668 Q_ASSERT(verifyCaches);
669 // Compile component
670 compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
671 if (isError())
672 return;
673 }
674
675 {
676 m_compiledData->inlineComponentData = m_inlineComponentData;
677
678 if (QList<QQmlError> errors = QQmlTypeCompiler::computeRuntimeData(
679 m_compiledData.data(), typeLoader(), m_importCache.data());
680 !errors.isEmpty()) {
681 setError(errors);
682 return;
683 }
684
685 {
686 // Sanity check property bindings
687 QQmlPropertyValidator validator(typeLoader(), m_importCache.data(), m_compiledData);
688 QList<QQmlError> errors = validator.validate();
689 if (!errors.isEmpty()) {
690 setError(errors);
691 return;
692 }
693 }
694
695 m_compiledData->finalizeCompositeType(qmlType());
696 }
697
698 {
699 QQmlType type = QQmlMetaType::qmlType(finalUrl());
700 if (m_compiledData && m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton) {
701 if (!type.isValid()) {
702 QQmlError error;
703 error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent."));
704 setError(error);
705 return;
706 } else if (!type.isCompositeSingleton()) {
707 QQmlError error;
708 error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type.qmlTypeName()));
709 setError(error);
710 return;
711 }
712 } else {
713 // If the type is CompositeSingleton but there was no pragma Singleton in the
714 // QML file, lets report an error.
715 if (type.isValid() && type.isCompositeSingleton()) {
716 QString typeName = type.qmlTypeName();
717 setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName));
718 return;
719 }
720 }
721 }
722
723 {
724 // Collect imported scripts
725 m_compiledData->dependentScripts.reserve(m_scripts.size());
726 for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
727 const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
728
729 QStringView qualifier(script.qualifier);
730 QString enclosingNamespace;
731
732 const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
733 if (lastDotIndex != -1) {
734 enclosingNamespace = qualifier.left(lastDotIndex).toString();
735 qualifier = qualifier.mid(lastDotIndex+1);
736 }
737
738 m_compiledData->typeNameCache->add(
739 qualifier.toString(), scriptIndex, enclosingNamespace);
740 QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
741 m_compiledData->dependentScripts << scriptData;
742 }
743 }
744}
745
746bool QQmlTypeData::loadImplicitImport()
747{
748 assertTypeLoaderThread();
749
750 m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
751
752 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
753
754 // For local urls, add an implicit import "." as most overridden lookup.
755 // This will also trigger the loading of the qmldir and the import of any native
756 // types from available plugins.
757 QList<QQmlError> implicitImportErrors;
758 QString localQmldir;
759 m_importCache->addImplicitImport(typeLoader(), &localQmldir, &implicitImportErrors);
760 bool hasError = !implicitImportErrors.isEmpty();
761
762 // When loading with QQmlImports::ImportImplicit, the imports are _appended_ to the namespace
763 // in the order they are loaded. Therefore, the addImplicitImport above gets the highest
764 // precedence. This is in contrast to normal priority imports. Those are _prepended_ in the
765 // order they are loaded.
766 if (!localQmldir.isEmpty()) {
767 const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
768 const QList<QQmlDirParser::Import> moduleImports
769 = QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
770 + qmldir.imports();
771 if (!loadDependentImports(moduleImports, QString(), QTypeRevision(), QTypeRevision(),
772 QQmlImportInstance::Implicit + 1, QQmlImports::ImportNoFlag,
773 &implicitImportErrors)) {
774 hasError = true;
775 }
776 }
777
778 if (hasError) {
779 setError(implicitImportErrors);
780 return false;
781 }
782
783 return true;
784}
785
786void QQmlTypeData::dataReceived(const SourceCodeData &data)
787{
788 assertTypeLoaderThread();
789
790 m_backupSourceCode = data;
791
792 if (tryLoadFromDiskCache())
793 return;
794
795 if (isError())
796 return;
797
798 if (!m_backupSourceCode.exists()) {
799 if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
800 setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
801 else
802 setError(QQmlTypeLoader::tr("No such file or directory"));
803 return;
804 }
805
806 if (!loadFromSource())
807 return;
808
809 continueLoadFromIR();
810}
811
812void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
813{
814 assertTypeLoaderThread();
815
816 if (unit->qmlData->qmlUnit()->nObjects == 0) {
817 setError(QQmlTypeLoader::tr("Cached QML Unit has no objects"));
818 return;
819 }
820
821 auto compilationUnit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
822 unit->qmlData, unit->aotCompiledFunctions, unit->validateLookupSignatures,
823 urlString(), finalUrlString());
824 loadFromDiskCache(compilationUnit);
825}
826
827bool QQmlTypeData::loadFromSource()
828{
829 assertTypeLoaderThread();
830
831 m_document.reset(
832 new QmlIR::Document(urlString(), finalUrlString(), m_typeLoader->isDebugging()));
833 m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp();
834 QmlIR::IRBuilder compiler;
835
836 QString sourceError;
837 const QString source = m_backupSourceCode.readAll(&sourceError);
838 if (!sourceError.isEmpty()) {
839 setError(sourceError);
840 return false;
841 }
842
843 if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
844 QList<QQmlError> errors;
845 errors.reserve(compiler.errors.size());
846 for (const QQmlJS::DiagnosticMessage &msg : std::as_const(compiler.errors)) {
847 QQmlError e;
848 e.setUrl(url());
849 e.setLine(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startLine));
850 e.setColumn(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startColumn));
851 e.setDescription(msg.message);
852 errors << e;
853 }
854 setError(errors);
855 return false;
856 }
857 return true;
858}
859
860void QQmlTypeData::continueLoadFromIR()
861{
862 assertTypeLoaderThread();
863
864 for (auto const& object: std::as_const(m_document->objects)) {
865 for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
866 QString const nameString = m_document->stringAt(it->nameIndex);
867 auto importUrl = finalUrl();
868 importUrl.setFragment(nameString);
869 auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
870 m_importCache->addInlineComponentImport(import, nameString, importUrl);
871 }
872 }
873
874 m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
875 m_importCache->setBaseUrl(finalUrl(), finalUrlString());
876
877 // For remote URLs, we don't delay the loading of the implicit import
878 // because the loading probably requires an asynchronous fetch of the
879 // qmldir (so we can't load it just in time).
880 if (!finalUrl().scheme().isEmpty()) {
881 QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir")));
882 if (!QQmlImports::isLocal(qmldirUrl)) {
883 if (!loadImplicitImport())
884 return;
885 // This qmldir is for the implicit import
886 auto implicitImport = std::make_shared<PendingImport>();
887 implicitImport->uri = QLatin1String(".");
888 implicitImport->version = QTypeRevision();
889 QList<QQmlError> errors;
890
891 if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
892 setError(errors);
893 return;
894 }
895 }
896 }
897
898 QList<QQmlError> errors;
899
900 for (const QV4::CompiledData::Import *import : std::as_const(m_document->imports)) {
901 if (!addImport(import, {}, &errors)) {
902 Q_ASSERT(errors.size());
903
904 // We're only interested in the chronoligically last error. The previous
905 // errors might be from unsuccessfully trying to load a module from the
906 // resource file system.
907 QQmlError error = errors.first();
908 error.setUrl(m_importCache->baseUrl());
909 error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
910 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
911 setError(error);
912 return;
913 }
914 }
915}
916
917void QQmlTypeData::allDependenciesDone()
918{
919 assertTypeLoaderThread();
920
921 QQmlTypeLoader::Blob::allDependenciesDone();
922
923 if (!m_typesResolved)
924 resolveTypes();
925}
926
927QString QQmlTypeData::stringAt(int index) const
928{
929 if (m_compiledData)
930 return m_compiledData->stringAt(index);
931 return m_document->jsGenerator.stringTable.stringForIndex(index);
932}
933
934void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
935 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
936 const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
937{
938 assertTypeLoaderThread();
939
940 Q_ASSERT(m_compiledData.isNull());
941
942 QQmlTypeCompiler compiler(
943 typeLoader(), this, m_document.data(), resolvedTypeCache, dependencyHasher);
944 auto compilationUnit = compiler.compile();
945 if (!compilationUnit) {
946 qDeleteAll(*resolvedTypeCache);
947 resolvedTypeCache->clear();
948 setError(compiler.compilationErrors());
949 return;
950 }
951
952 if (m_backupSourceCode.isCacheable() && m_typeLoader->writeCacheFile()) {
953 QString errorString;
954
955 QByteArray cachedChecksum;
956 const auto sourceChecksum = [&]() {
957 if (cachedChecksum.isEmpty())
958 cachedChecksum = m_backupSourceCode.checksum();
959 return cachedChecksum;
960 };
961
962 if (compilationUnit->saveToDisk(url(), sourceChecksum, &errorString)) {
963 QString error;
964 if (!compilationUnit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(),
965 sourceChecksum, &error)) {
966 // log but ignore error, keep using the in-memory compilation unit.
967 qCDebug(DBG_DISK_CACHE)
968 << "Error re-loading cached version of" << compilationUnit->fileName()
969 << "from disk:" << errorString;
970 }
971 } else {
972 qCDebug(DBG_DISK_CACHE) << "Error saving cached version of"
973 << compilationUnit->fileName() << "to disk:" << errorString;
974 }
975 }
976
977 m_compiledData = std::move(compilationUnit);
978 m_compiledData->typeNameCache = typeNameCache;
979 m_compiledData->resolvedTypes = *resolvedTypeCache;
980 m_compiledData->propertyCaches = std::move(*compiler.propertyCaches());
981 Q_ASSERT(m_compiledData->propertyCaches.count()
982 >= static_cast<int>(m_compiledData->objectCount()));
983}
984
985bool QQmlTypeData::resolveTypes()
986{
987 assertTypeLoaderThread();
988
989 Q_ASSERT(!m_typesResolved);
990
991 // Check that all imports were resolved
992 QList<QQmlError> errors;
993 auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
994 for ( ; it != end; ++it) {
995 const PendingImportPtr &import = *it;
996 if (import->priority != 0)
997 continue;
998
999 // If the import was potentially remote and all the network requests have failed,
1000 // we now know that there is no qmldir. We can register its types.
1001 if (registerPendingTypes(import))
1002 continue;
1003
1004 // This import was not resolved
1005 QQmlError error;
1006 error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
1007 error.setUrl(m_importCache->baseUrl());
1008 error.setLine(qmlConvertSourceCoordinate<quint32, int>(
1009 import->location.line()));
1010 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
1011 import->location.column()));
1012 errors.prepend(error);
1013 }
1014
1015 if (errors.size()) {
1016 setError(errors);
1017 return false;
1018 }
1019
1020 // Load the implicit import since it may have additional scripts.
1021 if (!m_implicitImportLoaded && !loadImplicitImport())
1022 return false;
1023
1024 // Add any imported scripts to our resolved set
1025 const auto resolvedScripts = m_importCache->resolvedScripts();
1026 for (const QQmlImports::ScriptReference &script : resolvedScripts) {
1027 QQmlRefPointer<QQmlScriptBlob> blob
1028 = typeLoader()->getScript(script.location, script.fileName);
1029 addDependency(blob.data());
1030
1031 ScriptReference ref;
1032 //ref.location = ...
1033 if (!script.qualifier.isEmpty())
1034 {
1035 ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace;
1036 // Add a reference to the enclosing namespace
1037 m_namespaces.insert(script.qualifier);
1038 } else {
1039 ref.qualifier = script.nameSpace;
1040 }
1041
1042 ref.script = blob;
1043 m_scripts << ref;
1044 }
1045
1046 // Lets handle resolved composite singleton types
1047 const auto resolvedCompositeSingletons = m_importCache->resolvedCompositeSingletons();
1048 for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
1049 TypeReference ref;
1050 QString typeName;
1051 if (!csRef.prefix.isEmpty()) {
1052 typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName;
1053 // Add a reference to the enclosing namespace
1054 m_namespaces.insert(csRef.prefix);
1055 } else {
1056 typeName = csRef.typeName;
1057 }
1058
1059 QTypeRevision version = csRef.version;
1060 if (!resolveType(typeName, version, ref, -1, -1, true, QQmlType::CompositeSingletonType))
1061 return false;
1062
1063 if (ref.type.isCompositeSingleton()) {
1064 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1065 if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
1066 qCDebug(lcCycle) << "Possible cyclic dependency detected between"
1067 << ref.typeData->urlString() << "and" << urlString();
1068 continue;
1069 }
1070 addDependency(ref.typeData.data());
1071 ref.prefix = csRef.prefix;
1072
1073 m_compositeSingletons << ref;
1074 }
1075 }
1076
1077 for (auto unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
1078 unresolvedRef != end; ++unresolvedRef) {
1079
1080 TypeReference ref; // resolved reference
1081
1082 const bool reportErrors = unresolvedRef->errorWhenNotFound;
1083
1084 QTypeRevision version;
1085
1086 const QString name = stringAt(unresolvedRef.key());
1087
1088 bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
1089
1090 if (!resolveType(name, version, ref, unresolvedRef->location.line(),
1091 unresolvedRef->location.column(), reportErrors,
1092 QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
1093 return false;
1094
1095 if (ref.selfReference) {
1096 // nothing to do
1097 } else if (ref.type.isInlineComponent()) {
1098 QUrl containingTypeUrl = ref.type.sourceUrl();
1099 Q_ASSERT(!containingTypeUrl.isEmpty());
1100 if (QQmlMetaType::equalBaseUrls(finalUrl(), containingTypeUrl)) {
1101 ref.selfReference = true;
1102 } else {
1103 containingTypeUrl.setFragment(QString());
1104 auto typeData = typeLoader()->getType(containingTypeUrl);
1105 Q_ASSERT(typeData.data() != this);
1106 ref.typeData = typeData;
1107 addDependency(typeData.data());
1108 }
1109 } else if (ref.type.isComposite()) {
1110 ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
1111 addDependency(ref.typeData.data());
1112 }
1113
1114 ref.version = version;
1115 ref.location = unresolvedRef->location;
1116 ref.needsCreation = unresolvedRef->needsCreation;
1117 m_resolvedTypes.insert(unresolvedRef.key(), ref);
1118 }
1119
1120 m_typesResolved = true;
1121 return true;
1122}
1123
1124QQmlError QQmlTypeData::buildTypeResolutionCaches(
1125 QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
1126 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache) const
1127{
1128 assertTypeLoaderThread();
1129
1130 typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
1131
1132 for (const QString &ns: m_namespaces)
1133 (*typeNameCache)->add(ns);
1134
1135 // Add any Composite Singletons that were used to the import cache
1136 for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
1137 (*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
1138
1139 m_importCache->populateCache(typeNameCache->data());
1140
1141 for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
1142 auto ref = std::make_unique<QV4::ResolvedTypeReference>();
1143 QQmlType qmlType = resolvedType->type;
1144 ref->setType(qmlType);
1145 ref->setIsSelfReference(resolvedType->selfReference);
1146 if (resolvedType->typeData) {
1147 if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
1148 return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
1149 }
1150 const auto compilationUnit = resolvedType->typeData->compilationUnit();
1151 if (qmlType.isInlineComponent()) {
1152 // Inline component which is part of an already resolved type
1153 QString icName = qmlType.elementName();
1154 Q_ASSERT(!icName.isEmpty());
1155
1156 ref->setTypePropertyCache(compilationUnit->propertyCaches.at(
1157 compilationUnit->inlineComponentId(icName)));
1158 Q_ASSERT(ref->type().isInlineComponent());
1159 } else {
1160 ref->setTypePropertyCache(compilationUnit->rootPropertyCache());
1161 }
1162 if (!resolvedType->selfReference)
1163 ref->setCompilationUnit(compilationUnit);
1164 } else if (qmlType.isInlineComponent()) {
1165 // Inline component.
1166 // If it's from a different file we have a typeData and can't get here.
1167 // If it's defined in the same file we're currently compiling, we don't want to use it.
1168 // We're going to fill in the property caches later after all.
1169 Q_ASSERT(resolvedType->selfReference);
1170 Q_ASSERT(ref->isSelfReference());
1171 } else if (qmlType.isValid() && !resolvedType->selfReference) {
1172 Q_ASSERT(ref->type().isValid());
1173
1174 if (resolvedType->needsCreation && !qmlType.isCreatable()) {
1175 QString reason = qmlType.noCreationReason();
1176 if (reason.isEmpty())
1177 reason = tr("Element is not creatable.");
1178 return qQmlCompileError(resolvedType->location, reason);
1179 }
1180
1181 if (qmlType.containsRevisionedAttributes()) {
1182 // It can only have (revisioned) properties or methods if it has a metaobject
1183 Q_ASSERT(qmlType.metaObject());
1184 ref->setTypePropertyCache(
1185 QQmlMetaType::propertyCache(qmlType, resolvedType->version));
1186 }
1187 }
1188 ref->setVersion(resolvedType->version);
1189 ref->doDynamicTypeCheck();
1190 resolvedTypeCache->insert(resolvedType.key(), ref.release());
1191 }
1192 QQmlError noError;
1193 return noError;
1194}
1195
1196bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
1197 TypeReference &ref, int lineNumber, int columnNumber,
1198 bool reportErrors, QQmlType::RegistrationType registrationType,
1199 bool *typeRecursionDetected)
1200{
1201 assertTypeLoaderThread();
1202
1203 QQmlImportNamespace *typeNamespace = nullptr;
1204 QList<QQmlError> errors;
1205
1206 bool typeFound = m_importCache->resolveType(
1207 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors, registrationType,
1208 typeRecursionDetected);
1209 if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
1210 // Lazy loading of implicit import
1211 if (loadImplicitImport()) {
1212 // Try again to find the type
1213 errors.clear();
1214 typeFound = m_importCache->resolveType(
1215 typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
1216 registrationType, typeRecursionDetected);
1217 } else {
1218 return false; //loadImplicitImport() hit an error, and called setError already
1219 }
1220 }
1221
1222 if ((!typeFound || typeNamespace) && reportErrors) {
1223 // Known to not be a type:
1224 // - known to be a namespace (Namespace {})
1225 // - type with unknown namespace (UnknownNamespace.SomeType {})
1226 QQmlError error;
1227 if (typeNamespace) {
1228 error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(typeName));
1229 } else {
1230 if (errors.size()) {
1231 error = errors.takeFirst();
1232 } else {
1233 // this should not be possible!
1234 // Description should come from error provided by addImport() function.
1235 error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
1236 }
1237 error.setUrl(m_importCache->baseUrl());
1238 error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName, error.description()));
1239 }
1240
1241 if (lineNumber != -1)
1242 error.setLine(lineNumber);
1243 if (columnNumber != -1)
1244 error.setColumn(columnNumber);
1245
1246 errors.prepend(error);
1247 setError(errors);
1248 return false;
1249 }
1250
1251 return true;
1252}
1253
1254void QQmlTypeData::scriptImported(
1255 const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location,
1256 const QString &nameSpace, const QString &qualifier)
1257{
1258 assertTypeLoaderThread();
1259
1260 ScriptReference ref;
1261 ref.script = blob;
1262 ref.location = location;
1263 ref.qualifier = qualifier.isEmpty() ? nameSpace : qualifier + QLatin1Char('.') + nameSpace;
1264
1265 m_scripts << ref;
1266}
1267
1268QT_END_NAMESPACE
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
DeepAliasResult