diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-09 15:24:59 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-13 08:11:08 +0000 |
commit | 5b94de09cc738837d1539e28b3c0dccd17c18d29 (patch) | |
tree | 66cd3ad68f0bddeddf3d623c10f2111ea9bffb11 | |
parent | a91b83c0bbafbdfb290f2766d51d12e805506e30 (diff) |
Fix caching of QML singleton types
When a QML file depends on a QML singleton, we failed to include it in
the dependency hash. Thus changes to the QML singleton did not result in
a re-creation of the caches of files that use it.
The list of singletons comes from random-ordered hashes in the qml
import handling. We provide an order to the direct dependencies by
sorting by the singleton type names.
Task-number: QTBUG-58486
Change-Id: Ie7e9d006f9bf3a60af1f819ee439c29bc234bd8a
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 37 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 1 | ||||
-rw-r--r-- | tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 53 |
3 files changed, 89 insertions, 2 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index dea8f3ed6f..3004fd2196 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2007,6 +2007,16 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback() { } +QString QQmlTypeData::TypeReference::qualifiedName() const +{ + QString result; + if (!prefix.isEmpty()) { + result = prefix + QLatin1Char('.'); + } + result.append(type->qmlTypeName()); + return result; +} + QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager) : QQmlTypeLoader::Blob(url, QmlFile, manager), m_typesResolved(false), m_implicitImportLoaded(false) @@ -2147,6 +2157,23 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName aliasCreator.appendAliasPropertiesToMetaObjects(); } +static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine) +{ + for (const auto &typeRef: typeRefs) { + if (typeRef.typeData) { + const auto unit = typeRef.typeData->compilationUnit(); + hash->addData(unit->data->md5Checksum, sizeof(unit->data->md5Checksum)); + } else if (typeRef.type) { + const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type->metaObject()); + bool ok = false; + hash->addData(propertyCache->checksum(&ok)); + if (!ok) + return false; + } + } + return true; +} + void QQmlTypeData::done() { QDeferredCleanup cleanup([this]{ @@ -2227,8 +2254,10 @@ void QQmlTypeData::done() QQmlEngine *const engine = typeLoader()->engine(); - const auto dependencyHasher = [engine, resolvedTypeCache](QCryptographicHash *hash) { - return resolvedTypeCache.addToHash(hash, engine); + const auto dependencyHasher = [engine, resolvedTypeCache, this](QCryptographicHash *hash) { + if (!resolvedTypeCache.addToHash(hash, engine)) + return false; + return ::addTypeReferenceChecksumsToHash(m_compositeSingletons, hash, engine); }; // verify if any dependencies changed if we're using a cache @@ -2568,6 +2597,10 @@ void QQmlTypeData::resolveTypes() } } + std::stable_sort(m_compositeSingletons.begin(), m_compositeSingletons.end(), [](const TypeReference &lhs, const TypeReference &rhs){ + return lhs.qualifiedName() < rhs.qualifiedName(); + }); + for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd(); unresolvedRef != end; ++unresolvedRef) { diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d85346c23e..e3c4a52c45 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -400,6 +400,7 @@ public: int minorVersion; QQmlTypeData *typeData; QString prefix; // used by CompositeSingleton types + QString qualifiedName() const; bool needsCreation; }; diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index b265607fd1..9494e3a7fd 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -58,6 +58,7 @@ private slots: void localAliases(); void cacheResources(); void stableOrderOfDependentCompositeTypes(); + void singletonDependency(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -737,6 +738,58 @@ void tst_qmldiskcache::stableOrderOfDependentCompositeTypes() } } +void tst_qmldiskcache::singletonDependency() +{ + QScopedPointer<QQmlEngine> engine(new QQmlEngine); + + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) { + QFile f(tempDir.path() + '/' + fileName); + const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); + Q_ASSERT(ok); + f.write(contents); + return f.fileName(); + }; + + writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }"); + writeTempFile("qmldir", "singleton MySingleton 1.0 MySingleton.qml"); + const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport \".\"\nQtObject {\n" + " property int value: MySingleton.value\n" + "}"); + + { + CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 42); + } + + const QString testFileCachePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(testFileCachePath)); + QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); + + engine.reset(new QQmlEngine); + waitForFileSystem(); + + writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }"); + waitForFileSystem(); + + { + CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 100); + } + + { + QVERIFY(QFile::exists(testFileCachePath)); + QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified(); + QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString())); + } +} + QTEST_MAIN(tst_qmldiskcache) #include "tst_qmldiskcache.moc" |