From 890cb4cb236333fd5b112fffc0e9088ecb43f2df Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Mon, 1 Mar 2021 15:34:58 +0100 Subject: qqmlapplicationengine: Handle errors during component creation Previously QQmlApplicationEngine did not handle any errors that occurred during object creation (i.e. failures to initialize required properties) which lead to QObject::connect errors and to the error messages not getting printed among other issues. Pick-to: 5.15 6.0 6.1 Change-Id: I69bc566a6d349c786cae82a963a621388684c8f5 Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmlapplicationengine.cpp | 8 ++++++++ tests/auto/qml/qqmlapplicationengine/data/Required.qml | 6 ++++++ .../qqmlapplicationengine/data/requiredViolation.qml | 3 +++ .../tst_qqmlapplicationengine.cpp | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+) create mode 100644 tests/auto/qml/qqmlapplicationengine/data/Required.qml create mode 100644 tests/auto/qml/qqmlapplicationengine/data/requiredViolation.qml diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index d866301f84..e0ab25892f 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -152,6 +152,14 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) break; case QQmlComponent::Ready: { auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties); + + if (c->isError()) { + qWarning() << "QQmlApplicationEngine failed to create component"; + warning(c->errors()); + q->objectCreated(nullptr, c->url()); + break; + } + objects << newObj; QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); }); q->objectCreated(objects.constLast(), c->url()); diff --git a/tests/auto/qml/qqmlapplicationengine/data/Required.qml b/tests/auto/qml/qqmlapplicationengine/data/Required.qml new file mode 100644 index 0000000000..dd45902bef --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/data/Required.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject +{ + required property int foo +} diff --git a/tests/auto/qml/qqmlapplicationengine/data/requiredViolation.qml b/tests/auto/qml/qqmlapplicationengine/data/requiredViolation.qml new file mode 100644 index 0000000000..21c29ca6c2 --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/data/requiredViolation.qml @@ -0,0 +1,3 @@ +import QtQml + +Required {} diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp index 365e40dfeb..a35375d6f3 100644 --- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp +++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp @@ -56,6 +56,7 @@ private slots: void translationChange(); void setInitialProperties(); void failureToLoadTriggersWarningSignal(); + void errorWhileCreating(); private: QString buildDir; @@ -333,6 +334,23 @@ void tst_qqmlapplicationengine::failureToLoadTriggersWarningSignal() QTRY_COMPARE(warningObserver.count(), 1); } +void tst_qqmlapplicationengine::errorWhileCreating() +{ + auto url = testFileUrl("requiredViolation.qml"); + QQmlApplicationEngine test; + QSignalSpy observer(&test, &QQmlApplicationEngine::objectCreated); + + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlApplicationEngine failed to create component"); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, qPrintable(QStringLiteral("%1:5:5: Required property foo was not initialized").arg(testFileUrl("Required.qml").toString()))); + + test.load(url); + + QTRY_COMPARE(observer.count(), 1); + QList args = observer.takeFirst(); + QVERIFY(args.at(0).isNull()); + QCOMPARE(args.at(1).toUrl(), url); +} + QTEST_MAIN(tst_qqmlapplicationengine) #include "tst_qqmlapplicationengine.moc" -- cgit v1.2.3