|
|
5c5ecc4 |
From 98358715930739ca8de172d88c5ce6941c275ff3 Mon Sep 17 00:00:00 2001
|
|
|
5c5ecc4 |
From: Simon Hausmann <simon.hausmann@qt.io>
|
|
|
5c5ecc4 |
Date: Tue, 12 Sep 2017 15:13:33 +0200
|
|
|
5c5ecc4 |
Subject: [PATCH 111/153] Fix qml cache invalidation when changing dependent
|
|
|
5c5ecc4 |
C++ registered QML singletons
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
When a qml file uses a qml singleton, we need to reliably detect when
|
|
|
5c5ecc4 |
the singleton changes and re-generate the cache of the qml file using
|
|
|
5c5ecc4 |
it. This is a scenario covered and fixed by commit
|
|
|
5c5ecc4 |
5b94de09cc738837d1539e28b3c0dccd17c18d29, with the exception that
|
|
|
5c5ecc4 |
currently QML singletons registered via qmlRegisterSingleton were not
|
|
|
5c5ecc4 |
added to the list of dependent singletons for a qml file. We can fix
|
|
|
5c5ecc4 |
this by extending findCompositeSingletons() to also cover the singletons
|
|
|
5c5ecc4 |
that do not originate from a qmldir file.
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
[ChangeLog][Qt][Qml] Fixed bug where sometimes changes to a qml
|
|
|
5c5ecc4 |
singleton would not propagate to the users or cause crashes.
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
Task-number: QTBUG-62243
|
|
|
5c5ecc4 |
Change-Id: I16c3d9ba65fd82e898a29b946c341907751135a9
|
|
|
5c5ecc4 |
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
|
|
5c5ecc4 |
---
|
|
|
5c5ecc4 |
src/qml/qml/qqmlimport.cpp | 11 +++++
|
|
|
5c5ecc4 |
src/qml/qml/qqmlmetatype.cpp | 12 +++++
|
|
|
5c5ecc4 |
src/qml/qml/qqmlmetatype_p.h | 2 +
|
|
|
5c5ecc4 |
tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 61 ++++++++++++++++++++++++
|
|
|
5c5ecc4 |
4 files changed, 86 insertions(+)
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
|
|
|
5c5ecc4 |
index 0bd731747..ccd287e1b 100644
|
|
|
5c5ecc4 |
--- a/src/qml/qml/qqmlimport.cpp
|
|
|
5c5ecc4 |
+++ b/src/qml/qml/qqmlimport.cpp
|
|
|
5c5ecc4 |
@@ -471,6 +471,17 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList
|
|
|
5c5ecc4 |
resultList.append(ref);
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
|
|
|
5c5ecc4 |
+ module->walkCompositeSingletons([&resultList, &set](const QQmlType &singleton) {
|
|
|
5c5ecc4 |
+ QQmlImports::CompositeSingletonReference ref;
|
|
|
5c5ecc4 |
+ ref.typeName = singleton.elementName();
|
|
|
5c5ecc4 |
+ ref.prefix = set.prefix;
|
|
|
5c5ecc4 |
+ ref.majorVersion = singleton.majorVersion();
|
|
|
5c5ecc4 |
+ ref.minorVersion = singleton.minorVersion();
|
|
|
5c5ecc4 |
+ resultList.append(ref);
|
|
|
5c5ecc4 |
+ });
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
|
|
|
5c5ecc4 |
index 5bbc250d5..8f5d11a96 100644
|
|
|
5c5ecc4 |
--- a/src/qml/qml/qqmlmetatype.cpp
|
|
|
5c5ecc4 |
+++ b/src/qml/qml/qqmlmetatype.cpp
|
|
|
5c5ecc4 |
@@ -1258,6 +1258,18 @@ QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
|
|
|
5c5ecc4 |
return QQmlType();
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
+void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
|
|
|
5c5ecc4 |
+{
|
|
|
5c5ecc4 |
+ QMutexLocker lock(metaTypeDataLock());
|
|
|
5c5ecc4 |
+ for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
|
|
|
5c5ecc4 |
+ typeCandidates != end; ++typeCandidates) {
|
|
|
5c5ecc4 |
+ for (auto type: typeCandidates.value()) {
|
|
|
5c5ecc4 |
+ if (type->regType == QQmlType::CompositeSingletonType)
|
|
|
5c5ecc4 |
+ callback(QQmlType(type));
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
+}
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
|
|
|
5c5ecc4 |
: m_module(0), m_minor(0)
|
|
|
5c5ecc4 |
{
|
|
|
5c5ecc4 |
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
|
|
|
5c5ecc4 |
index ac2133ba3..9a7736ffc 100644
|
|
|
5c5ecc4 |
--- a/src/qml/qml/qqmlmetatype_p.h
|
|
|
5c5ecc4 |
+++ b/src/qml/qml/qqmlmetatype_p.h
|
|
|
5c5ecc4 |
@@ -298,6 +298,8 @@ public:
|
|
|
5c5ecc4 |
QQmlType type(const QHashedStringRef &, int) const;
|
|
|
5c5ecc4 |
QQmlType type(const QV4::String *, int) const;
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
+ void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
QQmlTypeModulePrivate *priv() { return d; }
|
|
|
5c5ecc4 |
private:
|
|
|
5c5ecc4 |
//Used by register functions and creates the QQmlTypeModule for them
|
|
|
5c5ecc4 |
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
|
|
|
5c5ecc4 |
index 6ab84774f..e75e51ed2 100644
|
|
|
5c5ecc4 |
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
|
|
|
5c5ecc4 |
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
|
|
|
5c5ecc4 |
@@ -59,6 +59,7 @@ private slots:
|
|
|
5c5ecc4 |
void cacheResources();
|
|
|
5c5ecc4 |
void stableOrderOfDependentCompositeTypes();
|
|
|
5c5ecc4 |
void singletonDependency();
|
|
|
5c5ecc4 |
+ void cppRegisteredSingletonDependency();
|
|
|
5c5ecc4 |
};
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
// A wrapper around QQmlComponent to ensure the temporary reference counts
|
|
|
5c5ecc4 |
@@ -790,6 +791,66 @@ void tst_qmldiskcache::singletonDependency()
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
}
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
+void tst_qmldiskcache::cppRegisteredSingletonDependency()
|
|
|
5c5ecc4 |
+{
|
|
|
5c5ecc4 |
+ qmlClearTypeRegistrations();
|
|
|
5c5ecc4 |
+ QScopedPointer<QQmlEngine> engine(new QQmlEngine);
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ QTemporaryDir tempDir;
|
|
|
5c5ecc4 |
+ QVERIFY(tempDir.isValid());
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
|
|
|
5c5ecc4 |
+ QFile f(tempDir.path() + '/' + fileName);
|
|
|
5c5ecc4 |
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
|
|
5c5ecc4 |
+ Q_ASSERT(ok);
|
|
|
5c5ecc4 |
+ f.write(contents);
|
|
|
5c5ecc4 |
+ return f.fileName();
|
|
|
5c5ecc4 |
+ };
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }");
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ qmlRegisterSingletonType(QUrl::fromLocalFile(tempDir.path() + QLatin1String("/MySingleton.qml")), "CppRegisteredSingletonDependency", 1, 0, "Singly");
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport CppRegisteredSingletonDependency 1.0\nQtObject {\n"
|
|
|
5c5ecc4 |
+ " function getValue() { return Singly.value; }\n"
|
|
|
5c5ecc4 |
+ "}");
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ {
|
|
|
5c5ecc4 |
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
|
|
|
5c5ecc4 |
+ QScopedPointer<QObject> obj(component.create());
|
|
|
5c5ecc4 |
+ QVERIFY(!obj.isNull());
|
|
|
5c5ecc4 |
+ QVariant value;
|
|
|
5c5ecc4 |
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
|
|
|
5c5ecc4 |
+ QCOMPARE(value.toInt(), 42);
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ const QString testFileCachePath = testFilePath + QLatin1Char('c');
|
|
|
5c5ecc4 |
+ QVERIFY(QFile::exists(testFileCachePath));
|
|
|
5c5ecc4 |
+ QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ engine.reset(new QQmlEngine);
|
|
|
5c5ecc4 |
+ waitForFileSystem();
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }");
|
|
|
5c5ecc4 |
+ waitForFileSystem();
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ {
|
|
|
5c5ecc4 |
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
|
|
|
5c5ecc4 |
+ QScopedPointer<QObject> obj(component.create());
|
|
|
5c5ecc4 |
+ QVERIFY(!obj.isNull());
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ {
|
|
|
5c5ecc4 |
+ QVERIFY(QFile::exists(testFileCachePath));
|
|
|
5c5ecc4 |
+ QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
|
|
|
5c5ecc4 |
+ QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString()));
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
+ QVariant value;
|
|
|
5c5ecc4 |
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
|
|
|
5c5ecc4 |
+ QCOMPARE(value.toInt(), 100);
|
|
|
5c5ecc4 |
+ }
|
|
|
5c5ecc4 |
+}
|
|
|
5c5ecc4 |
+
|
|
|
5c5ecc4 |
QTEST_MAIN(tst_qmldiskcache)
|
|
|
5c5ecc4 |
|
|
|
5c5ecc4 |
#include "tst_qmldiskcache.moc"
|
|
|
5c5ecc4 |
--
|
|
|
5c5ecc4 |
2.14.3
|
|
|
5c5ecc4 |
|