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 <tim.jenssen@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Marco Bubke
2022-08-09 17:36:42 +02:00
committed by Thomas Hartmann
parent 35a773b2dc
commit c7b6d83f94
6 changed files with 275 additions and 6 deletions

View File

@@ -456,6 +456,7 @@ extend_qtc_plugin(QmlDesigner
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX designercore/projectstorage SOURCES_PREFIX designercore/projectstorage
SOURCES SOURCES
commontypecache.h
directorypathcompressor.h directorypathcompressor.h
filesysteminterface.h filesysteminterface.h
filesystem.cpp filesystem.h filesystem.cpp filesystem.h

View File

@@ -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 <tuple>
#include <type_traits>
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<const auto &moduleName_, const auto &typeName_>
struct CacheType
{
QmlDesigner::ModuleId moduleId;
QmlDesigner::TypeId typeId;
};
template<typename ProjectStorage>
class CommonTypeCache
{
using CommonTypes = std::tuple<CacheType<QtQuick, Item>, CacheType<QML, DoubleType>, CacheType<QML, var>>;
public:
CommonTypeCache(const ProjectStorage &projectStorage)
: m_projectStorage{projectStorage}
{}
void resetTypeIds()
{
std::apply([](auto &...type) { ((type.typeId = QmlDesigner::TypeId{}), ...); }, m_types);
}
template<const auto &moduleName, const auto &typeName>
auto typeId() const
{
auto &type = std::get<CacheType<moduleName, typeName>>(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<const auto &typeName>
auto builtinTypeId() const
{
return typeId<QML, typeName>();
}
template<typename Type>
auto builtinTypeId() const
{
if constexpr (std::is_same_v<Type, double>)
return builtinTypeId<DoubleType>();
else
return TypeId{};
}
private:
const ProjectStorage &m_projectStorage;
mutable CommonTypes m_types;
};
} // namespace QmlDesigner::Storage::Info

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include "commontypecache.h"
#include "projectstorageexceptions.h" #include "projectstorageexceptions.h"
#include "projectstorageinterface.h" #include "projectstorageinterface.h"
#include "sourcepathcachetypes.h" #include "sourcepathcachetypes.h"
@@ -116,15 +117,17 @@ public:
synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds); synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
commonTypeCache.resetTypeIds();
transaction.commit(); transaction.commit();
} }
ModuleId moduleId(Utils::SmallStringView moduleName) override ModuleId moduleId(Utils::SmallStringView moduleName) const override
{ {
return moduleCache.id(moduleName); return moduleCache.id(moduleName);
} }
Utils::SmallString moduleName(ModuleId moduleId) Utils::SmallString moduleName(ModuleId moduleId) const
{ {
if (!moduleId) if (!moduleId)
throw ModuleDoesNotExists{}; throw ModuleDoesNotExists{};
@@ -134,7 +137,7 @@ public:
TypeId typeId(ModuleId moduleId, TypeId typeId(ModuleId moduleId,
Utils::SmallStringView exportedTypeName, Utils::SmallStringView exportedTypeName,
Storage::Synchronization::Version version) Storage::Synchronization::Version version) const
{ {
if (version.minor) if (version.minor)
return selectTypeIdByModuleIdAndExportedNameAndVersionStatement return selectTypeIdByModuleIdAndExportedNameAndVersionStatement
@@ -208,6 +211,24 @@ public:
propertyDeclarationId); propertyDeclarationId);
} }
template<const auto &moduleName, const auto &typeName>
TypeId commonTypeId() const
{
return commonTypeCache.template typeId<moduleName, typeName>();
}
template<typename BuiltinType>
TypeId builtinTypeId() const
{
return commonTypeCache.template builtinTypeId<BuiltinType>();
}
template<const auto &builtinType>
TypeId builtinTypeId() const
{
return commonTypeCache.template builtinTypeId<builtinType>();
}
PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
Utils::SmallStringView name) Utils::SmallStringView name)
{ {
@@ -2515,7 +2536,8 @@ private:
public: public:
Database &database; Database &database;
Initializer initializer; Initializer initializer;
ModuleCache moduleCache{ModuleStorageAdapter{*this}}; mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}};
Storage::Info::CommonTypeCache<ProjectStorage<Database>> commonTypeCache{*this};
ReadWriteStatement<1, 3> upsertTypeStatement{ ReadWriteStatement<1, 3> upsertTypeStatement{
"INSERT INTO types(sourceId, name, traits) VALUES(?1, ?2, ?3) ON CONFLICT DO " "INSERT INTO types(sourceId, name, traits) VALUES(?1, ?2, ?3) ON CONFLICT DO "
"UPDATE SET traits=excluded.traits WHERE traits IS NOT " "UPDATE SET traits=excluded.traits WHERE traits IS NOT "

View File

@@ -35,7 +35,7 @@ class ProjectStorageInterface
public: public:
virtual void synchronize(Storage::Synchronization::SynchronizationPackage package) = 0; 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 FileStatus fetchFileStatus(SourceId sourceId) const = 0;
virtual Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0; virtual Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0;

View File

@@ -378,6 +378,41 @@ protected:
return package; 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 createSynchronizationPackageWithAliases()
{ {
auto package{createSimpleSynchronizationPackage()}; auto package{createSimpleSynchronizationPackage()};
@@ -983,6 +1018,7 @@ protected:
ModuleId pathToModuleId{storage.moduleId("/path/to")}; ModuleId pathToModuleId{storage.moduleId("/path/to")};
ModuleId qtQuick3DModuleId{storage.moduleId("QtQuick3D")}; ModuleId qtQuick3DModuleId{storage.moduleId("QtQuick3D")};
ModuleId myModuleModuleId{storage.moduleId("MyModule")}; ModuleId myModuleModuleId{storage.moduleId("MyModule")};
ModuleId QMLModuleId{storage.moduleId("QML")};
Storage::Synchronization::Imports importsSourceId1; Storage::Synchronization::Imports importsSourceId1;
Storage::Synchronization::Imports importsSourceId2; Storage::Synchronization::Imports importsSourceId2;
Storage::Synchronization::Imports importsSourceId3; Storage::Synchronization::Imports importsSourceId3;
@@ -5896,4 +5932,114 @@ TEST_F(ProjectStorage, DontGetTypeForInvalidId)
ASSERT_THAT(type, Eq(Utils::nullopt)); ASSERT_THAT(type, Eq(Utils::nullopt));
} }
TEST_F(ProjectStorage, GetCommonType)
{
auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package);
auto typeId = storage.commonTypeId<QmlDesigner::Storage::Info::QtQuick,
QmlDesigner::Storage::Info::Item>();
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QQuickItem"));
}
TEST_F(ProjectStorage, GetCommonTypeAgain)
{
auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package);
auto firstTypeId = storage.commonTypeId<QmlDesigner::Storage::Info::QtQuick,
QmlDesigner::Storage::Info::Item>();
auto typeId = storage.commonTypeId<QmlDesigner::Storage::Info::QtQuick,
QmlDesigner::Storage::Info::Item>();
ASSERT_THAT(typeId, firstTypeId);
}
TEST_F(ProjectStorage, GetCommonTypeAfterChangingType)
{
auto package{createSimpleSynchronizationPackage()};
storage.synchronize(package);
auto oldTypeId = storage.commonTypeId<QmlDesigner::Storage::Info::QtQuick,
QmlDesigner::Storage::Info::Item>();
package.types.front().typeName = "QQuickItem2";
storage.synchronize(package);
auto typeId = storage.commonTypeId<QmlDesigner::Storage::Info::QtQuick,
QmlDesigner::Storage::Info::Item>();
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<double>();
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "double"));
}
TEST_F(ProjectStorage, GetBuiltinTypeAgain)
{
auto package{createBuiltinSynchronizationPackage()};
storage.synchronize(package);
auto firstTypeId = storage.builtinTypeId<double>();
auto typeId = storage.builtinTypeId<double>();
ASSERT_THAT(typeId, firstTypeId);
}
TEST_F(ProjectStorage, GetBuiltinTypeAfterChangingType)
{
auto package{createBuiltinSynchronizationPackage()};
storage.synchronize(package);
auto oldTypeId = storage.builtinTypeId<double>();
package.types.front().typeName = "float";
storage.synchronize(package);
auto typeId = storage.builtinTypeId<double>();
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<QmlDesigner::Storage::Info::var>();
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "var"));
}
TEST_F(ProjectStorage, GetBuiltinStringTypeAgain)
{
auto package{createBuiltinSynchronizationPackage()};
storage.synchronize(package);
auto firstTypeId = storage.builtinTypeId<QmlDesigner::Storage::Info::var>();
auto typeId = storage.builtinTypeId<QmlDesigner::Storage::Info::var>();
ASSERT_THAT(typeId, firstTypeId);
}
TEST_F(ProjectStorage, GetBuiltinStringTypeAfterChangingType)
{
auto package{createBuiltinSynchronizationPackage()};
storage.synchronize(package);
auto oldTypeId = storage.builtinTypeId<QmlDesigner::Storage::Info::var>();
package.types.back().typeName = "variant";
storage.synchronize(package);
auto typeId = storage.builtinTypeId<QmlDesigner::Storage::Info::var>();
ASSERT_THAT(typeId, Ne(oldTypeId));
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "variant"));
}
} // namespace } // namespace

View File

@@ -41,7 +41,7 @@ public:
(QmlDesigner::Storage::Synchronization::SynchronizationPackage package), (QmlDesigner::Storage::Synchronization::SynchronizationPackage package),
(override)); (override));
MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (override)); MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (const, override));
MOCK_METHOD(QmlDesigner::FileStatus, MOCK_METHOD(QmlDesigner::FileStatus,
fetchFileStatus, fetchFileStatus,