diff options
author | Richard Weickelt <richard@weickelt.de> | 2018-05-15 12:28:41 +0200 |
---|---|---|
committer | Richard Weickelt <richard@weickelt.de> | 2018-05-18 09:29:26 +0000 |
commit | d33d5a40483c6b56c3be19ce244f14938a5941a0 (patch) | |
tree | fdc7a803067b976ccf24470ee9288238806e1667 | |
parent | 38dc69ae01d2ba733fb35f7c8d26500062858798 (diff) |
Allow partial creation of more than 10 QQmlComponent instances
The recursion detection in QQmlComponent erroneously triggered when
calling beginCreate() on >= 10 different instances. This may happen by
intention and is not necessarily a sign of recursion.
Since beginCreate() does never invoke a potentially nested
Qt.createComponent(), but completeCreate() does, it is better to
modify the creationDepth counter in completeCreate(). This also leads
to simpler code.
The test, however, can remain in beginCreate().
Task-number: QTBUG-47633
Change-Id: If413a8b08421d321d6a426ec16600996cb3f6ea1
Reviewed-by: Matthew Vogt <matthew.vogt@qinetic.com.au>
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 24 |
3 files changed, 27 insertions, 15 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 1802932f45..22e20de8d7 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -845,13 +845,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) // Do not create infinite recursion in object creation static const int maxCreationDepth = 10; - if (++creationDepth.localData() >= maxCreationDepth) { + if (creationDepth.localData() >= maxCreationDepth) { qWarning("QQmlComponent: Component creation is recursing - aborting"); - --creationDepth.localData(); return nullptr; } - Q_ASSERT(creationDepth.localData() >= 1); - depthIncreased = true; QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); @@ -875,10 +872,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) ddata->indestructible = true; ddata->explicitIndestructibleSet = true; ddata->rootObjectInCreation = false; - } else { - Q_ASSERT(creationDepth.localData() >= 1); - --creationDepth.localData(); - depthIncreased = false; } return rv; @@ -952,14 +945,10 @@ void QQmlComponent::completeCreate() void QQmlComponentPrivate::completeCreate() { if (state.completePending) { + ++creationDepth.localData(); QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); complete(ep, &state); - } - - if (depthIncreased) { - Q_ASSERT(creationDepth.localData() >= 1); --creationDepth.localData(); - depthIncreased = false; } } diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 83af5074b8..9b2db4bccf 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -79,7 +79,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public public: QQmlComponentPrivate() - : progress(0.), start(-1), engine(nullptr), creationContext(nullptr), depthIncreased(false) {} + : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {} void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous); @@ -136,7 +136,6 @@ public: QQmlEngine *engine; QQmlGuardedContextData creationContext; - bool depthIncreased; void clear(); diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 6a0dc28ca4..0263115db8 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -116,6 +116,7 @@ private slots: void onDestructionCount(); void recursion(); void recursionContinuation(); + void partialComponentCreation(); void callingContextForInitialProperties(); void relativeUrl_data(); void relativeUrl(); @@ -526,6 +527,29 @@ void tst_qqmlcomponent::recursionContinuation() QVERIFY(object->property("success").toBool()); } +void tst_qqmlcomponent::partialComponentCreation() +{ + const int maxCount = 17; + QQmlEngine engine; + QScopedPointer<QQmlComponent> components[maxCount]; + QScopedPointer<QObject> objects[maxCount]; + QQmlTestMessageHandler messageHandler; + + QCOMPARE(engine.outputWarningsToStandardError(), true); + + for (int i = 0; i < maxCount; i++) { + components[i].reset(new QQmlComponent(&engine, testFileUrl("QtObjectComponent.qml"))); + objects[i].reset(components[i]->beginCreate(engine.rootContext())); + QVERIFY(objects[i].isNull() == false); + } + QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString())); + + for (int i = 0; i < maxCount; i++) { + components[i]->completeCreate(); + } + QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString())); +} + class CallingContextCheckingClass : public QObject { Q_OBJECT |