aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-01-07 15:35:20 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-10 10:26:43 +0100
commit5c40193f8223a8bdefcf694c719396807a83f0ea (patch)
tree626991eb96b9da976cf0ebe6c944012e81effe0b
parentb681bd3e4ad20eb558da68ba1a2e2dfddfab9cf1 (diff)
[new compiler] Add support for implicitly defined components
Use-cases like itemDelegate: Item { ... } implicitly define a component without the item-surrounding Component {}, base on the fact that the property itself is of type QQmlComponent (or derived). This means we have to synthesize a Component {} object and insert it into the data structure. Change-Id: I8992451a5a6732c7fd898eaf83c276dc6a8b7d19 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp27
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h4
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp10
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp100
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h14
7 files changed, 124 insertions, 35 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index a4da07ab66..f0dfc9b7ea 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -64,6 +64,21 @@ using namespace QtQml;
return false; \
}
+void QmlObject::init(MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &loc)
+{
+ inheritedTypeNameIndex = typeNameIndex;
+
+ location.line = loc.startLine;
+ location.column = loc.startColumn;
+
+ idIndex = id;
+ indexOfDefaultProperty = -1;
+ properties = pool->New<PoolList<QmlProperty> >();
+ qmlSignals = pool->New<PoolList<Signal> >();
+ bindings = pool->New<PoolList<Binding> >();
+ functions = pool->New<PoolList<Function> >();
+}
+
void QmlObject::dump(DebugStream &out)
{
out << inheritedTypeNameIndex << " {" << endl;
@@ -306,20 +321,10 @@ int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId,
const int objectIndex = _objects.size() - 1;
qSwap(_object, obj);
- _object->inheritedTypeNameIndex = registerString(asString(qualifiedTypeNameId));
-
AST::SourceLocation loc;
if (qualifiedTypeNameId)
loc = qualifiedTypeNameId->firstSourceLocation();
- _object->location.line = loc.startLine;
- _object->location.column = loc.startColumn;
-
- _object->idIndex = emptyStringIndex;
- _object->indexOfDefaultProperty = -1;
- _object->properties = New<PoolList<QmlProperty> >();
- _object->qmlSignals = New<PoolList<Signal> >();
- _object->bindings = New<PoolList<Binding> >();
- _object->functions = New<PoolList<Function> >();
+ _object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, loc);
QSet<QString> propertyNames;
qSwap(_propertyNames, propertyNames);
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 18193eea2b..4b126ef5ea 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -155,6 +155,8 @@ struct QmlObject
PoolList<Binding> *bindings;
PoolList<Function> *functions;
+ void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &location = AST::SourceLocation());
+
void dump(DebugStream &out);
};
@@ -274,7 +276,7 @@ public:
static QQmlScript::LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
int registerString(const QString &str) const { return jsGenerator->registerString(str); }
- template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
QString stringAt(int index) const { return jsGenerator->strings.at(index); }
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index b5a48f3611..f39ea2f3c7 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -224,6 +224,11 @@ QString QQmlTypeCompiler::stringAt(int idx) const
return parsedQML->stringAt(idx);
}
+int QQmlTypeCompiler::registerString(const QString &str)
+{
+ return parsedQML->jsGenerator.registerString(str);
+}
+
const QV4::CompiledData::QmlUnit *QQmlTypeCompiler::qmlUnit() const
{
return compiledData->qmlUnit;
@@ -274,4 +279,9 @@ QHash<int, QByteArray> *QQmlTypeCompiler::customParserData()
return &compiledData->customParserData;
}
+MemoryPool *QQmlTypeCompiler::memoryPool()
+{
+ return parsedQML->jsParserEngine.pool();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 9ce8313d8d..442911093c 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -75,6 +75,7 @@ struct QQmlTypeCompiler
void recordError(const QQmlError &error);
QString stringAt(int idx) const;
+ int registerString(const QString &str);
const QV4::CompiledData::QmlUnit *qmlUnit() const;
@@ -88,6 +89,7 @@ struct QQmlTypeCompiler
QHash<int, int> *objectIndexToIdForRoot();
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
QHash<int, QByteArray> *customParserData();
+ QQmlJS::MemoryPool *memoryPool();
private:
QList<QQmlError> errors;
diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h
index 820ae8ed71..29103930ad 100644
--- a/src/qml/parser/qqmljsmemorypool_p.h
+++ b/src/qml/parser/qqmljsmemorypool_p.h
@@ -108,6 +108,8 @@ public:
_ptr = _end = 0;
}
+ template <typename _Tp> _Tp *New() { return new (this->allocate(sizeof(_Tp))) _Tp(); }
+
private:
void *allocate_helper(size_t size)
{
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 1067a8dd0a..4e6f354214 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1470,11 +1470,13 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
+ , enginePrivate(typeCompiler->enginePrivate())
+ , pool(typeCompiler->memoryPool())
+ , qmlObjects(typeCompiler->qmlObjects())
, indexOfRootObject(typeCompiler->rootObjectIndex())
, _componentIndex(-1)
, _objectIndexToIdInScope(0)
- , resolvedTypes(*typeCompiler->resolvedTypes())
+ , resolvedTypes(typeCompiler->resolvedTypes())
, propertyCaches(typeCompiler->propertyCaches())
, vmeMetaObjectData(typeCompiler->vmeMetaObjects())
, objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
@@ -1482,26 +1484,88 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
{
}
-bool QQmlComponentAndAliasResolver::resolve()
+void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex)
{
- QVector<int> componentRoots;
+ QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
+ Q_ASSERT(propertyCache);
+
+ PropertyResolver propertyResolver(propertyCache);
+
+ for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ continue;
+ if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ continue;
+
+ const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex);
+ QQmlType *targetType = resolvedTypes->value(targetObject->inheritedTypeNameIndex).type;
+ if (targetType && targetType->metaObject() == &QQmlComponent::staticMetaObject)
+ continue;
+
+ QString propertyName = stringAt(binding->propertyNameIndex);
+ bool notInRevision = false;
+ QQmlPropertyData *pd = propertyResolver.property(propertyName, &notInRevision);
+ if (!pd || !pd->isQObject())
+ continue;
+
+ QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType);
+ const QMetaObject *mo = pc->firstCppMetaObject();
+ while (mo) {
+ if (mo == &QQmlComponent::staticMetaObject)
+ break;
+ mo = mo->superClass();
+ }
+
+ if (!mo)
+ continue;
+
+ static QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
+ Q_ASSERT(componentType);
+
+ QtQml::QmlObject *syntheticComponent = pool->New<QtQml::QmlObject>();
+ syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
+
+ if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
+ QQmlCompiledData::TypeReference typeRef;
+ typeRef.type = componentType;
+ typeRef.majorVersion = componentType->majorVersion();
+ typeRef.minorVersion = componentType->minorVersion();
+ resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
+ }
- // Find objects that are Components. This is missing an extra pass
- // that finds implicitly defined components, i.e.
- // someProperty: Item { ... }
- // when someProperty _is_ a QQmlComponent. In that case the Item {}
- // should be implicitly surrounded by Component {}
+ qmlObjects->append(syntheticComponent);
+ const int componentIndex = qmlObjects->count() - 1;
- for (int i = 0; i < qmlObjects.count(); ++i) {
- const QtQml::QmlObject *obj = qmlObjects.at(i);
+ QtQml::Binding *syntheticBinding = pool->New<QtQml::Binding>();
+ *syntheticBinding = *binding;
+ syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
+ syntheticComponent->bindings->append(syntheticBinding);
+
+ binding->value.objectIndex = componentIndex;
+
+ componentRoots.append(componentIndex);
+ componentBoundaries.append(syntheticBinding->value.objectIndex);
+ }
+}
+
+bool QQmlComponentAndAliasResolver::resolve()
+{
+ // Detect real Component {} objects as well as implicitly defined components, such as
+ // someItemDelegate: Item {}
+ // In the implicit case Item is surrounded by a synthetic Component {} because the property
+ // on the left hand side is of QQmlComponent type.
+ for (int i = 0; i < qmlObjects->count(); ++i) {
+ const QtQml::QmlObject *obj = qmlObjects->at(i);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty())
continue;
- QQmlCompiledData::TypeReference tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ QQmlCompiledData::TypeReference tref = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (!tref.type)
continue;
- if (tref.type->metaObject() != &QQmlComponent::staticMetaObject)
+ if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) {
+ findAndRegisterImplicitComponents(obj, i);
continue;
+ }
componentRoots.append(i);
@@ -1525,7 +1589,7 @@ bool QQmlComponentAndAliasResolver::resolve()
std::sort(componentBoundaries.begin(), componentBoundaries.end());
for (int i = 0; i < componentRoots.count(); ++i) {
- const QtQml::QmlObject *component = qmlObjects.at(componentRoots.at(i));
+ const QtQml::QmlObject *component = qmlObjects->at(componentRoots.at(i));
const QtQml::Binding *rootBinding = component->bindings->first;
_componentIndex = i;
@@ -1557,7 +1621,7 @@ bool QQmlComponentAndAliasResolver::resolve()
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
{
- const QtQml::QmlObject *obj = qmlObjects.at(objectIndex);
+ const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
QString id = stringAt(obj->idIndex);
if (!id.isEmpty()) {
@@ -1596,7 +1660,7 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
bool QQmlComponentAndAliasResolver::resolveAliases()
{
foreach (int objectIndex, _objectsWithAliases) {
- const QtQml::QmlObject *obj = qmlObjects.at(objectIndex);
+ const QtQml::QmlObject *obj = qmlObjects->at(objectIndex);
QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex);
Q_ASSERT(propertyCache);
@@ -1642,8 +1706,8 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
quint32 propertyFlags = QQmlPropertyData::IsAlias;
if (property.isEmpty()) {
- const QtQml::QmlObject *targetObject = qmlObjects.at(targetObjectIndex);
- QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex);
+ const QtQml::QmlObject *targetObject = qmlObjects->at(targetObjectIndex);
+ QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex);
if (typeRef.type)
type = typeRef.type->typeId();
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 92f40648d3..2d776058ca 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -76,16 +76,20 @@ public:
bool resolve();
protected:
+ void findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex);
bool collectIdsAndAliases(int objectIndex);
bool resolveAliases();
- bool isComponentType(int typeNameIndex) const
- { return resolvedTypes.value(typeNameIndex).type == 0; }
+ QQmlEnginePrivate *enginePrivate;
+ QQmlJS::MemoryPool *pool;
- const QList<QtQml::QmlObject*> &qmlObjects;
+ QList<QtQml::QmlObject*> *qmlObjects;
const int indexOfRootObject;
- // indices of objects that are of type QQmlComponent
+ // indices of the objects that are actually Component {}
+ QVector<int> componentRoots;
+ // indices of objects that are the beginning of a new component
+ // scope. This is sorted and used for binary search.
QVector<int> componentBoundaries;
int _componentIndex;
@@ -93,7 +97,7 @@ protected:
QHash<int, int> *_objectIndexToIdInScope;
QList<int> _objectsWithAliases;
- const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
+ QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
const QList<QQmlPropertyCache *> propertyCaches;
QList<QByteArray> *vmeMetaObjectData;
QHash<int, int> *objectIndexToIdForRoot;