From c7b6d83f9449a42d7fff534ea36d350f2f7601e8 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 9 Aug 2022 17:36:42 +0200 Subject: [PATCH] QmlDesigner: Add comon type cache There are common types like QtQuick.Item or double which are needed for a fast lookup. Task-number: QDS-7380 Change-Id: Ibbdf77e2cc351fc56eeca3b96ac1b83a3feb83c9 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann Reviewed-by: --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../projectstorage/commontypecache.h | 100 ++++++++++++ .../projectstorage/projectstorage.h | 30 +++- .../projectstorage/projectstorageinterface.h | 2 +- tests/unit/unittest/projectstorage-test.cpp | 146 ++++++++++++++++++ tests/unit/unittest/projectstoragemock.h | 2 +- 6 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 3ef5dbcce1c..7146d8c567f 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -456,6 +456,7 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX designercore/projectstorage SOURCES + commontypecache.h directorypathcompressor.h filesysteminterface.h filesystem.cpp filesystem.h diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h new file mode 100644 index 00000000000..06307be0f84 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "projectstoragetypes.h" + +#include +#include + +namespace QmlDesigner::Storage::Info { + +inline constexpr char QtQuick[] = "QtQuick"; +inline constexpr char QML[] = "QML"; +inline constexpr char Item[] = "Item"; +inline constexpr char DoubleType[] = "double"; +inline constexpr char var[] = "var"; + +template +struct CacheType +{ + QmlDesigner::ModuleId moduleId; + QmlDesigner::TypeId typeId; +}; + +template +class CommonTypeCache +{ + using CommonTypes = std::tuple, CacheType, CacheType>; + +public: + CommonTypeCache(const ProjectStorage &projectStorage) + : m_projectStorage{projectStorage} + {} + + void resetTypeIds() + { + std::apply([](auto &...type) { ((type.typeId = QmlDesigner::TypeId{}), ...); }, m_types); + } + + template + auto typeId() const + { + auto &type = std::get>(m_types); + if (type.typeId) + return type.typeId; + + if (!type.moduleId) + type.moduleId = m_projectStorage.moduleId(moduleName); + + type.typeId = m_projectStorage.typeId(type.moduleId, + typeName, + QmlDesigner::Storage::Synchronization::Version{}); + + return type.typeId; + } + + template + auto builtinTypeId() const + { + return typeId(); + } + + template + auto builtinTypeId() const + { + if constexpr (std::is_same_v) + return builtinTypeId(); + else + return TypeId{}; + } + +private: + const ProjectStorage &m_projectStorage; + mutable CommonTypes m_types; +}; + +} // namespace QmlDesigner::Storage::Info diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index f0d9a3b6a96..65bb06cfd81 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -25,6 +25,7 @@ #pragma once +#include "commontypecache.h" #include "projectstorageexceptions.h" #include "projectstorageinterface.h" #include "sourcepathcachetypes.h" @@ -116,15 +117,17 @@ public: synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds); + commonTypeCache.resetTypeIds(); + transaction.commit(); } - ModuleId moduleId(Utils::SmallStringView moduleName) override + ModuleId moduleId(Utils::SmallStringView moduleName) const override { return moduleCache.id(moduleName); } - Utils::SmallString moduleName(ModuleId moduleId) + Utils::SmallString moduleName(ModuleId moduleId) const { if (!moduleId) throw ModuleDoesNotExists{}; @@ -134,7 +137,7 @@ public: TypeId typeId(ModuleId moduleId, Utils::SmallStringView exportedTypeName, - Storage::Synchronization::Version version) + Storage::Synchronization::Version version) const { if (version.minor) return selectTypeIdByModuleIdAndExportedNameAndVersionStatement @@ -208,6 +211,24 @@ public: propertyDeclarationId); } + template + TypeId commonTypeId() const + { + return commonTypeCache.template typeId(); + } + + template + TypeId builtinTypeId() const + { + return commonTypeCache.template builtinTypeId(); + } + + template + TypeId builtinTypeId() const + { + return commonTypeCache.template builtinTypeId(); + } + PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, Utils::SmallStringView name) { @@ -2515,7 +2536,8 @@ private: public: Database &database; Initializer initializer; - ModuleCache moduleCache{ModuleStorageAdapter{*this}}; + mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}}; + Storage::Info::CommonTypeCache> commonTypeCache{*this}; ReadWriteStatement<1, 3> upsertTypeStatement{ "INSERT INTO types(sourceId, name, traits) VALUES(?1, ?2, ?3) ON CONFLICT DO " "UPDATE SET traits=excluded.traits WHERE traits IS NOT " diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index bd9013c6bcc..f5aef722855 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -35,7 +35,7 @@ class ProjectStorageInterface public: virtual void synchronize(Storage::Synchronization::SynchronizationPackage package) = 0; - virtual ModuleId moduleId(Utils::SmallStringView name) = 0; + virtual ModuleId moduleId(Utils::SmallStringView name) const = 0; virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; virtual Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0; diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index 00aaa062db6..c57ce05ddfe 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -378,6 +378,41 @@ protected: return package; } + auto createBuiltinSynchronizationPackage() + { + SynchronizationPackage package; + + package.imports.emplace_back(QMLModuleId, Storage::Synchronization::Version{}, sourceId1); + package.moduleDependencies.emplace_back(QMLModuleId, + Storage::Synchronization::Version{}, + sourceId1); + package.updatedModuleDependencySourceIds.push_back(sourceId1); + + importsSourceId1.emplace_back(QMLModuleId, Storage::Synchronization::Version{}, sourceId1); + moduleDependenciesSourceId1.emplace_back(QMLModuleId, + Storage::Synchronization::Version{}, + sourceId1); + + package.types.push_back( + Storage::Synchronization::Type{"double", + Storage::Synchronization::ImportedType{}, + TypeTraits::Value, + sourceId1, + {Storage::Synchronization::ExportedType{QMLModuleId, + "double"}}}); + package.types.push_back( + Storage::Synchronization::Type{"var", + Storage::Synchronization::ImportedType{}, + TypeTraits::Value, + sourceId1, + {Storage::Synchronization::ExportedType{QMLModuleId, + "var"}}}); + + package.updatedSourceIds = {sourceId1}; + + return package; + } + auto createSynchronizationPackageWithAliases() { auto package{createSimpleSynchronizationPackage()}; @@ -983,6 +1018,7 @@ protected: ModuleId pathToModuleId{storage.moduleId("/path/to")}; ModuleId qtQuick3DModuleId{storage.moduleId("QtQuick3D")}; ModuleId myModuleModuleId{storage.moduleId("MyModule")}; + ModuleId QMLModuleId{storage.moduleId("QML")}; Storage::Synchronization::Imports importsSourceId1; Storage::Synchronization::Imports importsSourceId2; Storage::Synchronization::Imports importsSourceId3; @@ -5896,4 +5932,114 @@ TEST_F(ProjectStorage, DontGetTypeForInvalidId) ASSERT_THAT(type, Eq(Utils::nullopt)); } +TEST_F(ProjectStorage, GetCommonType) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + + auto typeId = storage.commonTypeId(); + + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QQuickItem")); +} + +TEST_F(ProjectStorage, GetCommonTypeAgain) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + auto firstTypeId = storage.commonTypeId(); + + auto typeId = storage.commonTypeId(); + + ASSERT_THAT(typeId, firstTypeId); +} + +TEST_F(ProjectStorage, GetCommonTypeAfterChangingType) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + auto oldTypeId = storage.commonTypeId(); + package.types.front().typeName = "QQuickItem2"; + storage.synchronize(package); + + auto typeId = storage.commonTypeId(); + + ASSERT_THAT(typeId, Ne(oldTypeId)); + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QQuickItem2")); +} + +TEST_F(ProjectStorage, GetBuiltinType) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "double")); +} + +TEST_F(ProjectStorage, GetBuiltinTypeAgain) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + auto firstTypeId = storage.builtinTypeId(); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, firstTypeId); +} + +TEST_F(ProjectStorage, GetBuiltinTypeAfterChangingType) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + auto oldTypeId = storage.builtinTypeId(); + package.types.front().typeName = "float"; + storage.synchronize(package); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, Ne(oldTypeId)); + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "float")); +} + +TEST_F(ProjectStorage, GetBuiltinStringType) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "var")); +} + +TEST_F(ProjectStorage, GetBuiltinStringTypeAgain) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + auto firstTypeId = storage.builtinTypeId(); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, firstTypeId); +} + +TEST_F(ProjectStorage, GetBuiltinStringTypeAfterChangingType) +{ + auto package{createBuiltinSynchronizationPackage()}; + storage.synchronize(package); + auto oldTypeId = storage.builtinTypeId(); + package.types.back().typeName = "variant"; + storage.synchronize(package); + + auto typeId = storage.builtinTypeId(); + + ASSERT_THAT(typeId, Ne(oldTypeId)); + ASSERT_THAT(typeId, fetchTypeId(sourceId1, "variant")); +} + } // namespace diff --git a/tests/unit/unittest/projectstoragemock.h b/tests/unit/unittest/projectstoragemock.h index b53ee5d23ab..4ee86f09420 100644 --- a/tests/unit/unittest/projectstoragemock.h +++ b/tests/unit/unittest/projectstoragemock.h @@ -41,7 +41,7 @@ public: (QmlDesigner::Storage::Synchronization::SynchronizationPackage package), (override)); - MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (override)); + MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (const, override)); MOCK_METHOD(QmlDesigner::FileStatus, fetchFileStatus,