aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4executablecompilationunit.cpp
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-01-15 14:47:35 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2020-01-23 15:58:10 +0100
commit684f9df7849bc79f1f02a60844fb43c7a3927d2f (patch)
tree531be4d102388395e4ddd2d14f38a679e15c283d /src/qml/jsruntime/qv4executablecompilationunit.cpp
parent020a6e67766595351bcf911e965b26952a7c81b8 (diff)
Long live QML inline components
[ChangeLog][QtQml] It is now possible to declare new QML components in a QML file via the component keyword. They can be used just as if they were declared in another file, with the only difference that the type name needs to be prefixed with the name of the containing type outside of the file were the inline component has been declared. Notably, inline components are not closures: In the following example, the output would be 42 // MyItem.qml Item { property int i: 33 component IC: Item { Component.onCompleted: console.log(i) } } // user.qml Item { property int i: 42 MyItem.IC {} } Fixes: QTBUG-79382 Change-Id: I6a5ffc43f093a76323f435cfee9bab217781b8f5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4executablecompilationunit.cpp')
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp111
1 files changed, 99 insertions, 12 deletions
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index b1e2879bba..fa4a1f1ce4 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -53,6 +53,7 @@
#include <private/qv4compilationunitmapper_p.h>
#include <private/qml_compile_hash_p.h>
#include <private/qqmltypewrapper_p.h>
+#include <private/inlinecomponentutils_p.h>
#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlpropertymap.h>
@@ -62,6 +63,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/QScopedValueRollback>
#if defined(QML_COMPILE_HASH)
# ifdef Q_OS_LINUX
@@ -387,7 +389,7 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
-void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds)
+void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds typeIds)
{
this->qmlEngine = qmlEngine;
@@ -399,6 +401,7 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
metaTypeId = typeIds.id;
listMetaTypeId = typeIds.listId;
qmlEngine->registerInternalCompositeType(this);
+
} else {
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
@@ -413,29 +416,105 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
}
// Collect some data for instantiation later.
+ using namespace icutils;
+ std::vector<QV4::CompiledData::InlineComponent> allICs {};
+ for (int i=0; i != objectCount(); ++i) {
+ const CompiledObject *obj = objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+ std::vector<Node> nodes;
+ nodes.resize(allICs.size());
+ std::iota(nodes.begin(), nodes.end(), 0);
+ AdjacencyList adjacencyList;
+ adjacencyList.resize(nodes.size());
+ fillAdjacencyListForInlineComponents(this, adjacencyList, nodes, allICs);
+ bool hasCycle = false;
+ auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ Q_ASSERT(!hasCycle); // would have already been discovered by qqmlpropertycachcecreator
+
+ // We need to first iterate over all inline components, as the containing component might create instances of them
+ // and in that case we need to add its object count
+ for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
+ const auto &ic = allICs.at(nodeIt->index);
+ int lastICRoot = ic.objectIndex;
+ for (int i = ic.objectIndex; i<objectCount(); ++i) {
+ const QV4::CompiledData::Object *obj = objectAt(i);
+ bool leftCurrentInlineComponent =
+ (i != lastICRoot && obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ || !(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ if (leftCurrentInlineComponent)
+ break;
+ inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings;
+
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1)
+ ++inlineComponentData[lastICRoot].totalParserStatusCount;
+
+ ++inlineComponentData[lastICRoot].totalObjectCount;
+ if (typeRef->compilationUnit) {
+ // if the type is an inline component type, we have to extract the information from it
+ // This requires that inline components are visited in the correct order
+ auto icRoot = typeRef->compilationUnit->icRoot;
+ if (typeRef->type.isInlineComponentType()) {
+ icRoot = typeRef->type.inlineComponendId();
+ }
+ QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot};
+ inlineComponentData[lastICRoot].totalBindingCount += typeRef->compilationUnit->totalBindingsCount();
+ inlineComponentData[lastICRoot].totalParserStatusCount += typeRef->compilationUnit->totalParserStatusCount();
+ inlineComponentData[lastICRoot].totalObjectCount += typeRef->compilationUnit->totalObjectCount();
+ }
+ }
+ }
+ }
int bindingCount = 0;
int parserStatusCount = 0;
int objectCount = 0;
for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
+ if (obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) {
+ continue;
+ }
bindingCount += obj->nBindings;
if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid()) {
- if (typeRef->type.parserStatusCast() != -1)
- ++parserStatusCount;
- }
+ if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1)
+ ++parserStatusCount;
++objectCount;
if (typeRef->compilationUnit) {
- bindingCount += typeRef->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->compilationUnit->totalObjectCount;
+ auto icRoot = typeRef->compilationUnit->icRoot;
+ if (typeRef->type.isInlineComponentType()) {
+ icRoot = typeRef->type.inlineComponendId();
+ }
+ QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot};
+ bindingCount += typeRef->compilationUnit->totalBindingsCount();
+ parserStatusCount += typeRef->compilationUnit->totalParserStatusCount();
+ objectCount += typeRef->compilationUnit->totalObjectCount();
}
}
}
- totalBindingsCount = bindingCount;
- totalParserStatusCount = parserStatusCount;
- totalObjectCount = objectCount;
+ m_totalBindingsCount = bindingCount;
+ m_totalParserStatusCount = parserStatusCount;
+ m_totalObjectCount = objectCount;
+}
+
+int ExecutableCompilationUnit::totalBindingsCount() const {
+ if (icRoot == -1)
+ return m_totalBindingsCount;
+ return inlineComponentData[icRoot].totalBindingCount;
+}
+
+int ExecutableCompilationUnit::totalObjectCount() const {
+ if (icRoot == -1)
+ return m_totalObjectCount;
+ return inlineComponentData[icRoot].totalObjectCount;
+}
+
+int ExecutableCompilationUnit::totalParserStatusCount() const {
+ if (icRoot == -1)
+ return m_totalParserStatusCount;
+ return inlineComponentData[icRoot].totalParserStatusCount;
}
bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
@@ -453,6 +532,13 @@ bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentType
sizeof(data->dependencyMD5Checksum)) == 0;
}
+CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent(int objectid) const
+{
+ if (objectid == 0)
+ return {metaTypeId, listMetaTypeId};
+ return inlineComponentData[objectid].typeIds;
+}
+
QStringList ExecutableCompilationUnit::moduleRequests() const
{
QStringList requests;
@@ -734,13 +820,14 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQm
typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion);
return typePropertyCache;
} else {
+ Q_ASSERT(compilationUnit);
return compilationUnit->rootPropertyCache();
}
}
bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine)
{
- if (type.isValid()) {
+ if (type.isValid() && !type.isInlineComponentType()) {
bool ok = false;
hash->addData(createPropertyCache(engine)->checksum(&ok));
return ok;