From dd4a79c36b39415171ca2f4723b3cdd52e5eebd0 Mon Sep 17 00:00:00 2001 From: Jaeyoon Jung Date: Thu, 15 Jul 2021 11:44:55 +0900 Subject: [PATCH] Fix qmldir cache inconsistency If there are multiple qmldir entries for the same QML module in the import list, the one that comes first should take precedence. The same applies when constructing the qmldir cache. We can achieve that by inserting the entries into the cache in the same order they appear in the completeQmldirPaths list. Pick-to: 6.2 Change-Id: Ic56a0952b16c4be016180c695d79089fc132319a Reviewed-by: Fabian Kosmale --- src/qml/qml/qqmlimport_p.h | 51 +++++++++---------- .../data/importPathOrder/MyModuleTest.qml | 7 +++ .../data/importPathOrder/MyView.qml | 3 ++ .../importPathOrder/path1/MyModule/MyItem.qml | 6 +++ .../importPathOrder/path1/MyModule/qmldir | 3 ++ .../importPathOrder/path2/MyModule/MyItem.qml | 6 +++ .../importPathOrder/path2/MyModule/qmldir | 3 ++ tests/auto/qml/qqmlimport/tst_qqmlimport.cpp | 16 ++++++ 8 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/MyModuleTest.qml create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/MyView.qml create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/MyItem.qml create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/qmldir create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/MyItem.qml create mode 100644 tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/qmldir diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index f92c2f7c38..2d27fed648 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -278,28 +278,27 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir( // Check cache first LocalQmldirResult result = QmldirNotFound; - QmldirCache *cacheHead = nullptr; - { - QmldirCache **cachePtr = qmldirCache.value(uri); - if (cachePtr) { - cacheHead = *cachePtr; - QmldirCache *cache = cacheHead; - while (cache) { - if (cache->version == version) { - if (cache->qmldirFilePath.isEmpty()) { - return cache->qmldirPathUrl.isEmpty() - ? QmldirNotFound - : QmldirInterceptedToRemote; - } - if (callback(cache->qmldirFilePath, cache->qmldirPathUrl)) - return QmldirFound; - result = QmldirRejected; + QmldirCache *cacheTail = nullptr; + + QmldirCache **cachePtr = qmldirCache.value(uri); + QmldirCache *cacheHead = cachePtr ? *cachePtr : nullptr; + if (cacheHead) { + cacheTail = cacheHead; + do { + if (cacheTail->version == version) { + if (cacheTail->qmldirFilePath.isEmpty()) { + return cacheTail->qmldirPathUrl.isEmpty() + ? QmldirNotFound + : QmldirInterceptedToRemote; } - cache = cache->next; + if (callback(cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl)) + return QmldirFound; + result = QmldirRejected; } - } + } while (cacheTail->next && (cacheTail = cacheTail->next)); } + // Do not try to construct the cache if it already had any entries for the URI. // Otherwise we might duplicate cache entries. if (result != QmldirNotFound) @@ -349,15 +348,15 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir( cache->version = version; cache->qmldirFilePath = qmldirAbsoluteFilePath; cache->qmldirPathUrl = url; - cache->next = cacheHead; - qmldirCache.insert(uri, cache); - cacheHead = cache; + cache->next = nullptr; + if (cacheTail) + cacheTail->next = cache; + else + qmldirCache.insert(uri, cache); + cacheTail = cache; - if (result != QmldirFound) { - result = callback(qmldirAbsoluteFilePath, url) - ? QmldirFound - : QmldirRejected; - } + if (result != QmldirFound) + result = callback(qmldirAbsoluteFilePath, url) ? QmldirFound : QmldirRejected; // Do not return here. Rather, construct the complete cache for this URI. } diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/MyModuleTest.qml b/tests/auto/qml/qqmlimport/data/importPathOrder/MyModuleTest.qml new file mode 100644 index 0000000000..5ac9ec4fb2 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/MyModuleTest.qml @@ -0,0 +1,7 @@ +import QtQuick +import MyModule + +Item { + MyItem { objectName: "myItem1" } + MyView {} +} diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/MyView.qml b/tests/auto/qml/qqmlimport/data/importPathOrder/MyView.qml new file mode 100644 index 0000000000..a4fdcb51a0 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/MyView.qml @@ -0,0 +1,3 @@ +import MyModule + +MyItem { objectName: "myItem2" } diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/MyItem.qml b/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/MyItem.qml new file mode 100644 index 0000000000..3da82d1b77 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/MyItem.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + width: 100 + height: 100 +} diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/qmldir b/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/qmldir new file mode 100644 index 0000000000..edfd2c9462 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/path1/MyModule/qmldir @@ -0,0 +1,3 @@ +module MyModule + +MyItem MyItem.qml diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/MyItem.qml b/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/MyItem.qml new file mode 100644 index 0000000000..ed02d2df7a --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/MyItem.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + width: 200 + height: 200 +} diff --git a/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/qmldir b/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/qmldir new file mode 100644 index 0000000000..edfd2c9462 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importPathOrder/path2/MyModule/qmldir @@ -0,0 +1,3 @@ +module MyModule + +MyItem MyItem.qml diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 4f2b4f6b13..572c8771a0 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -205,6 +205,22 @@ void tst_QQmlImport::importPathOrder() engine.addImportPath(qml2Imports); expectedImportPaths.move(expectedImportPaths.indexOf(qml2Imports), 0); QCOMPARE(engine.importPathList(), expectedImportPaths); + + // Verify if the type in the module comes first in the import path list + // takes the precedence. In the case below, the width of both items + // should be the same to that of the type defined in "path2". + engine.addImportPath(testFile("importPathOrder/path1")); + engine.addImportPath(testFile("importPathOrder/path2")); + QQmlComponent component(&engine, testFile("importPathOrder/MyModuleTest.qml")); + QScopedPointer rootItem(component.create()); + QVERIFY(component.errorString().isEmpty()); + QVERIFY(!rootItem.isNull()); + QQuickItem *item1 = rootItem->findChild("myItem1"); + QQuickItem *item2 = rootItem->findChild("myItem2"); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QCOMPARE(item1->width(), 200); + QCOMPARE(item2->width(), 200); } Q_DECLARE_METATYPE(QQmlImports::ImportVersion)