diff options
Diffstat (limited to 'src/plugins/qmldesigner/designercore')
69 files changed, 9599 insertions, 4526 deletions
diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp new file mode 100644 index 0000000000..da40c4d387 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp @@ -0,0 +1,291 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "generatedcomponentutils.h" +#include <qmldesignerconstants.h> + +namespace QmlDesigner { + +bool couldBeProjectModule(const Utils::FilePath &path, const QString &projectName) +{ + if (!path.exists()) + return false; + + Utils::FilePath qmlDirPath = path.pathAppended("qmldir"); + if (qmlDirPath.exists()) { + Utils::expected_str<QByteArray> qmldirContents = qmlDirPath.fileContents(); + if (!qmldirContents.has_value()) + return false; + + const QString expectedLine = QLatin1String("module %1").arg(projectName); + QByteArray fileContents = *qmldirContents; + QTextStream stream(fileContents); + while (!stream.atEnd()) { + QString lineData = stream.readLine().trimmed(); + if (lineData.startsWith(u"module ")) + return lineData == expectedLine; + } + } + if (path.endsWith(projectName)) + return true; + + return false; +} + +GeneratedComponentUtils::GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies) + : m_externalDependencies(externalDependencies) +{ +} + +Utils::FilePath GeneratedComponentUtils::generatedComponentsPath() const +{ + Utils::FilePath projectPath = Utils::FilePath::fromString(m_externalDependencies.currentProjectDirPath()); + if (projectPath.isEmpty()) + return {}; + + Utils::FilePath assetImportsPath = projectPath.resolvePath(QLatin1String(Constants::OLD_ASSET_IMPORT_FOLDER)); + if (assetImportsPath.exists()) + return assetImportsPath; + + Utils::FilePath componentsPath = projectPath.resolvePath(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER)); + if (!componentsPath.exists()) + componentsPath.createDir(); + + return componentsPath; +} + +Utils::FilePath GeneratedComponentUtils::composedEffectsBasePath() const +{ + Utils::FilePath basePath = generatedComponentsPath(); + if (basePath.isEmpty()) + return {}; + + QString effectsImportPath; + if (basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER)) + effectsImportPath = Constants::OLD_EFFECTS_FOLDER; + else + effectsImportPath = Constants::COMPOSED_EFFECTS_TYPE; + + return basePath.resolvePath(effectsImportPath); +} + +Utils::FilePath GeneratedComponentUtils::composedEffectPath(const QString &effectPath) const +{ + Utils::FilePath effectsBasePath = composedEffectsBasePath(); + + QString effectName = Utils::FilePath::fromString(effectPath).baseName(); + + return effectsBasePath.resolvePath(effectName + "/" + effectName + ".qml"); +} + +Utils::FilePath GeneratedComponentUtils::componentBundlesBasePath() const +{ + Utils::FilePath basePath = generatedComponentsPath(); + + if (basePath.isEmpty()) + return {}; + + if (basePath.endsWith(Constants::GENERATED_COMPONENTS_FOLDER)) + return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_TYPE)); + + return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_TYPE)); +} + +Utils::FilePath GeneratedComponentUtils::import3dBasePath() const +{ + Utils::FilePath basePath = generatedComponentsPath(); + + if (basePath.isEmpty()) + return {}; + + Utils::FilePath import3dPath; + if (basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER)) + return basePath.resolvePath(QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER)); + + return basePath.resolvePath(QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER)); +} + +Utils::FilePath GeneratedComponentUtils::materialBundlePath() const +{ + Utils::FilePath basePath = componentBundlesBasePath(); + + if (basePath.isEmpty()) + return {}; + + if (basePath.endsWith(Constants::OLD_COMPONENT_BUNDLES_TYPE)) + return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE)); + + return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE)); +} + +Utils::FilePath GeneratedComponentUtils::effectBundlePath() const +{ + Utils::FilePath basePath = componentBundlesBasePath(); + + if (basePath.isEmpty()) + return {}; + + if (basePath.endsWith(Constants::OLD_COMPONENT_BUNDLES_TYPE)) + return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE)); + + return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE)); +} + +Utils::FilePath GeneratedComponentUtils::projectModulePath(bool generateIfNotExists) const +{ + using Utils::FilePath; + FilePath projectPath = FilePath::fromString(m_externalDependencies.currentProjectDirPath()); + + if (projectPath.isEmpty()) + return {}; + + const QString projectName = m_externalDependencies.projectName(); + + FilePath newImportDirectory = projectPath.pathAppended(projectName); + if (couldBeProjectModule(newImportDirectory, projectName)) + return newImportDirectory; + + FilePath oldImportDirectory = projectPath.resolvePath(QLatin1String("imports/") + projectName); + if (couldBeProjectModule(oldImportDirectory, projectName)) + return oldImportDirectory; + + for (const QString &path : m_externalDependencies.projectModulePaths()) { + FilePath dir = FilePath::fromString(path); + if (couldBeProjectModule(dir, projectName)) + return dir; + } + + if (generateIfNotExists) + newImportDirectory.createDir(); + + return newImportDirectory; +} + +bool GeneratedComponentUtils::isImport3dPath(const QString &path) const +{ + return path.contains('/' + QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER)) + || path.contains(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER) + '/' + + QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER)); +} + +bool GeneratedComponentUtils::isComposedEffectPath(const QString &path) const +{ + return path.contains(Constants::OLD_EFFECTS_IMPORT_FOLDER) + || path.contains(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER) + '/' + + QLatin1String(Constants::COMPOSED_EFFECTS_TYPE)); +} + +bool GeneratedComponentUtils::isBundlePath(const QString &path) const +{ + return path.contains(componentBundlesTypePrefix().replace('.', '/')); +} + +bool GeneratedComponentUtils::isGeneratedPath(const QString &path) const +{ + return path.startsWith(generatedComponentsPath().toFSPathString()); +} + + +QString GeneratedComponentUtils::generatedComponentTypePrefix() const +{ + Utils::FilePath basePath = generatedComponentsPath(); + if (basePath.isEmpty() || basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER)) + return {}; + + return Constants::GENERATED_COMPONENTS_FOLDER; +} + +QString GeneratedComponentUtils::import3dTypePrefix() const +{ + QString basePrefix = generatedComponentTypePrefix(); + + if (basePrefix == Constants::GENERATED_COMPONENTS_FOLDER) + return basePrefix + '.' + QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER); + + return Constants::OLD_QUICK_3D_ASSETS_FOLDER; +} + +QString GeneratedComponentUtils::import3dTypePath() const +{ + QString prefix = import3dTypePrefix(); + prefix.replace('.', '/'); + return prefix; +} + +QString GeneratedComponentUtils::componentBundlesTypePrefix() const +{ + QString basePrefix = generatedComponentTypePrefix(); + + if (basePrefix.endsWith(Constants::GENERATED_COMPONENTS_FOLDER)) + return basePrefix + '.' + QLatin1String(Constants::COMPONENT_BUNDLES_TYPE); + + return Constants::OLD_COMPONENT_BUNDLES_TYPE; +} + +QString GeneratedComponentUtils::composedEffectsTypePrefix() const +{ + QString basePrefix = generatedComponentTypePrefix(); + + if (basePrefix == Constants::GENERATED_COMPONENTS_FOLDER) + return basePrefix + '.' + QLatin1String(Constants::COMPOSED_EFFECTS_TYPE); + + return Constants::OLD_EFFECTS_FOLDER; +} + +QString GeneratedComponentUtils::materialsBundleId() const +{ + bool isNewImportDir = generatedComponentTypePrefix().endsWith(Constants::GENERATED_COMPONENTS_FOLDER); + + return QLatin1String(isNewImportDir ? Constants::COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE + : Constants::OLD_COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE); +} + +QString GeneratedComponentUtils::effectsBundleId() const +{ + bool isNewImportDir = generatedComponentTypePrefix().endsWith(Constants::GENERATED_COMPONENTS_FOLDER); + + return QLatin1String(isNewImportDir ? Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE + : Constants::OLD_COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE); +} + +QString GeneratedComponentUtils::userMaterialsBundleId() const +{ + return QLatin1String(Constants::COMPONENT_BUNDLES_USER_MATERIAL_BUNDLE_TYPE); +} + +QString GeneratedComponentUtils::userEffectsBundleId() const +{ + return QLatin1String(Constants::COMPONENT_BUNDLES_USER_EFFECT_BUNDLE_TYPE); +} + +QString GeneratedComponentUtils::user3DBundleId() const +{ + return QLatin1String(Constants::COMPONENT_BUNDLES_USER_3D_BUNDLE_TYPE); +} + +QString GeneratedComponentUtils::materialsBundleType() const +{ + return componentBundlesTypePrefix() + '.' + materialsBundleId(); +} + +QString GeneratedComponentUtils::effectsBundleType() const +{ + return componentBundlesTypePrefix() + '.' + effectsBundleId(); +} + +QString GeneratedComponentUtils::userMaterialsBundleType() const +{ + return componentBundlesTypePrefix() + '.' + userMaterialsBundleId(); +} + +QString GeneratedComponentUtils::userEffectsBundleType() const +{ + return componentBundlesTypePrefix() + '.' + userEffectsBundleId(); +} + +QString GeneratedComponentUtils::user3DBundleType() const +{ + return componentBundlesTypePrefix() + '.' + user3DBundleId(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.h b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h new file mode 100644 index 0000000000..ceddb405a3 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h @@ -0,0 +1,55 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include <externaldependenciesinterface.h> +#include <qmldesignercorelib_exports.h> + +#include <utils/filepath.h> + +#include <QString> + +namespace QmlDesigner { + +class QMLDESIGNERCORE_EXPORT GeneratedComponentUtils { +public: + GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies); + + Utils::FilePath generatedComponentsPath() const; + Utils::FilePath composedEffectsBasePath() const; + Utils::FilePath composedEffectPath(const QString &effectPath) const; + Utils::FilePath componentBundlesBasePath() const; + Utils::FilePath import3dBasePath() const; + Utils::FilePath materialBundlePath() const; + Utils::FilePath effectBundlePath() const; + Utils::FilePath projectModulePath(bool generateIfNotExists = false) const; + + bool isImport3dPath(const QString &path) const; + bool isComposedEffectPath(const QString &path) const; + bool isBundlePath(const QString &path) const; + bool isGeneratedPath(const QString &path) const; + + QString generatedComponentTypePrefix() const; + QString import3dTypePrefix() const; + QString import3dTypePath() const; + QString componentBundlesTypePrefix() const; + QString composedEffectsTypePrefix() const; + + QString materialsBundleId() const; + QString effectsBundleId() const; + QString userMaterialsBundleId() const; + QString userEffectsBundleId() const; + QString user3DBundleId() const; + + QString materialsBundleType() const; + QString effectsBundleType() const; + QString userMaterialsBundleType() const; + QString userEffectsBundleType() const; + QString user3DBundleType() const; + +private: + ExternalDependenciesInterface &m_externalDependencies; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 955e676d3b..97148e664f 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -76,8 +76,10 @@ void ImageCacheCollector::start(Utils::SmallStringView name, AbortCallback abortCallback, ImageCache::TraceToken traceToken) { +#ifdef QDS_USE_PROJECTSTORAGE if (!m_projectStorage || !m_pathCache) return; +#endif using namespace NanotraceHR::Literals; auto [collectorTraceToken, flowtoken] = traceToken.beginDurationWithFlow( diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h index c2a912cc3a..fec68c2894 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h @@ -64,8 +64,10 @@ private: QSize captureImageMaximumSize; ExternalDependenciesInterface &m_externalDependencies; ImageCacheCollectorNullImageHandling nullImageHandling{}; +#ifdef QDS_USE_PROJECTSTORAGE ProjectStorageType *m_projectStorage = nullptr; PathCacheType *m_pathCache = nullptr; +#endif }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h b/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h index fac7e7d9bf..dc5ed3de23 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h +++ b/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h @@ -31,7 +31,7 @@ public: { std::unique_lock lock{m_mutex}; - ensureThreadIsRunning(std::move(traceToken)); + ensureThreadIsRunning(lock, std::move(traceToken)); m_tasks.emplace_back(std::forward<Arguments>(arguments)...); } @@ -54,6 +54,15 @@ public: clearTasks(oldTasks); } + void putThreadToSleep() + { + { + std::unique_lock lock{m_mutex}; + m_sleeping = true; + } + m_condition.notify_all(); + } + private: void destroy() { @@ -66,19 +75,20 @@ private: { using namespace std::literals::chrono_literals; std::unique_lock lock{m_mutex}; - if (m_finishing) + + if (m_finishing || m_sleeping) return {std::move(lock), true}; + if (m_tasks.empty()) { auto timedOutWithoutEntriesOrFinishing = !m_condition.wait_for(lock, 10min, [&] { - return m_tasks.size() || m_finishing; + return m_tasks.size() || m_finishing || m_sleeping; }); - if (timedOutWithoutEntriesOrFinishing || m_finishing) { + if (timedOutWithoutEntriesOrFinishing) m_sleeping = true; - return {std::move(lock), true}; - } } - return {std::move(lock), false}; + + return {std::move(lock), m_finishing || m_sleeping}; } [[nodiscard]] std::optional<Task> getTask(std::unique_lock<std::mutex> lock) @@ -94,29 +104,38 @@ private: return {std::move(task)}; } - template<typename TraceToken> - void ensureThreadIsRunning(TraceToken traceToken) + template<typename Lock, typename TraceToken> + void ensureThreadIsRunning(Lock &lock, TraceToken traceToken) { using namespace NanotraceHR::Literals; if (m_finishing || !m_sleeping) return; + if (m_sleeping) { + lock.unlock(); + joinThread(); + lock.lock(); + + m_sleeping = false; + } + if (m_backgroundThread.joinable()) return; - m_sleeping = false; - auto [threadCreateToken, flowToken] = traceToken.beginDurationWithFlow( "thread is created in the task queue"_t); m_backgroundThread = std::thread{[this](auto traceToken) { auto duration = traceToken.beginDuration( "thread is ready"_t); + while (true) { auto [lock, abort] = waitForTasks(); duration.end(); + if (abort) return; + auto getTaskToken = duration.beginDuration( "get task from queue"_t); if (auto task = getTask(std::move(lock)); task) { diff --git a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h index 71ddeb7dc1..9055f51b6a 100644 --- a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h +++ b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h @@ -28,6 +28,7 @@ public: virtual QString qmlPuppetFallbackDirectory() const = 0; virtual QString defaultPuppetToplevelBuildDirectory() const = 0; virtual QUrl projectUrl() const = 0; + virtual QString projectName() const = 0; virtual QString currentProjectDirPath() const = 0; virtual QUrl currentResourcePath() const = 0; virtual void parseItemLibraryDescriptions() = 0; diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h b/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h index f88f9e35c6..2d0f2ef31e 100644 --- a/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h +++ b/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h @@ -42,13 +42,16 @@ class QMLDESIGNERCORE_EXPORT ItemLibraryEntry public: ItemLibraryEntry(); - explicit ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry, - const ProjectStorageType &projectStorage); - ~ItemLibraryEntry() = default; + ItemLibraryEntry(const ItemLibraryEntry &) = default; + ItemLibraryEntry &operator=(const ItemLibraryEntry &) = default; + ItemLibraryEntry(ItemLibraryEntry &&) = default; + ItemLibraryEntry &operator=(ItemLibraryEntry &&) = default; + explicit ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry); + ~ItemLibraryEntry(); QString name() const; TypeName typeName() const; - const NodeMetaInfo &metaInfo() const; + TypeId typeId() const; QIcon typeIcon() const; QString libraryEntryIconPath() const; int majorVersion() const; @@ -86,7 +89,7 @@ private: using ItemLibraryEntries = QList<ItemLibraryEntry>; QMLDESIGNERCORE_EXPORT QList<ItemLibraryEntry> toItemLibraryEntries( - const Storage::Info::ItemLibraryEntries &entries, const ProjectStorageType &projectStorage); + const Storage::Info::ItemLibraryEntries &entries); } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index b907e6c5d8..39b5cdaa81 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -137,7 +137,7 @@ public: ModelPointer createModel(const TypeName &typeName, std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {}); - QUrl fileUrl() const; + const QUrl &fileUrl() const; SourceId fileUrlSourceId() const; void setFileUrl(const QUrl &url); @@ -147,7 +147,7 @@ public: void setMetaInfo(const MetaInfo &metaInfo); #endif - Module module(Utils::SmallStringView moduleName); + Module module(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind); NodeMetaInfo metaInfo(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const; NodeMetaInfo metaInfo(Module module, Utils::SmallStringView typeName, @@ -166,6 +166,7 @@ public: NodeMetaInfo qtQmlConnectionsMetaInfo() const; NodeMetaInfo qtQmlModelsListModelMetaInfo() const; NodeMetaInfo qtQmlModelsListElementMetaInfo() const; + NodeMetaInfo qtQmlXmlListModelXmlListModelRoleMetaInfo() const; NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const; NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const; NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const; @@ -218,14 +219,17 @@ public: // Imports: const Imports &imports() const; - const Imports &possibleImports() const; - const Imports &usedImports() const; + Imports possibleImports() const; + Imports usedImports() const; void changeImports(Imports importsToBeAdded, Imports importsToBeRemoved); +#ifndef QDS_USE_PROJECTSTORAGE void setPossibleImports(Imports possibleImports); +#endif +#ifndef QDS_USE_PROJECTSTORAGE void setUsedImports(Imports usedImports); +#endif bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const; bool isImportPossible(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const; - QString pathForImport(const Import &import); QStringList importPaths() const; Import highestPossibleImport(const QString &importPath); @@ -251,10 +255,7 @@ public: bool hasId(const QString &id) const; bool hasImport(const QString &importUrl) const; - QString generateNewId(const QString &prefixName, - const QString &fallbackPrefix = "element", - std::optional<std::function<bool(const QString &)>> isDuplicate = {}) const; - QString generateIdFromName(const QString &name, const QString &fallbackId = "element") const; + QString generateNewId(const QString &prefixName, const QString &fallbackPrefix = "element") const; void startDrag(QMimeData *mimeData, const QPixmap &icon); void endDrag(); diff --git a/src/plugins/qmldesigner/designercore/include/modelfwd.h b/src/plugins/qmldesigner/designercore/include/modelfwd.h index 0a062289fd..91c533fe7b 100644 --- a/src/plugins/qmldesigner/designercore/include/modelfwd.h +++ b/src/plugins/qmldesigner/designercore/include/modelfwd.h @@ -77,7 +77,7 @@ constexpr bool useProjectStorage() using ProjectStorageType = ProjectStorageInterface; using PathCacheType = SourcePathCacheInterface; #else -using ProjectStorageType = ProjectStorage<Sqlite::Database>; +using ProjectStorageType = ProjectStorage; using PathCacheType = SourcePathCache<ProjectStorageType, NonLockingMutex>; #endif diff --git a/src/plugins/qmldesigner/designercore/include/nodehints.h b/src/plugins/qmldesigner/designercore/include/nodehints.h index 9e67c2d99b..99470db65f 100644 --- a/src/plugins/qmldesigner/designercore/include/nodehints.h +++ b/src/plugins/qmldesigner/designercore/include/nodehints.h @@ -3,9 +3,11 @@ #pragma once +#include "modelnode.h" +#include "nodemetainfo.h" + #include <QList> #include <QString> -#include "modelnode.h" #include "qmldesignercorelib_global.h" #include "invalidmetainfoexception.h" @@ -54,18 +56,19 @@ public: QHash<QString, QString> hints() const; static NodeHints fromModelNode(const ModelNode &modelNode); - static NodeHints fromItemLibraryEntry(const ItemLibraryEntry &entry); + static NodeHints fromItemLibraryEntry(const ItemLibraryEntry &entry, Model *model); private: explicit NodeHints(const ModelNode &modelNode); explicit NodeHints(const NodeMetaInfo &metaInfo); - explicit NodeHints(const ItemLibraryEntry &entry); + explicit NodeHints(const ItemLibraryEntry &entry, Model *model); const ModelNode &modelNode() const; bool isValid() const; Model *model() const; bool evaluateBooleanExpression(const QString &hintName, bool defaultValue, const ModelNode potentialParent = ModelNode()) const; ModelNode m_modelNode; + NodeMetaInfo m_metaInfo; QHash<QString, QString> m_hints; }; diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h index 53c755ddc8..fd3f2f9be8 100644 --- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h @@ -27,9 +27,15 @@ QT_END_NAMESPACE # define DEPRECATED_VERSION_NUMBER \ [[deprecated( \ "In most cases you don't need them anymore because the import is setting them!")]] +# define DEPRECATED_COMPONENT_FILE_NAME [[deprecated("Use sourceId() instead.")]] +# define DEPRECATED_IMPORT_DIRECTORY_PATH [[deprecated("Use allExportedTypeNames().")]] +# define DEPRECATED_REQUIRED_IMPORT_STRING [[deprecated("Use allExportedTypeNames().")]] #else # define DEPRECATED_TYPENAME # define DEPRECATED_VERSION_NUMBER +# define DEPRECATED_COMPONENT_FILE_NAME +# define DEPRECATED_IMPORT_DIRECTORY_PATH +# define DEPRECATED_REQUIRED_IMPORT_STRING #endif namespace QmlDesigner { @@ -116,7 +122,7 @@ public: Storage::Info::ItemLibraryEntries itemLibrariesEntries() const; SourceId sourceId() const; - QString componentFileName() const; + DEPRECATED_COMPONENT_FILE_NAME QString componentFileName() const; bool isBasedOn(const NodeMetaInfo &metaInfo) const; bool isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const; @@ -167,6 +173,7 @@ public: bool isQtMultimediaSoundEffect() const; bool isQtObject() const; bool isQtQmlConnections() const; + bool isQtQmlModelsListElement() const; bool isQtQuick3DBakedLightmap() const; bool isQtQuick3DBuffer() const; bool isQtQuick3DCamera() const; @@ -176,9 +183,9 @@ public: bool isQtQuick3DInstanceList() const; bool isQtQuick3DInstanceListEntry() const; bool isQtQuick3DLight() const; - bool isQtQuickListElement() const; bool isQtQuickListModel() const; bool isQtQuickListView() const; + bool isQtQuickGridView() const; bool isQtQuick3DMaterial() const; bool isQtQuick3DModel() const; bool isQtQuick3DNode() const; @@ -235,8 +242,8 @@ public: bool usesCustomParser() const; bool isEnumeration() const; - QString importDirectoryPath() const; - QString requiredImportString() const; + DEPRECATED_IMPORT_DIRECTORY_PATH QString importDirectoryPath() const; + DEPRECATED_REQUIRED_IMPORT_STRING QString requiredImportString() const; friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second) { @@ -265,12 +272,14 @@ public: private: const Storage::Info::Type &typeData() const; + PropertyDeclarationId defaultPropertyDeclarationId() const; bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const; private: TypeId m_typeId; NotNullPointer<const ProjectStorageType> m_projectStorage = {}; mutable std::optional<Storage::Info::Type> m_typeData; + mutable std::optional<PropertyDeclarationId> m_defaultPropertyId; std::shared_ptr<NodeMetaInfoPrivate> m_privateData; }; diff --git a/src/plugins/qmldesigner/designercore/include/projectstorageids.h b/src/plugins/qmldesigner/designercore/include/projectstorageids.h index bc66e0d2b2..7c2e8c4b25 100644 --- a/src/plugins/qmldesigner/designercore/include/projectstorageids.h +++ b/src/plugins/qmldesigner/designercore/include/projectstorageids.h @@ -7,6 +7,8 @@ #include <utils/span.h> +#include <QVarLengthArray> + namespace QmlDesigner { enum class BasicIdType { @@ -29,6 +31,8 @@ enum class BasicIdType { using TypeId = Sqlite::BasicId<BasicIdType::Type>; using TypeIds = std::vector<TypeId>; +template<std::size_t size> +using SmallTypeIds = QVarLengthArray<TypeId, size>; using PropertyDeclarationId = Sqlite::BasicId<BasicIdType::PropertyDeclaration>; using PropertyDeclarationIds = std::vector<PropertyDeclarationId>; @@ -44,9 +48,13 @@ using EnumerationDeclarationIds = std::vector<EnumerationDeclarationId>; using SourceContextId = Sqlite::BasicId<BasicIdType::SourceContext, int>; using SourceContextIds = std::vector<SourceContextId>; +template<std::size_t size> +using SmallSourceContextIds = QVarLengthArray<SourceContextId, size>; using SourceId = Sqlite::BasicId<BasicIdType::Source, int>; using SourceIds = std::vector<SourceId>; +template<std::size_t size> +using SmallSourceIds = QVarLengthArray<SourceId, size>; using ModuleId = Sqlite::BasicId<BasicIdType::Module, int>; using ModuleIds = std::vector<ModuleId>; diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h index dde5515a5a..e11f201cdb 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h @@ -174,6 +174,7 @@ public: ModelNode targetTransition() const; void assignTargetFlowItem(const QmlFlowTargetNode &flowItem); QmlFlowItemNode flowItemParent() const; +private: void destroyTarget(); }; diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index 23841accda..92c79c7863 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -8,11 +8,11 @@ #include "documentmessage.h" #include "rewritertransaction.h" -#include <QScopedPointer> #include <QTimer> #include <QUrl> #include <functional> +#include <memory> namespace QmlJS { class Document; @@ -123,7 +123,10 @@ public: bool renameId(const QString& oldId, const QString& newId); const QmlJS::Document *document() const; + +#ifndef QDS_USE_PROJECTSTORAGE const QmlJS::ScopeChain *scopeChain() const; +#endif QString convertTypeToImportAlias(const QString &type) const; @@ -135,8 +138,6 @@ public: void setCheckLinkErrors(bool b) { m_checkLinkErrors = b; } - QString pathForImport(const Import &import); - QStringList importDirectories() const; QSet<QPair<QString, QString> > qrcMapping() const; @@ -202,9 +203,9 @@ private: //variables bool m_checkLinkErrors = true; DifferenceHandling m_differenceHandling; - QScopedPointer<Internal::ModelNodePositionStorage> m_positionStorage; - QScopedPointer<Internal::ModelToTextMerger> m_modelToTextMerger; - QScopedPointer<Internal::TextToModelMerger> m_textToModelMerger; + std::unique_ptr<Internal::ModelNodePositionStorage> m_positionStorage; + std::unique_ptr<Internal::ModelToTextMerger> m_modelToTextMerger; + std::unique_ptr<Internal::TextToModelMerger> m_textToModelMerger; QList<DocumentMessage> m_errors; QList<DocumentMessage> m_warnings; RewriterTransaction m_removeDefaultPropertyTransaction; diff --git a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h index 7fa2348854..a42164d1bd 100644 --- a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h +++ b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h @@ -7,6 +7,7 @@ # include "qmldesignercorelib_global.h" +# include <generatedcomponentutils.h> # include <import.h> # include <QObject> @@ -62,6 +63,7 @@ private: // variables QDir m_filePathDir; QPointer<Model> m_model; ExternalDependenciesInterface &m_externalDependencies; + GeneratedComponentUtils m_componentUtils; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 33a100f7b2..484f18e42b 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -64,6 +64,8 @@ #include <qmlitemnode.h> #include <rewriterview.h> +#include <projectstorage/projectstorage.h> + #include <utils/hdrimage.h> #include <coreplugin/messagemanager.h> @@ -89,7 +91,6 @@ #include <QMultiHash> #include <QPainter> #include <QPicture> -#include <QScopedPointer> #include <QTimerEvent> #include <QUrl> @@ -205,22 +206,17 @@ NodeInstanceView::~NodeInstanceView() static bool isSkippedRootNode(const ModelNode &node) { - static const PropertyNameList skipList({"Qt.ListModel", "QtQuick.ListModel", "Qt.ListModel", "QtQuick.ListModel"}); - - if (skipList.contains(node.type())) - return true; - - return false; + return node.metaInfo().isQtQuickListModel(); } static bool isSkippedNode(const ModelNode &node) { - static const PropertyNameList skipList({"QtQuick.XmlRole", "Qt.XmlRole", "QtQuick.ListElement", "Qt.ListElement"}); + auto model = node.model(); - if (skipList.contains(node.type())) - return true; + auto listElement = model->qtQmlModelsListElementMetaInfo(); + auto xmlRole = model->qtQmlXmlListModelXmlListModelRoleMetaInfo(); - return false; + return node.metaInfo().isBasedOn(listElement, xmlRole); } static bool parentTakesOverRendering(const ModelNode &modelNode) @@ -644,7 +640,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node, TypeName(), key.type}; m_nodeInstanceServer->changeAuxiliaryValues({{container}}); - }; + } break; case AuxiliaryDataType::NodeInstanceAuxiliary: @@ -656,7 +652,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node, TypeName(), key.type}; m_nodeInstanceServer->changeAuxiliaryValues({{container}}); - }; + } break; case AuxiliaryDataType::NodeInstancePropertyOverwrite: @@ -991,6 +987,8 @@ QRectF NodeInstanceView::sceneRect() const return {}; } +namespace { + QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList) { QList<ModelNode> filteredNodeList; @@ -1003,14 +1001,12 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList) return filteredNodeList; } -namespace { bool shouldSendAuxiliary(const AuxiliaryDataKey &key) { return key.type == AuxiliaryDataType::NodeInstancePropertyOverwrite || key.type == AuxiliaryDataType::NodeInstanceAuxiliary || key == invisibleProperty || key == lockedProperty; } -} // namespace bool parentIsBehavior(ModelNode node) { @@ -1024,6 +1020,43 @@ bool parentIsBehavior(ModelNode node) return false; } +TypeName createQualifiedTypeName(const ModelNode &node) +{ + if (!node) + return {}; + +#ifdef QDS_USE_PROJECTSTORAGE + auto model = node.model(); + auto exportedTypes = node.metaInfo().exportedTypeNamesForSourceId(model->fileUrlSourceId()); + if (exportedTypes.size()) { + const auto &exportedType = exportedTypes.front(); + using Storage::ModuleKind; + auto module = model->projectStorage()->module(exportedType.moduleId); + Utils::PathString typeName; + switch (module.kind) { + case ModuleKind::QmlLibrary: + typeName += module.name; + typeName += '/'; + break; + case ModuleKind::PathLibrary: + break; + case ModuleKind::CppLibrary: + break; + } + + typeName += exportedType.name; + + return typeName.toQByteArray(); + } + + return {}; +#else + return node.type(); +#endif +} + +} // namespace + CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList<ModelNode> nodeList = allModelNodes(); @@ -1079,8 +1112,9 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() nodeFlags |= InstanceContainer::ParentTakesOverRendering; const auto modelNode = instance.modelNode(); + InstanceContainer container(instance.instanceId(), - modelNode.type(), + createQualifiedTypeName(modelNode), modelNode.majorVersion(), modelNode.minorVersion(), ModelUtils::componentFilePath(modelNode), @@ -1182,6 +1216,13 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isQtQuickState()) stateInstanceId = stateNode.internalId(); + QHash<QString, QVariantMap> sceneStates = m_edit3DToolStates[model()->fileUrl()]; + QHash<QString, QVariantMap> projectStates = m_edit3DToolStates[ + QUrl::fromLocalFile(m_externalDependencies.currentProjectDirPath())]; + const QString ptsId = "@PTS"; + if (projectStates.contains(ptsId)) + sceneStates.insert(ptsId, projectStates[ptsId]); + return CreateSceneCommand(instanceContainerList, reparentContainerList, idContainerList, @@ -1192,7 +1233,7 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() mockupTypesVector, model()->fileUrl(), m_externalDependencies.currentResourcePath(), - m_edit3DToolStates[model()->fileUrl()], + sceneStates, lastUsedLanguage, m_captureImageMinimumSize, m_captureImageMaximumSize, @@ -1243,7 +1284,7 @@ CreateInstancesCommand NodeInstanceView::createCreateInstancesCommand(const QLis const auto modelNode = instance.modelNode(); InstanceContainer container(instance.instanceId(), - modelNode.type(), + createQualifiedTypeName(modelNode), modelNode.majorVersion(), modelNode.minorVersion(), ModelUtils::componentFilePath(modelNode), @@ -1710,7 +1751,12 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand auto data = qvariant_cast<QVariantList>(command.data()); if (data.size() == 3) { QString qmlId = data[0].toString(); - m_edit3DToolStates[model()->fileUrl()][qmlId].insert(data[1].toString(), data[2]); + QUrl mainKey; + if (qmlId == "@PTS") // Project tool state + mainKey = QUrl::fromLocalFile(m_externalDependencies.currentProjectDirPath()); + else + mainKey = model()->fileUrl(); + m_edit3DToolStates[mainKey][qmlId].insert(data[1].toString(), data[2]); } } } else if (command.type() == PuppetToCreatorCommand::Render3DView) { @@ -1824,7 +1870,7 @@ QVariant NodeInstanceView::modelNodePreviewImageDataToVariant(const ModelNodePre placeHolder = {150, 150}; // Placeholder has transparency, but we don't want to show the checkerboard, so // paint in the correct background color - placeHolder.fill(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal)); + placeHolder.fill(Utils::creatorColor(Utils::Theme::BackgroundColorNormal)); QPainter painter(&placeHolder); painter.drawPixmap(0, 0, 150, 150, placeHolderSrc); } @@ -1850,7 +1896,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo ModelNodePreviewImageData imageData; imageData.id = modelNode.id(); - imageData.type = QString::fromLatin1(modelNode.type()); + imageData.type = QString::fromUtf8(createQualifiedTypeName(modelNode)); const double ratio = m_externalDependencies.formEditorDevicePixelRatio(); if (imageSource.isEmpty() && modelNode.metaInfo().isQtQuick3DTexture()) { @@ -1923,7 +1969,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo imageData.pixmap = originalPixmap.scaled(dim, dim, Qt::KeepAspectRatio); imageData.pixmap.setDevicePixelRatio(ratio); imageData.time = modified; - imageData.info = ImageUtils::imageInfo(imageSource); + imageData.info = ImageUtils::imageInfoString(imageSource); m_imageDataMap.insert(imageData.id, imageData); } } @@ -1958,7 +2004,7 @@ QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &model if (m_imageDataMap.contains(id)) { imageData = m_imageDataMap[id]; } else { - imageData.type = QString::fromLatin1(modelNode.type()); + imageData.type = QString::fromLatin1(createQualifiedTypeName(modelNode)); imageData.id = id; m_imageDataMap.insert(id, imageData); } diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp index 806da7e7c4..2aec766002 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp @@ -22,7 +22,7 @@ class ItemLibraryEntryData public: QString name; TypeName typeName; - NodeMetaInfo metaInfo; + TypeId typeId; QString category; int majorVersion{-1}; int minorVersion{-1}; @@ -64,12 +64,12 @@ ItemLibraryEntry::ItemLibraryEntry() : m_data(std::make_shared<Internal::ItemLibraryEntryData>()) {} -ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry, - const ProjectStorageType &projectStorage) +ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry) : ItemLibraryEntry{} { m_data->name = entry.name.toQString(); - m_data->metaInfo = {entry.typeId, &projectStorage}; + m_data->typeId = entry.typeId; + m_data->typeName = entry.typeName.toQByteArray(); m_data->category = entry.category.toQString(); if (entry.iconPath.size()) m_data->libraryEntryIconPath = entry.iconPath.toQString(); @@ -87,6 +87,8 @@ ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry, m_data->extraFilePaths.emplace_back(extraFilePath.toQString()); } +ItemLibraryEntry::~ItemLibraryEntry() = default; + QString ItemLibraryEntry::name() const { return m_data->name; @@ -97,9 +99,9 @@ TypeName ItemLibraryEntry::typeName() const return m_data->typeName; } -const NodeMetaInfo &ItemLibraryEntry::metaInfo() const +TypeId ItemLibraryEntry::typeId() const { - return m_data->metaInfo; + return m_data->typeId; } QString ItemLibraryEntry::qmlSource() const @@ -245,6 +247,7 @@ QDataStream &operator<<(QDataStream &stream, const ItemLibraryEntry &itemLibrary stream << itemLibraryEntry.m_data->qmlSource; stream << itemLibraryEntry.m_data->customComponentSource; stream << itemLibraryEntry.m_data->extraFilePaths; + stream << itemLibraryEntry.m_data->typeId.internalId(); return stream; } @@ -270,6 +273,9 @@ QDataStream &operator>>(QDataStream &stream, ItemLibraryEntry &itemLibraryEntry) stream >> itemLibraryEntry.m_data->qmlSource; stream >> itemLibraryEntry.m_data->customComponentSource; stream >> itemLibraryEntry.m_data->extraFilePaths; + TypeId::DatabaseType internalTypeId; + stream >> internalTypeId; + itemLibraryEntry.m_data->typeId = TypeId::create(internalTypeId); return stream; } @@ -295,11 +301,10 @@ QDebug operator<<(QDebug debug, const ItemLibraryEntry &itemLibraryEntry) return debug.space(); } -QList<ItemLibraryEntry> toItemLibraryEntries(const Storage::Info::ItemLibraryEntries &entries, - const ProjectStorageType &projectStorage) +QList<ItemLibraryEntry> toItemLibraryEntries(const Storage::Info::ItemLibraryEntries &entries) { return Utils::transform<QList<ItemLibraryEntry>>(entries, [&](const auto &entry) { - return ItemLibraryEntry{entry, projectStorage}; + return ItemLibraryEntry{entry}; }); } diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp index af61ef6573..0addc6884d 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp @@ -272,7 +272,7 @@ inline QString deEscape(const QString &value) inline QVariant deEscapeVariant(const QVariant &value) { - if (value.typeId() == QVariant::String) + if (value.typeId() == QMetaType::QString) return deEscape(value.toString()); return value; } diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp index 32e68a3cdc..1f9a3e42bd 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp @@ -106,14 +106,15 @@ QmlDesigner::NodeHints::NodeHints(const ModelNode &node) } NodeHints::NodeHints(const NodeMetaInfo &metaInfo) + : m_metaInfo{metaInfo} { for (const auto &[name, expression] : metaInfo.typeHints()) m_hints.insert(name.toQString(), expression.toQString()); } -NodeHints::NodeHints(const ItemLibraryEntry &entry) +NodeHints::NodeHints(const ItemLibraryEntry &entry, [[maybe_unused]] Model *model) #ifdef QDS_USE_PROJECTSTORAGE - : NodeHints{entry.metaInfo()} + : NodeHints{NodeMetaInfo{entry.typeId(), model->projectStorage()}} #endif { if constexpr (!useProjectStorage()) @@ -135,7 +136,7 @@ bool NodeHints::canBeContainerFor(const ModelNode &potenialChild) const if (!isValid()) return true; - auto flagIs = m_modelNode.metaInfo().canBeContainer(); + auto flagIs = m_metaInfo.canBeContainer(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -151,7 +152,7 @@ bool NodeHints::forceClip() const if (isSwipeView(modelNode())) return true; - auto flagIs = m_modelNode.metaInfo().forceClip(); + auto flagIs = m_metaInfo.forceClip(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -167,7 +168,7 @@ bool NodeHints::doesLayoutChildren() const if (isSwipeView(modelNode())) return true; - auto flagIs = m_modelNode.metaInfo().doesLayoutChildren(); + auto flagIs = m_metaInfo.doesLayoutChildren(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -177,7 +178,7 @@ bool NodeHints::doesLayoutChildren() const bool NodeHints::canBeDroppedInFormEditor() const { - auto flagIs = m_modelNode.metaInfo().canBeDroppedInFormEditor(); + auto flagIs = m_metaInfo.canBeDroppedInFormEditor(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -187,7 +188,7 @@ bool NodeHints::canBeDroppedInFormEditor() const bool NodeHints::canBeDroppedInNavigator() const { - auto flagIs = m_modelNode.metaInfo().canBeDroppedInNavigator(); + auto flagIs = m_metaInfo.canBeDroppedInNavigator(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -197,7 +198,7 @@ bool NodeHints::canBeDroppedInNavigator() const bool NodeHints::canBeDroppedInView3D() const { - auto flagIs = m_modelNode.metaInfo().canBeDroppedInView3D(); + auto flagIs = m_metaInfo.canBeDroppedInView3D(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -210,7 +211,7 @@ bool NodeHints::isMovable() const if (!isValid()) return true; - auto flagIs = m_modelNode.metaInfo().isMovable(); + auto flagIs = m_metaInfo.isMovable(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -223,7 +224,7 @@ bool NodeHints::isResizable() const if (!isValid()) return true; - auto flagIs = m_modelNode.metaInfo().isResizable(); + auto flagIs = m_metaInfo.isResizable(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -236,7 +237,7 @@ bool NodeHints::hasFormEditorItem() const if (!isValid()) return true; - auto flagIs = m_modelNode.metaInfo().hasFormEditorItem(); + auto flagIs = m_metaInfo.hasFormEditorItem(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -252,7 +253,7 @@ bool NodeHints::isStackedContainer() const if (isSwipeView(modelNode())) return true; - auto flagIs = m_modelNode.metaInfo().isStackedContainer(); + auto flagIs = m_metaInfo.isStackedContainer(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -299,7 +300,7 @@ bool NodeHints::takesOverRenderingOfChildren() const if (!isValid()) return false; - auto flagIs = m_modelNode.metaInfo().takesOverRenderingOfChildren(); + auto flagIs = m_metaInfo.takesOverRenderingOfChildren(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -312,7 +313,7 @@ bool NodeHints::visibleInNavigator() const if (!isValid()) return false; - auto flagIs = m_modelNode.metaInfo().visibleInNavigator(); + auto flagIs = m_metaInfo.visibleInNavigator(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -322,7 +323,7 @@ bool NodeHints::visibleInNavigator() const bool NodeHints::visibleInLibrary() const { - auto flagIs = m_modelNode.metaInfo().visibleInLibrary(); + auto flagIs = m_metaInfo.visibleInLibrary(); if (flagIs != FlagIs::Set) return convert(flagIs); @@ -391,9 +392,9 @@ NodeHints NodeHints::fromModelNode(const ModelNode &modelNode) return NodeHints(modelNode); } -NodeHints NodeHints::fromItemLibraryEntry(const ItemLibraryEntry &entry) +NodeHints NodeHints::fromItemLibraryEntry(const ItemLibraryEntry &entry, Model *model) { - return NodeHints(entry); + return NodeHints(entry, model); } const ModelNode &NodeHints::modelNode() const diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp index 85f904666c..c656634272 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp @@ -53,6 +53,10 @@ NodeMetaInfo object will result in an InvalidMetaInfoException being thrown. namespace { +using Storage::ModuleKind; + +auto category = MetaInfoTracing::category; + struct TypeDescription { QString className; @@ -919,8 +923,11 @@ const ObjectValue *NodeMetaInfoPrivate::getObjectValue() const ContextPtr NodeMetaInfoPrivate::context() const { +#ifndef QDS_USE_PROJECTSTORAGE if (m_model && m_model->rewriterView() && m_model->rewriterView()->scopeChain()) return m_model->rewriterView()->scopeChain()->context(); +#endif + return ContextPtr(nullptr); } @@ -1490,15 +1497,20 @@ MetaInfoType NodeMetaInfo::type() const { if constexpr (useProjectStorage()) { if (isValid()) { - switch (typeData().traits.kind) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type"_t, category(), keyValue("type id", m_typeId)}; + auto kind = typeData().traits.kind; + tracer.end(keyValue("type kind", kind)); + + switch (kind) { case Storage::TypeTraitsKind::Reference: return MetaInfoType::Reference; case Storage::TypeTraitsKind::Value: return MetaInfoType::Value; case Storage::TypeTraitsKind::Sequence: return MetaInfoType::Sequence; - default: - break; + case Storage::TypeTraitsKind::None: + return MetaInfoType::None; } } } @@ -1508,16 +1520,38 @@ MetaInfoType NodeMetaInfo::type() const bool NodeMetaInfo::isFileComponent() const { - if constexpr (useProjectStorage()) - return isValid() && typeData().traits.isFileComponent; - else + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is file component"_t, category(), keyValue("type id", m_typeId)}; + + auto isFileComponent = typeData().traits.isFileComponent; + + tracer.end(keyValue("is file component", isFileComponent)); + + return isFileComponent; + + } else { return isValid() && m_privateData->isFileComponent(); + } } bool NodeMetaInfo::isProjectComponent() const { if constexpr (useProjectStorage()) { - return isValid() && typeData().traits.isProjectComponent; + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is project component"_t, category(), keyValue("type id", m_typeId)}; + + auto isProjectComponent = typeData().traits.isProjectComponent; + + tracer.end(keyValue("is project component", isProjectComponent)); + + return isProjectComponent; } return false; @@ -1526,7 +1560,17 @@ bool NodeMetaInfo::isProjectComponent() const bool NodeMetaInfo::isInProjectModule() const { if constexpr (useProjectStorage()) { - return isValid() && typeData().traits.isInProjectModule; + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is project module"_t, category(), keyValue("type id", m_typeId)}; + + auto isInProjectModule = typeData().traits.isInProjectModule; + + tracer.end(keyValue("is project module", isInProjectModule)); + + return isInProjectModule; } return false; @@ -1535,10 +1579,17 @@ bool NodeMetaInfo::isInProjectModule() const FlagIs NodeMetaInfo::canBeContainer() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.canBeContainer; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"can be container"_t, category(), keyValue("type id", m_typeId)}; + + auto canBeContainer = typeData().traits.canBeContainer; - return FlagIs::False; + tracer.end(keyValue("can be container", canBeContainer)); + + return canBeContainer; } return FlagIs::Set; @@ -1547,10 +1598,17 @@ FlagIs NodeMetaInfo::canBeContainer() const FlagIs NodeMetaInfo::forceClip() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.forceClip; + if (!isValid()) + return FlagIs::False; - return FlagIs::False; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"force clip"_t, category(), keyValue("type id", m_typeId)}; + + auto forceClip = typeData().traits.forceClip; + + tracer.end(keyValue("force clip", forceClip)); + + return forceClip; } return FlagIs::Set; @@ -1559,10 +1617,17 @@ FlagIs NodeMetaInfo::forceClip() const FlagIs NodeMetaInfo::doesLayoutChildren() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.doesLayoutChildren; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"does layout children"_t, category(), keyValue("type id", m_typeId)}; - return FlagIs::False; + auto doesLayoutChildren = typeData().traits.doesLayoutChildren; + + tracer.end(keyValue("does layout children", doesLayoutChildren)); + + return doesLayoutChildren; } return FlagIs::Set; @@ -1571,10 +1636,19 @@ FlagIs NodeMetaInfo::doesLayoutChildren() const FlagIs NodeMetaInfo::canBeDroppedInFormEditor() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.canBeDroppedInFormEditor; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"can be dropped in form editor"_t, + category(), + keyValue("type id", m_typeId)}; - return FlagIs::False; + auto canBeDroppedInFormEditor = typeData().traits.canBeDroppedInFormEditor; + + tracer.end(keyValue("can be dropped in form editor", canBeDroppedInFormEditor)); + + return canBeDroppedInFormEditor; } return FlagIs::Set; @@ -1583,10 +1657,19 @@ FlagIs NodeMetaInfo::canBeDroppedInFormEditor() const FlagIs NodeMetaInfo::canBeDroppedInNavigator() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.canBeDroppedInNavigator; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"can be dropped in navigator"_t, + category(), + keyValue("type id", m_typeId)}; + + auto canBeDroppedInNavigator = typeData().traits.canBeDroppedInNavigator; - return FlagIs::False; + tracer.end(keyValue("can be dropped in navigator", canBeDroppedInNavigator)); + + return canBeDroppedInNavigator; } return FlagIs::Set; @@ -1595,10 +1678,19 @@ FlagIs NodeMetaInfo::canBeDroppedInNavigator() const FlagIs NodeMetaInfo::canBeDroppedInView3D() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.canBeDroppedInView3D; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"can be dropped in view3d"_t, + category(), + keyValue("type id", m_typeId)}; + + auto canBeDroppedInView3D = typeData().traits.canBeDroppedInView3D; + + tracer.end(keyValue("can be dropped in view3d", canBeDroppedInView3D)); - return FlagIs::False; + return canBeDroppedInView3D; } return FlagIs::Set; @@ -1607,10 +1699,17 @@ FlagIs NodeMetaInfo::canBeDroppedInView3D() const FlagIs NodeMetaInfo::isMovable() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.isMovable; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is movable"_t, category(), keyValue("type id", m_typeId)}; - return FlagIs::False; + auto isMovable = typeData().traits.isMovable; + + tracer.end(keyValue("is movable", isMovable)); + + return isMovable; } return FlagIs::Set; @@ -1619,10 +1718,17 @@ FlagIs NodeMetaInfo::isMovable() const FlagIs NodeMetaInfo::isResizable() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.isResizable; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is resizable"_t, category(), keyValue("type id", m_typeId)}; + + auto isResizable = typeData().traits.isResizable; - return FlagIs::False; + tracer.end(keyValue("is resizable", isResizable)); + + return isResizable; } return FlagIs::Set; @@ -1631,10 +1737,17 @@ FlagIs NodeMetaInfo::isResizable() const FlagIs NodeMetaInfo::hasFormEditorItem() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.hasFormEditorItem; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"has form editor item"_t, category(), keyValue("type id", m_typeId)}; + + auto hasFormEditorItem = typeData().traits.hasFormEditorItem; - return FlagIs::False; + tracer.end(keyValue("has form editor item", hasFormEditorItem)); + + return hasFormEditorItem; } return FlagIs::Set; @@ -1643,10 +1756,17 @@ FlagIs NodeMetaInfo::hasFormEditorItem() const FlagIs NodeMetaInfo::isStackedContainer() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.isStackedContainer; + if (!isValid()) + return FlagIs::False; - return FlagIs::False; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is stacked container"_t, category(), keyValue("type id", m_typeId)}; + + auto isStackedContainer = typeData().traits.isStackedContainer; + + tracer.end(keyValue("is stacked container", isStackedContainer)); + + return isStackedContainer; } return FlagIs::Set; @@ -1655,10 +1775,19 @@ FlagIs NodeMetaInfo::isStackedContainer() const FlagIs NodeMetaInfo::takesOverRenderingOfChildren() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.takesOverRenderingOfChildren; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"takes over rendering of children"_t, + category(), + keyValue("type id", m_typeId)}; - return FlagIs::False; + auto takesOverRenderingOfChildren = typeData().traits.takesOverRenderingOfChildren; + + tracer.end(keyValue("takes over rendering of children", takesOverRenderingOfChildren)); + + return takesOverRenderingOfChildren; } return FlagIs::Set; @@ -1667,10 +1796,17 @@ FlagIs NodeMetaInfo::takesOverRenderingOfChildren() const FlagIs NodeMetaInfo::visibleInNavigator() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.visibleInNavigator; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"visible in navigator"_t, category(), keyValue("type id", m_typeId)}; + + auto visibleInNavigator = typeData().traits.visibleInNavigator; - return FlagIs::False; + tracer.end(keyValue("visible in navigator", visibleInNavigator)); + + return visibleInNavigator; } return FlagIs::Set; @@ -1679,10 +1815,17 @@ FlagIs NodeMetaInfo::visibleInNavigator() const FlagIs NodeMetaInfo::visibleInLibrary() const { if constexpr (useProjectStorage()) { - if (isValid()) - return typeData().traits.visibleInLibrary; + if (!isValid()) + return FlagIs::False; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"visible in library"_t, category(), keyValue("type id", m_typeId)}; + + auto visibleInLibrary = typeData().traits.visibleInLibrary; - return FlagIs::False; + tracer.end(keyValue("visible in library", visibleInLibrary)); + + return visibleInLibrary; } return FlagIs::Set; @@ -1694,6 +1837,12 @@ namespace { TypeId typeId, Utils::SmallStringView propertyName) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get combound property id"_t, + category(), + keyValue("type id", typeId), + keyValue("property name", propertyName)}; + auto begin = propertyName.begin(); const auto end = propertyName.end(); @@ -1709,11 +1858,17 @@ namespace { if (propertyId && found != end) { begin = std::next(found); - return projectStorage.propertyDeclarationId(propertyTypeId, {begin, end}); + auto id = projectStorage.propertyDeclarationId(propertyTypeId, {begin, end}); + + tracer.end(keyValue("property id", id)); + + return id; } } } + tracer.end(keyValue("property id", propertyId)); + return propertyId; } @@ -1721,10 +1876,24 @@ namespace { bool NodeMetaInfo::hasProperty(Utils::SmallStringView propertyName) const { - if constexpr (useProjectStorage()) - return isValid() && bool(propertyId(*m_projectStorage, m_typeId, propertyName)); - else + if constexpr (useProjectStorage()) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"has property"_t, + category(), + keyValue("type id", m_typeId), + keyValue("property name", propertyName)}; + + if (!isValid()) + return false; + + auto hasPropertyId = bool(propertyId(*m_projectStorage, m_typeId, propertyName)); + + tracer.end(keyValue("has property", hasPropertyId)); + + return hasPropertyId; + } else { return isValid() && m_privateData->properties().contains(QByteArrayView(propertyName)); + } } PropertyMetaInfos NodeMetaInfo::properties() const @@ -1733,12 +1902,14 @@ PropertyMetaInfos NodeMetaInfo::properties() const return {}; if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<PropertyMetaInfos>( - m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) { - return PropertyMetaInfo{id, m_projectStorage}; - }); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get properties"_t, category(), keyValue("type id", m_typeId)}; + + return Utils::transform<PropertyMetaInfos>( + m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) { + return PropertyMetaInfo{id, m_projectStorage}; + }); + } else { const auto &properties = m_privateData->properties(); @@ -1750,19 +1921,22 @@ PropertyMetaInfos NodeMetaInfo::properties() const return propertyMetaInfos; } - - return {}; } PropertyMetaInfos NodeMetaInfo::localProperties() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<PropertyMetaInfos>( - m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) { - return PropertyMetaInfo{id, m_projectStorage}; - }); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get local properties"_t, category(), keyValue("type id", m_typeId)}; + + return Utils::transform<PropertyMetaInfos>( + m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) { + return PropertyMetaInfo{id, m_projectStorage}; + }); + } else { const auto &properties = m_privateData->localProperties(); @@ -1774,71 +1948,82 @@ PropertyMetaInfos NodeMetaInfo::localProperties() const return propertyMetaInfos; } - - return {}; } PropertyMetaInfo NodeMetaInfo::property(const PropertyName &propertyName) const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) - return {propertyId(*m_projectStorage, m_typeId, propertyName), m_projectStorage}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property"_t, + category(), + keyValue("type id", m_typeId), + keyValue("property name", propertyName)}; + + return {propertyId(*m_projectStorage, m_typeId, propertyName), m_projectStorage}; } else { if (hasProperty(propertyName)) { return PropertyMetaInfo{m_privateData, propertyName}; } + return {}; } - - return {}; } PropertyNameList NodeMetaInfo::signalNames() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<PropertyNameList>(m_projectStorage->signalDeclarationNames( - m_typeId), - [&](const auto &name) { - return name.toQByteArray(); - }); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get signal names"_t, category(), keyValue("type id", m_typeId)}; + + return Utils::transform<PropertyNameList>(m_projectStorage->signalDeclarationNames(m_typeId), + [&](const auto &name) { + return name.toQByteArray(); + }); + } else { - if (isValid()) - return m_privateData->signalNames(); + return m_privateData->signalNames(); } - - return {}; } PropertyNameList NodeMetaInfo::slotNames() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<PropertyNameList>(m_projectStorage->functionDeclarationNames( - m_typeId), - [&](const auto &name) { - return name.toQByteArray(); - }); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get slot names"_t, category(), keyValue("type id", m_typeId)}; + return Utils::transform<PropertyNameList>(m_projectStorage->functionDeclarationNames(m_typeId), + [&](const auto &name) { + return name.toQByteArray(); + }); } else { - if (isValid()) - return m_privateData->slotNames(); + return m_privateData->slotNames(); } - - return {}; } PropertyName NodeMetaInfo::defaultPropertyName() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - if (auto name = m_projectStorage->propertyName(typeData().defaultPropertyId)) { - return name->toQByteArray(); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get default property name"_t, + category(), + keyValue("type id", m_typeId)}; + if (auto name = m_projectStorage->propertyName(defaultPropertyDeclarationId())) { + tracer.end(keyValue("default property name", name)); + return name->toQByteArray(); } + } else { - if (isValid()) - return m_privateData->defaultPropertyName(); + return m_privateData->defaultPropertyName(); } return {}; @@ -1846,88 +2031,128 @@ PropertyName NodeMetaInfo::defaultPropertyName() const PropertyMetaInfo NodeMetaInfo::defaultProperty() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return PropertyMetaInfo(typeData().defaultPropertyId, m_projectStorage); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get default property"_t, category(), keyValue("type id", m_typeId)}; + + auto id = defaultPropertyDeclarationId(); + + tracer.end(keyValue("default property id", id)); + + return PropertyMetaInfo(id, m_projectStorage); } else { return property(defaultPropertyName()); } - - return {}; } bool NodeMetaInfo::hasDefaultProperty() const { - if constexpr (useProjectStorage()) - return isValid() && bool(typeData().defaultPropertyId); - else + if (!isValid()) + return false; + + if constexpr (useProjectStorage()) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"has default property"_t, category(), keyValue("type id", m_typeId)}; + auto hasDefaultProperty = bool(defaultPropertyDeclarationId()); + tracer.end(keyValue("has default property", hasDefaultProperty)); + + return hasDefaultProperty; + } else { return !defaultPropertyName().isEmpty(); + } } std::vector<NodeMetaInfo> NodeMetaInfo::selfAndPrototypes() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<NodeMetaInfos>( - m_projectStorage->prototypeAndSelfIds(m_typeId), [&](TypeId typeId) { - return NodeMetaInfo{typeId, m_projectStorage}; - }); - } - } else { - if (isValid()) { - NodeMetaInfos hierarchy = {*this}; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get self and prototypes"_t, + category(), + keyValue("type id", m_typeId)}; - return hierarchy; + return Utils::transform<NodeMetaInfos>(m_projectStorage->prototypeAndSelfIds(m_typeId), + [&](TypeId typeId) { + return NodeMetaInfo{typeId, m_projectStorage}; + }); + } else { + NodeMetaInfos hierarchy = {*this}; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } - } - return {}; + return hierarchy; + } } NodeMetaInfos NodeMetaInfo::prototypes() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform<NodeMetaInfos>( - m_projectStorage->prototypeIds(m_typeId), [&](TypeId typeId) { - return NodeMetaInfo{typeId, m_projectStorage}; - }); - } - } else { - if (isValid()) { - NodeMetaInfos hierarchy; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)}; + return Utils::transform<NodeMetaInfos>(m_projectStorage->prototypeIds(m_typeId), + [&](TypeId typeId) { + return NodeMetaInfo{typeId, m_projectStorage}; + }); - return hierarchy; + } else { + NodeMetaInfos hierarchy; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } + + return hierarchy; } +} - return {}; +namespace { +template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary> +bool isBasedOnCommonType(NotNullPointer<const ProjectStorageType> projectStorage, TypeId typeId) +{ + if (!typeId) + return false; + + auto base = projectStorage->commonTypeId<moduleName, typeName, moduleKind>(); + + return projectStorage->isBasedOn(typeId, base); } +} // namespace bool NodeMetaInfo::defaultPropertyIsComponent() const { - if (hasDefaultProperty()) - return defaultProperty().propertyType().isQmlComponent(); + if (!isValid()) + return false; - return false; + if (useProjectStorage()) { + auto id = defaultPropertyDeclarationId(); + auto propertyDeclaration = m_projectStorage->propertyDeclaration(id); + + using namespace Storage::Info; + return isBasedOnCommonType<QML, Component>(m_projectStorage, propertyDeclaration->typeId); + } else { + if (hasDefaultProperty()) + return defaultProperty().propertyType().isQmlComponent(); + return false; + } } TypeName NodeMetaInfo::displayName() const @@ -1973,10 +2198,16 @@ int NodeMetaInfo::minorVersion() const Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return m_projectStorage->exportedTypeNames(m_typeId); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get all exported type names"_t, + category(), + keyValue("type id", m_typeId)}; + + return m_projectStorage->exportedTypeNames(m_typeId); } return {}; @@ -1984,10 +2215,17 @@ Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const Storage::Info::ExportedTypeNames NodeMetaInfo::exportedTypeNamesForSourceId(SourceId sourceId) const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return m_projectStorage->exportedTypeNames(m_typeId, sourceId); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get exported type names for source id"_t, + category(), + keyValue("type id", m_typeId), + keyValue("source id", sourceId)}; + + return m_projectStorage->exportedTypeNames(m_typeId, sourceId); } return {}; @@ -1995,9 +2233,18 @@ Storage::Info::ExportedTypeNames NodeMetaInfo::exportedTypeNamesForSourceId(Sour Storage::Info::TypeHints NodeMetaInfo::typeHints() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) - return m_projectStorage->typeHints(m_typeId); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type hints"_t, category(), keyValue("type id", m_typeId)}; + + auto hints = m_projectStorage->typeHints(m_typeId); + + tracer.end(keyValue("type hints", hints)); + + return hints; } return {}; @@ -2005,9 +2252,18 @@ Storage::Info::TypeHints NodeMetaInfo::typeHints() const Utils::PathString NodeMetaInfo::iconPath() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) - return m_projectStorage->typeIconPath(m_typeId); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get icon path"_t, category(), keyValue("type id", m_typeId)}; + + auto iconPath = m_projectStorage->typeIconPath(m_typeId); + + tracer.end(keyValue("icon path", iconPath)); + + return iconPath; } return {}; @@ -2015,9 +2271,20 @@ Utils::PathString NodeMetaInfo::iconPath() const Storage::Info::ItemLibraryEntries NodeMetaInfo::itemLibrariesEntries() const { + if (!isValid()) + return {}; + if constexpr (useProjectStorage()) { - if (isValid()) - return m_projectStorage->itemLibraryEntries(m_typeId); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries"_t, + category(), + keyValue("type id", m_typeId)}; + + auto entries = m_projectStorage->itemLibraryEntries(m_typeId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; } return {}; @@ -2025,10 +2292,18 @@ Storage::Info::ItemLibraryEntries NodeMetaInfo::itemLibrariesEntries() const SourceId NodeMetaInfo::sourceId() const { + if (!isValid()) + return SourceId{}; + if constexpr (useProjectStorage()) { - if (isValid()) { - return typeData().sourceId; - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get source id"_t, category(), keyValue("type id", m_typeId)}; + + auto id = typeData().sourceId; + + tracer.end(keyValue("source id", id)); + + return id; } return SourceId{}; @@ -2061,18 +2336,31 @@ QString NodeMetaInfo::requiredImportString() const if (!isValid()) return {}; - Import imp = m_privateData->requiredImport(); - if (!imp.isEmpty()) - return imp.toImportString(); + if constexpr (!useProjectStorage()) { + Import imp = m_privateData->requiredImport(); + if (!imp.isEmpty()) + return imp.toImportString(); + } return {}; } SourceId NodeMetaInfo::propertyEditorPathId() const { + if (!isValid()) + return SourceId{}; + if (useProjectStorage()) { - if (isValid()) - return m_projectStorage->propertyEditorPathId(m_typeId); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property editor path id"_t, + category(), + keyValue("type id", m_typeId)}; + + auto id = m_projectStorage->propertyEditorPathId(m_typeId); + + tracer.end(keyValue("property editor path id", id)); + + return id; } return SourceId{}; @@ -2086,6 +2374,14 @@ const Storage::Info::Type &NodeMetaInfo::typeData() const return *m_typeData; } +PropertyDeclarationId NodeMetaInfo::defaultPropertyDeclarationId() const +{ + if (!m_defaultPropertyId) + m_defaultPropertyId.emplace(m_projectStorage->defaultPropertyDeclarationId(m_typeId)); + + return *m_defaultPropertyId; +} + bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const { if (!isValid()) { @@ -2122,9 +2418,13 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino bool NodeMetaInfo::isSuitableForMouseAreaFill() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is suitable for mouse area fill"_t, + category(), + keyValue("type id", m_typeId)}; using namespace Storage::Info; auto itemId = m_projectStorage->commonTypeId<QtQuick, Item>(); @@ -2132,11 +2432,16 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const auto controlsControlId = m_projectStorage->commonTypeId<QtQuick_Controls, Control>(); auto templatesControlId = m_projectStorage->commonTypeId<QtQuick_Templates, Control>(); - return m_projectStorage->isBasedOn(m_typeId, - itemId, - mouseAreaId, - controlsControlId, - templatesControlId); + auto isSuitableForMouseAreaFill = m_projectStorage->isBasedOn(m_typeId, + itemId, + mouseAreaId, + controlsControlId, + templatesControlId); + + tracer.end(keyValue("is suitable for mouse area fill", isSuitableForMouseAreaFill)); + + return isSuitableForMouseAreaFill; + } else { return isSubclassOf("QtQuick.Item") && !isSubclassOf("QtQuick.MouseArea") && !isSubclassOf("QtQuick.Controls.Control") @@ -2147,6 +2452,15 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + category(), + keyValue("type id", m_typeId), + keyValue("meta info type id", metaInfo.m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId); } else { if (!isValid()) @@ -2160,6 +2474,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId); } else { if (!isValid()) @@ -2178,6 +2498,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo3) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId, @@ -2202,6 +2528,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo4) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId, @@ -2229,6 +2561,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo5) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId, @@ -2261,6 +2599,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo6) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId, @@ -2298,6 +2642,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo7) const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId, @@ -2330,26 +2680,14 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, } } -namespace { -template<const char *moduleName, const char *typeName> -bool isBasedOnCommonType(NotNullPointer<const ProjectStorageType> projectStorage, TypeId typeId) -{ - if (!typeId) { - return false; - } - - auto base = projectStorage->commonTypeId<moduleName, typeName>(); - - return projectStorage->isBasedOn(typeId, base); -} -} // namespace - bool NodeMetaInfo::isGraphicalItem() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is graphical item"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto itemId = m_projectStorage->commonTypeId<QtQuick, Item>(); @@ -2369,6 +2707,12 @@ bool NodeMetaInfo::isGraphicalItem() const bool NodeMetaInfo::isQtObject() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt object"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QML, QtObject>(m_projectStorage, m_typeId); } else { @@ -2379,6 +2723,14 @@ bool NodeMetaInfo::isQtObject() const bool NodeMetaInfo::isQtQmlConnections() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt Qml connections"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQml, Connections>(m_projectStorage, m_typeId); } else { @@ -2389,9 +2741,11 @@ bool NodeMetaInfo::isQtQmlConnections() const bool NodeMetaInfo::isLayoutable() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is layoutable"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto positionerId = m_projectStorage->commonTypeId<QtQuick, Positioner>(); @@ -2410,6 +2764,14 @@ bool NodeMetaInfo::isLayoutable() const bool NodeMetaInfo::isQtQuickLayoutsLayout() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Layouts.Layout"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Layouts, Layout>(m_projectStorage, m_typeId); } else { @@ -2420,9 +2782,11 @@ bool NodeMetaInfo::isQtQuickLayoutsLayout() const bool NodeMetaInfo::isView() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is view"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto listViewId = m_projectStorage->commonTypeId<QtQuick, ListView>(); @@ -2439,17 +2803,20 @@ bool NodeMetaInfo::isView() const bool NodeMetaInfo::usesCustomParser() const { if constexpr (useProjectStorage()) { - return isValid() && typeData().traits.usesCustomParser; + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)}; + + return typeData().traits.usesCustomParser; } else { if (!isValid()) return false; - auto type = typeName(); - return type == "QtQuick.VisualItemModel" || type == "Qt.VisualItemModel" - || type == "QtQuick.VisualDataModel" || type == "Qt.VisualDataModel" - || type == "QtQuick.ListModel" || type == "Qt.ListModel" - || type == "QtQml.Models.ListModel" || type == "QtQuick.XmlListModel" - || type == "Qt.XmlListModel" || type == "QtQml.XmlListModel.XmlListModel"; + auto type = simplifiedTypeName(); + return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel" + || type == "XmlListModel"; } } @@ -2468,8 +2835,14 @@ bool isTypeId(TypeId typeId, TypeIds... otherTypeIds) bool NodeMetaInfo::isVector2D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is vector2d"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector2d>()); + return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector2d>()); } else { if (!m_privateData) return false; @@ -2483,8 +2856,14 @@ bool NodeMetaInfo::isVector2D() const bool NodeMetaInfo::isVector3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is vector3d"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector3d>()); + return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector3d>()); } else { if (!m_privateData) return false; @@ -2498,8 +2877,14 @@ bool NodeMetaInfo::isVector3D() const bool NodeMetaInfo::isVector4D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is vector4d"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector4d>()); + return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector4d>()); } else { if (!m_privateData) return false; @@ -2513,6 +2898,14 @@ bool NodeMetaInfo::isVector4D() const bool NodeMetaInfo::isQtQuickPropertyChanges() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.PropertyChanges"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Storage::Info::PropertyChanges>(m_projectStorage, m_typeId); @@ -2524,6 +2917,14 @@ bool NodeMetaInfo::isQtQuickPropertyChanges() const bool NodeMetaInfo::isQtSafeRendererSafeRendererPicture() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt.SafeRenderer.SafeRendererPicture"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<Qt_SafeRenderer, SafeRendererPicture>(m_projectStorage, m_typeId); } else { @@ -2534,6 +2935,14 @@ bool NodeMetaInfo::isQtSafeRendererSafeRendererPicture() const bool NodeMetaInfo::isQtSafeRendererSafePicture() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt.SafeRenderer.SafePicture"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<Qt_SafeRenderer, SafePicture>(m_projectStorage, m_typeId); } else { @@ -2544,6 +2953,14 @@ bool NodeMetaInfo::isQtSafeRendererSafePicture() const bool NodeMetaInfo::isQtQuickTimelineKeyframe() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Timeline.Keyframe"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Timeline, Keyframe>(m_projectStorage, m_typeId); @@ -2555,6 +2972,14 @@ bool NodeMetaInfo::isQtQuickTimelineKeyframe() const bool NodeMetaInfo::isQtQuickTimelineTimelineAnimation() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Timeline.TimelineAnimation"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Timeline, TimelineAnimation>(m_projectStorage, m_typeId); } else { @@ -2565,6 +2990,14 @@ bool NodeMetaInfo::isQtQuickTimelineTimelineAnimation() const bool NodeMetaInfo::isQtQuickTimelineTimeline() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Timeline.Timeline"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Timeline, Timeline>(m_projectStorage, m_typeId); } else { @@ -2575,6 +3008,14 @@ bool NodeMetaInfo::isQtQuickTimelineTimeline() const bool NodeMetaInfo::isQtQuickTimelineKeyframeGroup() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Timeline.KeyframeGroup"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Timeline, KeyframeGroup>(m_projectStorage, m_typeId); } else { @@ -2585,9 +3026,11 @@ bool NodeMetaInfo::isQtQuickTimelineKeyframeGroup() const bool NodeMetaInfo::isListOrGridView() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is list or grid view"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto listViewId = m_projectStorage->commonTypeId<QtQuick, ListView>(); @@ -2601,9 +3044,11 @@ bool NodeMetaInfo::isListOrGridView() const bool NodeMetaInfo::isNumber() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is number"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto intId = m_projectStorage->builtinTypeId<int>(); @@ -2624,6 +3069,14 @@ bool NodeMetaInfo::isNumber() const bool NodeMetaInfo::isQtQuickExtrasPicture() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Extras.Picture"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Extras, Picture>(m_projectStorage, m_typeId); } else { @@ -2634,6 +3087,12 @@ bool NodeMetaInfo::isQtQuickExtrasPicture() const bool NodeMetaInfo::isQtQuickImage() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Image"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Image>(m_projectStorage, m_typeId); @@ -2645,6 +3104,14 @@ bool NodeMetaInfo::isQtQuickImage() const bool NodeMetaInfo::isQtQuickBorderImage() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.BorderImage"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, BorderImage>(m_projectStorage, m_typeId); @@ -2656,7 +3123,13 @@ bool NodeMetaInfo::isQtQuickBorderImage() const bool NodeMetaInfo::isAlias() const { if constexpr (useProjectStorage()) { - return false; // there is no type alias + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is alias"_t, category(), keyValue("type id", m_typeId)}; + + return false; // all types are already resolved } else { return isValid() && m_privateData->qualfiedTypeName() == "alias"; } @@ -2665,6 +3138,14 @@ bool NodeMetaInfo::isAlias() const bool NodeMetaInfo::isQtQuickPositioner() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Positioner"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Positioner>(m_projectStorage, m_typeId); @@ -2676,6 +3157,14 @@ bool NodeMetaInfo::isQtQuickPositioner() const bool NodeMetaInfo::isQtQuickPropertyAnimation() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.PropertyAnimation"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, PropertyAnimation>(m_projectStorage, m_typeId); } else { @@ -2686,6 +3175,12 @@ bool NodeMetaInfo::isQtQuickPropertyAnimation() const bool NodeMetaInfo::isQtQuickRepeater() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Repeater"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Repeater>(m_projectStorage, m_typeId); } else { @@ -2696,6 +3191,14 @@ bool NodeMetaInfo::isQtQuickRepeater() const bool NodeMetaInfo::isQtQuickControlsTabBar() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Controls.TabBar"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Controls, TabBar>(m_projectStorage, m_typeId); } else { @@ -2706,6 +3209,14 @@ bool NodeMetaInfo::isQtQuickControlsTabBar() const bool NodeMetaInfo::isQtQuickControlsSwipeView() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Controls.SwipeView"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Controls, SwipeView>(m_projectStorage, m_typeId); } else { @@ -2716,6 +3227,12 @@ bool NodeMetaInfo::isQtQuickControlsSwipeView() const bool NodeMetaInfo::isQtQuick3DCamera() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Camera"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Camera>(m_projectStorage, m_typeId); } else { @@ -2726,6 +3243,14 @@ bool NodeMetaInfo::isQtQuick3DCamera() const bool NodeMetaInfo::isQtQuick3DBakedLightmap() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.BakedLightmap"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, BakedLightmap>(m_projectStorage, m_typeId); } else { @@ -2736,6 +3261,12 @@ bool NodeMetaInfo::isQtQuick3DBakedLightmap() const bool NodeMetaInfo::isQtQuick3DBuffer() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Buffer"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Buffer>(m_projectStorage, m_typeId); } else { @@ -2746,6 +3277,14 @@ bool NodeMetaInfo::isQtQuick3DBuffer() const bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.InstanceListEntry"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, InstanceListEntry>(m_projectStorage, m_typeId); } else { @@ -2756,6 +3295,12 @@ bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const bool NodeMetaInfo::isQtQuick3DLight() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Light"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Light>(m_projectStorage, m_typeId); } else { @@ -2763,9 +3308,17 @@ bool NodeMetaInfo::isQtQuick3DLight() const } } -bool NodeMetaInfo::isQtQuickListElement() const +bool NodeMetaInfo::isQtQmlModelsListElement() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQml.Models.ListElement"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQml_Models, ListElement>(m_projectStorage, m_typeId); } else { @@ -2776,6 +3329,12 @@ bool NodeMetaInfo::isQtQuickListElement() const bool NodeMetaInfo::isQtQuickListModel() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.ListModel"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQml_Models, ListModel>(m_projectStorage, m_typeId); } else { @@ -2786,6 +3345,12 @@ bool NodeMetaInfo::isQtQuickListModel() const bool NodeMetaInfo::isQtQuickListView() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.ListView"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, ListView>(m_projectStorage, m_typeId); } else { @@ -2793,9 +3358,33 @@ bool NodeMetaInfo::isQtQuickListView() const } } +bool QmlDesigner::NodeMetaInfo::isQtQuickGridView() const +{ + if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.GridView"_t, category(), keyValue("type id", m_typeId)}; + + using namespace Storage::Info; + return isBasedOnCommonType<QtQuick, GridView>(m_projectStorage, m_typeId); + } else { + return isValid() && (isSubclassOf("QtQuick.GridView")); + } +} + bool NodeMetaInfo::isQtQuick3DInstanceList() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.InstanceList"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, InstanceList>(m_projectStorage, m_typeId); } else { @@ -2806,6 +3395,14 @@ bool NodeMetaInfo::isQtQuick3DInstanceList() const bool NodeMetaInfo::isQtQuick3DParticles3DParticle3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Particle3D"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D_Particles3D, Particle3D>(m_projectStorage, m_typeId); } else { @@ -2816,6 +3413,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DParticle3D() const bool NodeMetaInfo::isQtQuick3DParticles3DParticleEmitter3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.ParticleEmitter3D"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D_Particles3D, ParticleEmitter3D>(m_projectStorage, m_typeId); @@ -2827,6 +3432,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DParticleEmitter3D() const bool NodeMetaInfo::isQtQuick3DParticles3DAttractor3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Attractor3D"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D_Particles3D, Attractor3D>(m_projectStorage, m_typeId); } else { @@ -2837,8 +3450,16 @@ bool NodeMetaInfo::isQtQuick3DParticles3DAttractor3D() const bool NodeMetaInfo::isQtQuick3DParticlesAbstractShape() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.AbstractShape"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; - return isBasedOnCommonType<QtQuick3D_Particles3D_cppnative, QQuick3DParticleAbstractShape>( + return isBasedOnCommonType<QtQuick3D_Particles3D, QQuick3DParticleAbstractShape, ModuleKind::CppLibrary>( m_projectStorage, m_typeId); } else { return isValid() && isSubclassOf("QQuick3DParticleAbstractShape"); @@ -2848,6 +3469,12 @@ bool NodeMetaInfo::isQtQuick3DParticlesAbstractShape() const bool NodeMetaInfo::isQtQuickItem() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Item"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Item>(m_projectStorage, m_typeId); } else { @@ -2858,6 +3485,12 @@ bool NodeMetaInfo::isQtQuickItem() const bool NodeMetaInfo::isQtQuickPath() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Path"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Path>(m_projectStorage, m_typeId); } else { @@ -2868,6 +3501,14 @@ bool NodeMetaInfo::isQtQuickPath() const bool NodeMetaInfo::isQtQuickPauseAnimation() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.PauseAnimation"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, PauseAnimation>(m_projectStorage, m_typeId); } else { @@ -2878,6 +3519,14 @@ bool NodeMetaInfo::isQtQuickPauseAnimation() const bool NodeMetaInfo::isQtQuickTransition() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Transition"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Transition>(m_projectStorage, m_typeId); } else { @@ -2888,6 +3537,14 @@ bool NodeMetaInfo::isQtQuickTransition() const bool NodeMetaInfo::isQtQuickWindowWindow() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Window.Window"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Window, Window>(m_projectStorage, m_typeId); } else { @@ -2898,6 +3555,12 @@ bool NodeMetaInfo::isQtQuickWindowWindow() const bool NodeMetaInfo::isQtQuickLoader() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Loader"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Loader>(m_projectStorage, m_typeId); } else { @@ -2908,6 +3571,12 @@ bool NodeMetaInfo::isQtQuickLoader() const bool NodeMetaInfo::isQtQuickState() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.State"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, State>(m_projectStorage, m_typeId); } else { @@ -2918,9 +3587,17 @@ bool NodeMetaInfo::isQtQuickState() const bool NodeMetaInfo::isQtQuickStateOperation() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.StateOperation"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; - return isBasedOnCommonType<QtQuick_cppnative, QQuickStateOperation>(m_projectStorage, - m_typeId); + return isBasedOnCommonType<QtQuick, QQuickStateOperation, ModuleKind::CppLibrary>(m_projectStorage, + m_typeId); } else { return isValid() && isSubclassOf("<cpp>.QQuickStateOperation"); } @@ -2929,6 +3606,12 @@ bool NodeMetaInfo::isQtQuickStateOperation() const bool NodeMetaInfo::isQtQuickText() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Text"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick, Text>(m_projectStorage, m_typeId); } else { @@ -2939,6 +3622,14 @@ bool NodeMetaInfo::isQtQuickText() const bool NodeMetaInfo::isQtMultimediaSoundEffect() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtMultimedia.SoundEffect"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtMultimedia, SoundEffect>(m_projectStorage, m_typeId); } else { @@ -2949,9 +3640,11 @@ bool NodeMetaInfo::isQtMultimediaSoundEffect() const bool NodeMetaInfo::isFlowViewItem() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.ViewItem"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto flowItemId = m_projectStorage->commonTypeId<FlowView, FlowItem>(); @@ -2968,6 +3661,12 @@ bool NodeMetaInfo::isFlowViewItem() const bool NodeMetaInfo::isFlowViewFlowItem() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.FlowItem"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<FlowView, FlowItem>(m_projectStorage, m_typeId); } else { @@ -2978,6 +3677,12 @@ bool NodeMetaInfo::isFlowViewFlowItem() const bool NodeMetaInfo::isFlowViewFlowView() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.FlowView"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<FlowView, FlowView>(m_projectStorage, m_typeId); } else { @@ -2998,6 +3703,14 @@ bool NodeMetaInfo::isFlowViewFlowActionArea() const bool NodeMetaInfo::isFlowViewFlowTransition() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.FlowTransition"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<FlowView, FlowTransition>(m_projectStorage, m_typeId); } else { @@ -3008,6 +3721,14 @@ bool NodeMetaInfo::isFlowViewFlowTransition() const bool NodeMetaInfo::isFlowViewFlowDecision() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.FlowDecision"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<FlowView, FlowDecision>(m_projectStorage, m_typeId); } else { @@ -3018,6 +3739,14 @@ bool NodeMetaInfo::isFlowViewFlowDecision() const bool NodeMetaInfo::isFlowViewFlowWildcard() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is FlowView.FlowWildcard"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<FlowView, FlowWildcard>(m_projectStorage, m_typeId); } else { @@ -3028,6 +3757,14 @@ bool NodeMetaInfo::isFlowViewFlowWildcard() const bool NodeMetaInfo::isQtQuickStudioComponentsGroupItem() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Studio.Components.GroupItem"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Studio_Components, GroupItem>(m_projectStorage, m_typeId); } else { @@ -3038,6 +3775,14 @@ bool NodeMetaInfo::isQtQuickStudioComponentsGroupItem() const bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Studio.Utils.JsonListModel"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick_Studio_Components, JsonListModel>(m_projectStorage, m_typeId); @@ -3049,6 +3794,12 @@ bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const bool NodeMetaInfo::isQmlComponent() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QML, Component>(m_projectStorage, m_typeId); } else { @@ -3064,6 +3815,12 @@ bool NodeMetaInfo::isQmlComponent() const bool NodeMetaInfo::isFont() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, font>()); } else { @@ -3074,6 +3831,12 @@ bool NodeMetaInfo::isFont() const bool NodeMetaInfo::isColor() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QColor>()); } else { @@ -3089,6 +3852,12 @@ bool NodeMetaInfo::isColor() const bool NodeMetaInfo::isBool() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<bool>()); } else { @@ -3104,6 +3873,12 @@ bool NodeMetaInfo::isBool() const bool NodeMetaInfo::isInteger() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<int>()); } else { @@ -3119,9 +3894,11 @@ bool NodeMetaInfo::isInteger() const bool NodeMetaInfo::isFloat() const { if constexpr (useProjectStorage()) { - if (!isValid()) { + if (!isValid()) return false; - } + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)}; using namespace Storage::Info; auto floatId = m_projectStorage->builtinTypeId<float>(); @@ -3141,6 +3918,12 @@ bool NodeMetaInfo::isFloat() const bool NodeMetaInfo::isVariant() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QVariant>()); } else { @@ -3156,6 +3939,12 @@ bool NodeMetaInfo::isVariant() const bool NodeMetaInfo::isString() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QString>()); } else { @@ -3171,6 +3960,12 @@ bool NodeMetaInfo::isString() const bool NodeMetaInfo::isUrl() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QUrl>()); } else { @@ -3186,6 +3981,12 @@ bool NodeMetaInfo::isUrl() const bool NodeMetaInfo::isQtQuick3DTexture() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Texture"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Texture>(m_projectStorage, m_typeId); } else { @@ -3197,6 +3998,12 @@ bool NodeMetaInfo::isQtQuick3DTexture() const bool NodeMetaInfo::isQtQuick3DShader() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Shader"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Shader>(m_projectStorage, m_typeId); } else { @@ -3207,6 +4014,12 @@ bool NodeMetaInfo::isQtQuick3DShader() const bool NodeMetaInfo::isQtQuick3DPass() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Pass"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Pass>(m_projectStorage, m_typeId); } else { @@ -3217,6 +4030,12 @@ bool NodeMetaInfo::isQtQuick3DPass() const bool NodeMetaInfo::isQtQuick3DCommand() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Command"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Command>(m_projectStorage, m_typeId); } else { @@ -3227,6 +4046,14 @@ bool NodeMetaInfo::isQtQuick3DCommand() const bool NodeMetaInfo::isQtQuick3DDefaultMaterial() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.DefaultMaterial"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, DefaultMaterial>(m_projectStorage, m_typeId); } else { @@ -3247,6 +4074,12 @@ bool NodeMetaInfo::isQtQuick3DMaterial() const bool NodeMetaInfo::isQtQuick3DModel() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Model"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Storage::Info::Model>(m_projectStorage, m_typeId); } else { @@ -3257,6 +4090,12 @@ bool NodeMetaInfo::isQtQuick3DModel() const bool NodeMetaInfo::isQtQuick3DNode() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Node"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Node>(m_projectStorage, m_typeId); } else { @@ -3267,6 +4106,14 @@ bool NodeMetaInfo::isQtQuick3DNode() const bool NodeMetaInfo::isQtQuick3DParticles3DAffector3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Affector3D"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D_Particles3D, Affector3D>(m_projectStorage, m_typeId); } else { @@ -3277,6 +4124,12 @@ bool NodeMetaInfo::isQtQuick3DParticles3DAffector3D() const bool NodeMetaInfo::isQtQuick3DView3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.View3D"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, View3D>(m_projectStorage, m_typeId); } else { @@ -3287,6 +4140,14 @@ bool NodeMetaInfo::isQtQuick3DView3D() const bool NodeMetaInfo::isQtQuick3DPrincipledMaterial() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.PrincipledMaterial"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, PrincipledMaterial>(m_projectStorage, m_typeId); } else { @@ -3297,6 +4158,14 @@ bool NodeMetaInfo::isQtQuick3DPrincipledMaterial() const bool NodeMetaInfo::isQtQuick3DSpecularGlossyMaterial() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.SpecularGlossyMaterial"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, SpecularGlossyMaterial>(m_projectStorage, m_typeId); } else { @@ -3307,6 +4176,14 @@ bool NodeMetaInfo::isQtQuick3DSpecularGlossyMaterial() const bool NodeMetaInfo::isQtQuick3DParticles3DSpriteParticle3D() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.SpriteParticle3D"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D_Particles3D, SpriteParticle3D>(m_projectStorage, m_typeId); @@ -3318,6 +4195,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DSpriteParticle3D() const bool NodeMetaInfo::isQtQuick3DTextureInput() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.TextureInput"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, TextureInput>(m_projectStorage, m_typeId); } else { @@ -3328,6 +4213,14 @@ bool NodeMetaInfo::isQtQuick3DTextureInput() const bool NodeMetaInfo::isQtQuick3DCubeMapTexture() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.CubeMapTexture"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, CubeMapTexture>(m_projectStorage, m_typeId); } else { @@ -3340,6 +4233,14 @@ bool NodeMetaInfo::isQtQuick3DCubeMapTexture() const bool NodeMetaInfo::isQtQuick3DSceneEnvironment() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.SceneEnvironment"_t, + category(), + keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, SceneEnvironment>(m_projectStorage, m_typeId); } else { @@ -3350,6 +4251,12 @@ bool NodeMetaInfo::isQtQuick3DSceneEnvironment() const bool NodeMetaInfo::isQtQuick3DEffect() const { if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick3D.Effect"_t, category(), keyValue("type id", m_typeId)}; + using namespace Storage::Info; return isBasedOnCommonType<QtQuick3D, Effect>(m_projectStorage, m_typeId); } else { @@ -3359,8 +4266,15 @@ bool NodeMetaInfo::isQtQuick3DEffect() const bool NodeMetaInfo::isEnumeration() const { - if constexpr (useProjectStorage()) - return isValid() && typeData().traits.isEnum; + if constexpr (useProjectStorage()) { + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is enumeration"_t, category(), keyValue("type id", m_typeId)}; + + return typeData().traits.isEnum; + } return false; } @@ -3385,8 +4299,15 @@ PropertyMetaInfo::~PropertyMetaInfo() = default; NodeMetaInfo PropertyMetaInfo::propertyType() const { if constexpr (useProjectStorage()) { - if (isValid()) - return {propertyData().propertyTypeId, m_projectStorage}; + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property type"_t, + category(), + keyValue("property declaration id", m_id)}; + + return {propertyData().propertyTypeId, m_projectStorage}; } else { if (isValid()) return NodeMetaInfo{nodeMetaInfoPrivateData()->model(), @@ -3401,8 +4322,15 @@ NodeMetaInfo PropertyMetaInfo::propertyType() const NodeMetaInfo PropertyMetaInfo::type() const { if constexpr (useProjectStorage()) { - if (isValid()) - return NodeMetaInfo(propertyData().typeId, m_projectStorage); + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property owner type "_t, + category(), + keyValue("property declaration id", m_id)}; + + return NodeMetaInfo(propertyData().typeId, m_projectStorage); } return {}; @@ -3410,59 +4338,121 @@ NodeMetaInfo PropertyMetaInfo::type() const PropertyName PropertyMetaInfo::name() const { - if (isValid()) { - if constexpr (useProjectStorage()) - return PropertyName(Utils::SmallStringView(propertyData().name)); - else - return propertyName(); - } + if (!isValid()) + return {}; - return {}; + if constexpr (useProjectStorage()) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property name"_t, + category(), + keyValue("property declaration id", m_id)}; + + return PropertyName(Utils::SmallStringView(propertyData().name)); + } else { + return propertyName(); + } } bool PropertyMetaInfo::isWritable() const { - if constexpr (useProjectStorage()) - return isValid() && !(propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly); - else + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is property writable"_t, + category(), + keyValue("property declaration id", m_id)}; + + return !(propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly); + } else { return isValid() && nodeMetaInfoPrivateData()->isPropertyWritable(propertyName()); + } } bool PropertyMetaInfo::isReadOnly() const { - return !isWritable(); + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is property read only"_t, + category(), + keyValue("property declaration id", m_id)}; + + return propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly; + } else { + return !isWritable(); + } } bool PropertyMetaInfo::isListProperty() const { - if constexpr (useProjectStorage()) - return isValid() && propertyData().traits & Storage::PropertyDeclarationTraits::IsList; - else + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is list property"_t, + category(), + keyValue("property declaration id", m_id)}; + + return propertyData().traits & Storage::PropertyDeclarationTraits::IsList; + } else { return isValid() && nodeMetaInfoPrivateData()->isPropertyList(propertyName()); + } } bool PropertyMetaInfo::isEnumType() const { - if constexpr (useProjectStorage()) + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is enum type"_t, + category(), + keyValue("property has enumeration type", m_id)}; + return propertyType().isEnumeration(); - else + } else { return isValid() && nodeMetaInfoPrivateData()->isPropertyEnum(propertyName()); + } } bool PropertyMetaInfo::isPrivate() const { - if constexpr (useProjectStorage()) + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is private property"_t, + category(), + keyValue("property declaration id", m_id)}; + return isValid() && propertyData().name.startsWith("__"); - else + } else { return isValid() && propertyName().startsWith("__"); + } } bool PropertyMetaInfo::isPointer() const { - if constexpr (useProjectStorage()) + if constexpr (useProjectStorage()) { + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is pointer property"_t, + category(), + keyValue("property declaration id", m_id)}; + return isValid() && (propertyData().traits & Storage::PropertyDeclarationTraits::IsPointer); - else + } else { return isValid() && nodeMetaInfoPrivateData()->isPropertyPointer(propertyName()); + } } namespace { @@ -3479,6 +4469,11 @@ QVariant PropertyMetaInfo::castedValue(const QVariant &value) const return {}; if constexpr (!useProjectStorage()) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"cast value"_t, + category(), + keyValue("property declaration id", m_id)}; + const QVariant variant = value; QVariant copyVariant = variant; const TypeName &typeName = propertyTypeName(); @@ -3496,7 +4491,7 @@ QVariant PropertyMetaInfo::castedValue(const QVariant &value) const return variant; } else if (typeId == QVariant::UserType && typeName == "var") { return variant; - } else if (variant.typeId() == QVariant::List) { + } else if (variant.typeId() == QMetaType::QVariantList) { // TODO: check the contents of the list return variant; } else if (typeName == "var" || typeName == "variant") { diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index 403731d1c4..29a093f199 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -44,6 +44,7 @@ SubComponentManager::SubComponentManager(Model *model, ExternalDependenciesInterface &externalDependencies) : m_model(model) , m_externalDependencies{externalDependencies} + , m_componentUtils{externalDependencies} { connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &path) { parseDirectory(path); }); @@ -192,7 +193,7 @@ void SubComponentManager::parseDirectory(const QString &canonicalDirPath, bool a if (!model() || !model()->rewriterView()) return; - if (canonicalDirPath.endsWith(QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER))) { + if (m_componentUtils.isImport3dPath(canonicalDirPath)) { parseQuick3DAssetsDir(canonicalDirPath); return; } @@ -344,11 +345,8 @@ void SubComponentManager::unregisterQmlFile(const QFileInfo &fileInfo, const QSt void SubComponentManager::registerQmlFile(const QFileInfo &fileInfo, const QString &qualifier, bool addToLibrary) { - if (!addToLibrary || !model() - || fileInfo.path().contains(QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER)) - || fileInfo.path().contains(QLatin1String(Constants::DEFAULT_EFFECTS_IMPORT_FOLDER))) { + if (!addToLibrary || !model() || m_componentUtils.isGeneratedPath(fileInfo.path())) return; - } QString componentName = fileInfo.baseName(); const QString baseComponentName = componentName; @@ -395,7 +393,7 @@ void SubComponentManager::parseQuick3DAssetsDir(const QString &quick3DAssetsPath QDir quick3DAssetsDir(quick3DAssetsPath); QStringList assets = quick3DAssetsDir.entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot); for (QString &asset : assets) - asset.prepend(QString(Constants::QUICK_3D_ASSETS_FOLDER).mid(1) + '.'); + asset.prepend(m_componentUtils.import3dTypePrefix() + '.'); // Create item library entries for Quick3D assets that are imported by document for (auto &import : std::as_const(m_imports)) { @@ -460,7 +458,8 @@ QStringList SubComponentManager::quick3DAssetPaths() const const auto impPaths = importPaths(); QStringList retPaths; for (const auto &impPath : impPaths) { - const QString assetPath = impPath + QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER); + QString path3d = m_componentUtils.import3dTypePath(); + const QString assetPath = impPath + '/' + path3d; if (QFileInfo::exists(assetPath)) retPaths << assetPath; } @@ -520,7 +519,7 @@ void SubComponentManager::update(const QUrl &filePath, const Imports &imports) // Remove old watched asset paths const QStringList watchPaths = m_watcher.directories(); - const QString &quick3DAssetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER); + const QString &quick3DAssetFolder = m_componentUtils.import3dTypePath(); for (const auto &watchPath : watchPaths) { if (watchPath.endsWith(quick3DAssetFolder)) m_watcher.removePath(watchPath); @@ -580,7 +579,7 @@ void SubComponentManager::addAndParseImport(const Import &import) } else { QString url = import.url(); - if (url.startsWith(QString(Constants::QUICK_3D_ASSETS_FOLDER).mid(1))) { + if (url.startsWith(m_componentUtils.import3dTypePrefix())) { parseQuick3DAssetsItem(import.url()); return; } diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 061ab8ae2b..125c7195a8 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -567,8 +567,10 @@ void AbstractView::disableWidget() void AbstractView::enableWidget() { - if (hasWidget() && widgetInfo().widgetFlags == DesignerWidgetFlags::DisableOnError) - widgetInfo().widget->setEnabled(true); + if (hasWidget()) { + if (auto info = widgetInfo(); info.widgetFlags == DesignerWidgetFlags::DisableOnError) + info.widget->setEnabled(true); + } } QString AbstractView::contextHelpId() const diff --git a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp index 141548047e..23c17dc61a 100644 --- a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp +++ b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp @@ -37,10 +37,11 @@ BindingProperty::BindingProperty(const PropertyName &propertyName, const Interna void BindingProperty::setExpression(const QString &expression) { - Internal::WriteLocker locker(model()); if (!isValid()) return; + Internal::WriteLocker locker(model()); + if (isDynamic()) qWarning() << "Calling BindingProperty::setExpression on dynamic property."; diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index a4cd31b2a8..d4eea26378 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -9,7 +9,6 @@ #include "../projectstorage/sourcepath.h" #include "../projectstorage/sourcepathcache.h" #include "abstractview.h" -#include "auxiliarydataproperties.h" #include "internalbindingproperty.h" #include "internalnodeabstractproperty.h" #include "internalnodelistproperty.h" @@ -33,6 +32,8 @@ #include "signalhandlerproperty.h" #include "variantproperty.h" +#include <uniquename.h> + #include <projectstorage/projectstorage.h> #include <qmljs/qmljsmodelmanagerinterface.h> @@ -46,8 +47,6 @@ #include <QRegularExpression> #include <qcompilerdetection.h> -#include <string> - /*! \defgroup CoreModel */ @@ -170,10 +169,10 @@ Storage::Imports createStorageImports(const Imports &imports, SourceId fileId) { return Utils::transform<Storage::Imports>(imports, [&](const Import &import) { - return Storage::Import{projectStorage.moduleId(Utils::SmallString{import.url()}), - import.majorVersion(), - import.minorVersion(), - fileId}; + using Storage::ModuleKind; + auto moduleKind = import.isLibraryImport() ? ModuleKind::QmlLibrary : ModuleKind::PathLibrary; + auto moduleId = projectStorage.moduleId(Utils::SmallString{import.url()}, moduleKind); + return Storage::Import{moduleId, import.majorVersion(), import.minorVersion(), fileId}; }); } @@ -244,7 +243,7 @@ void ModelPrivate::notifyUsedImportsChanged(const Imports &usedImports) } } -QUrl ModelPrivate::fileUrl() const +const QUrl &ModelPrivate::fileUrl() const { return m_fileUrl; } @@ -390,7 +389,11 @@ ImportedTypeNameId ModelPrivate::importedTypeNameId(Utils::SmallStringView typeN return import.alias() == aliasName; }); if (found != m_imports.end()) { - ModuleId moduleId = projectStorage->moduleId(Utils::PathString{found->url()}); + using Storage::ModuleKind; + auto moduleKind = found->isLibraryImport() ? ModuleKind::QmlLibrary + : ModuleKind::PathLibrary; + ModuleId moduleId = projectStorage->moduleId(Utils::PathString{found->url()}, + moduleKind); ImportId importId = projectStorage->importId( Storage::Import{moduleId, found->majorVersion(), found->minorVersion(), m_sourceId}); return projectStorage->importedTypeNameId(importId, shortTypeName); @@ -1758,14 +1761,22 @@ Storage::Info::ExportedTypeName Model::exportedTypeNameForMetaInfo(const NodeMet return {}; } -const Imports &Model::possibleImports() const +Imports Model::possibleImports() const { +#ifdef QDS_USE_PROJECTSTORAGE + return {}; +#else return d->m_possibleImportList; +#endif } -const Imports &Model::usedImports() const +Imports Model::usedImports() const { +#ifdef QDS_USE_PROJECTSTORAGE + return {}; +#else return d->m_usedImportList; +#endif } void Model::changeImports(Imports importsToBeAdded, Imports importsToBeRemoved) @@ -1773,6 +1784,7 @@ void Model::changeImports(Imports importsToBeAdded, Imports importsToBeRemoved) d->changeImports(std::move(importsToBeAdded), std::move(importsToBeRemoved)); } +#ifndef QDS_USE_PROJECTSTORAGE void Model::setPossibleImports(Imports possibleImports) { auto tracer = d->traceToken.begin("possible imports"_t); @@ -1784,7 +1796,9 @@ void Model::setPossibleImports(Imports possibleImports) d->notifyPossibleImportsChanged(d->m_possibleImportList); } } +#endif +#ifndef QDS_USE_PROJECTSTORAGE void Model::setUsedImports(Imports usedImports) { auto tracer = d->traceToken.begin("used imports"_t); @@ -1796,6 +1810,7 @@ void Model::setUsedImports(Imports usedImports) d->notifyUsedImportsChanged(d->m_usedImportList); } } +#endif static bool compareVersions(const Import &import1, const Import &import2, bool allowHigherVersion) { @@ -1848,89 +1863,18 @@ bool Model::hasImport(const QString &importUrl) const }); } -static QString firstCharToLower(const QString &string) -{ - QString resultString = string; - - if (!resultString.isEmpty()) - resultString[0] = resultString.at(0).toLower(); - - return resultString; -} - -QString Model::generateNewId(const QString &prefixName, - const QString &fallbackPrefix, - std::optional<std::function<bool(const QString &)>> isDuplicate) const +QString Model::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const { - // First try just the prefixName without number as postfix, then continue with 2 and further - // as postfix until id does not already exist. - // Properties of the root node are not allowed for ids, because they are available in the - // complete context without qualification. - - int counter = 0; - - QString newBaseId = QStringView(u"%1").arg(firstCharToLower(prefixName)); - newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]"))); - - if (!newBaseId.isEmpty()) { - QChar firstChar = newBaseId.at(0); - if (firstChar.isDigit()) - newBaseId.prepend('_'); - } else { - newBaseId = fallbackPrefix; - } - - QString newId = newBaseId; + QString newId = prefixName; - if (!isDuplicate.has_value()) - isDuplicate = std::bind(&Model::hasId, this, std::placeholders::_1); + if (newId.isEmpty()) + newId = fallbackPrefix; - while (!ModelNode::isValidId(newId) || isDuplicate.value()(newId) - || d->rootNode()->property(newId.toUtf8())) { - ++counter; - newId = QStringView(u"%1%2").arg(firstCharToLower(newBaseId)).arg(counter); - } - - return newId; -} - -// Generate a unique camelCase id from a name -// note: this methods does the same as generateNewId(). The 2 methods should be merged into one -QString Model::generateIdFromName(const QString &name, const QString &fallbackId) const -{ - QString newId; - if (name.isEmpty()) { - newId = fallbackId; - } else { - // convert to camel case - QStringList nameWords = name.split(" "); - nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1); - for (int i = 1; i < nameWords.size(); ++i) - nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1); - newId = nameWords.join(""); - - // if id starts with a number prepend an underscore - if (newId.at(0).isDigit()) - newId.prepend('_'); - } - - // If the new id is not valid (e.g. qml keyword match), try fixing it by prepending underscore - if (!ModelNode::isValidId(newId)) - newId.prepend("_"); - - QRegularExpression rgx("\\d+$"); // matches a number at the end of a string - while (hasId(newId)) { // id exists - QRegularExpressionMatch match = rgx.match(newId); - if (match.hasMatch()) { // ends with a number, increment it - QString numStr = match.captured(); - int num = numStr.toInt() + 1; - newId = newId.mid(0, match.capturedStart()) + QString::number(num); - } else { - newId.append('1'); - } - } - - return newId; + return UniqueName::generateId(prefixName, [&] (const QString &id) { + // Properties of the root node are not allowed for ids, because they are available in the + // complete context without qualification. + return hasId(id) || d->rootNode()->property(id.toUtf8()); + }); } void Model::startDrag(QMimeData *mimeData, const QPixmap &icon) @@ -2021,14 +1965,6 @@ bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowH return false; } -QString Model::pathForImport(const Import &import) -{ - if (!rewriterView()) - return QString(); - - return rewriterView()->pathForImport(import); -} - QStringList Model::importPaths() const { if (rewriterView()) @@ -2110,7 +2046,7 @@ void Model::clearMetaInfoCache() \brief Returns the URL against which relative URLs within the model should be resolved. \return The base URL. */ -QUrl Model::fileUrl() const +const QUrl &Model::fileUrl() const { return d->fileUrl(); } @@ -2205,6 +2141,16 @@ NodeMetaInfo Model::qtQmlModelsListElementMetaInfo() const } } +NodeMetaInfo Model::qtQmlXmlListModelXmlListModelRoleMetaInfo() const +{ + if constexpr (useProjectStorage()) { + using namespace Storage::Info; + return createNodeMetaInfo<QtQml_XmlListModel, XmlListModelRole>(); + } else { + return metaInfo("QtQml.XmlListModel.XmlListModelRole"); + } +} + NodeMetaInfo Model::qmlQtObjectMetaInfo() const { if constexpr (useProjectStorage()) { @@ -2541,8 +2487,7 @@ QList<ItemLibraryEntry> Model::itemLibraryEntries() const { #ifdef QDS_USE_PROJECTSTORAGE using namespace Storage::Info; - return toItemLibraryEntries(d->projectStorage->itemLibraryEntries(d->m_sourceId), - *d->projectStorage); + return toItemLibraryEntries(d->projectStorage->itemLibraryEntries(d->m_sourceId)); #else return d->metaInfo().itemLibraryInfo()->entries(); #endif @@ -2608,11 +2553,10 @@ MetaInfo Model::metaInfo() } #endif -Module Model::module(Utils::SmallStringView moduleName) +Module Model::module(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind) { - if constexpr (useProjectStorage()) { - return Module(d->projectStorage->moduleId(moduleName), d->projectStorage); - } + if constexpr (useProjectStorage()) + return Module(d->projectStorage->moduleId(moduleName, moduleKind), d->projectStorage); return {}; } diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index a3e972f329..cb082fd1d7 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -122,7 +122,7 @@ public: ModelPrivate(const ModelPrivate &) = delete; ModelPrivate &operator=(const ModelPrivate &) = delete; - QUrl fileUrl() const; + const QUrl &fileUrl() const; void setFileUrl(const QUrl &url); InternalNodePointer createNode(const TypeName &typeName, diff --git a/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp b/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp index a61f1001f9..27ac2e67ab 100644 --- a/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp @@ -515,8 +515,7 @@ struct BindingFilter struct TargetFilter { TargetFilter(NodeDependencies &dependencies, Model *model) - : flowViewFlowActionAreaMetaInfo{model->flowViewFlowActionAreaMetaInfo()} - , flowViewFlowTransitionMetaInfo{model->flowViewFlowTransitionMetaInfo()} + : flowViewFlowTransitionMetaInfo{model->flowViewFlowTransitionMetaInfo()} , qtQuickPropertyChangesMetaInfo{model->qtQuickPropertyChangesMetaInfo()} , qtQuickTimelineKeyframeGroupMetaInfo{model->qtQuickTimelineKeyframeGroupMetaInfo()} , qtQuickPropertyAnimationMetaInfo{model->qtQuickPropertyAnimationMetaInfo()} diff --git a/src/plugins/qmldesigner/designercore/model/modelutils.cpp b/src/plugins/qmldesigner/designercore/model/modelutils.cpp index cb3f482289..6c3e1ea50f 100644 --- a/src/plugins/qmldesigner/designercore/model/modelutils.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelutils.cpp @@ -9,6 +9,8 @@ #include <projectstorage/projectstorage.h> #include <projectstorage/sourcepathcache.h> +#include <coreplugin/messagebox.h> + #include <utils/expected.h> #include <utils/ranges.h> @@ -107,19 +109,19 @@ PropertyMetaInfo metainfo(const ModelNode &node, const PropertyName &propertyNam return node.metaInfo().property(propertyName); } -QString componentFilePath(const PathCacheType &pathCache, const NodeMetaInfo &metaInfo) +QString componentFilePath([[maybe_unused]] const PathCacheType &pathCache, const NodeMetaInfo &metaInfo) { - if constexpr (useProjectStorage()) { - auto typeSourceId = metaInfo.sourceId(); +#ifdef QDS_USE_PROJECTSTORAGE + auto typeSourceId = metaInfo.sourceId(); - if (typeSourceId && metaInfo.isFileComponent()) { - return pathCache.sourcePath(typeSourceId).toQString(); - } - } else { - return metaInfo.componentFileName(); + if (typeSourceId && metaInfo.isFileComponent()) { + return pathCache.sourcePath(typeSourceId).toQString(); } return {}; +#else + return metaInfo.componentFileName(); +#endif } QString componentFilePath(const ModelNode &node) diff --git a/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp b/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp index cd7cebbb73..8eaa7947de 100644 --- a/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp +++ b/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp @@ -41,7 +41,7 @@ PropertyName PropertyContainer::name() const QVariant PropertyContainer::value() const { - if (m_value.typeId() == QVariant::String) + if (m_value.typeId() == QMetaType::QString) m_value = PropertyParser::read(m_type, m_value.toString()); return m_value; } diff --git a/src/plugins/qmldesigner/designercore/model/propertyparser.cpp b/src/plugins/qmldesigner/designercore/model/propertyparser.cpp index 788530c291..264c944fea 100644 --- a/src/plugins/qmldesigner/designercore/model/propertyparser.cpp +++ b/src/plugins/qmldesigner/designercore/model/propertyparser.cpp @@ -201,7 +201,7 @@ QVariant read(const QString &typeStr, const QString &str, const MetaInfo &) QVariant read(const QString &typeStr, const QString &str) { - int type = QMetaType::type(typeStr.toUtf8().constData()); + int type = QMetaType::fromName(typeStr.toUtf8().constData()).id(); if (type == 0) { if (typeStr != "binding"_L1 && typeStr != "enum"_L1) { qWarning() << "Type " << typeStr @@ -270,15 +270,14 @@ QVariant read(int variantType, const QString &str) value = QVariant::fromValue<Enumeration>(enumerationFromString(str, &conversionOk)); } else { value = QVariant(str); - value.convert(static_cast<QVariant::Type>(variantType)); + value.convert(QMetaType(variantType)); } break; } } if (!conversionOk) { - qWarning() << "Could not convert" << str - << "to" << QMetaType::typeName(variantType); + qWarning() << "Could not convert" << str << "to" << QMetaType(variantType).name(); value = QVariant(str); } diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 826856428b..6e3b739096 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -9,8 +9,9 @@ #include "bindingproperty.h" #include "qmlanchors.h" -#include <model.h> #include <abstractview.h> +#include <generatedcomponentutils.h> +#include <model.h> #include <coreplugin/icore.h> @@ -196,7 +197,9 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view, auto createEffectNode = [=, &newQmlItemNode, &parentProperty]() { const QString effectName = QFileInfo(effectPath).baseName(); - Import import = Import::createLibraryImport("Effects." + effectName, "1.0"); + Import import = Import::createLibraryImport(GeneratedComponentUtils(view->externalDependencies()) + .composedEffectsTypePrefix() + + '.' + effectName, "1.0"); try { if (!view->model()->hasImport(import, true, true)) view->model()->changeImports({import}, {}); @@ -748,7 +751,6 @@ void QmlFlowActionAreaNode::assignTargetFlowItem(const QmlFlowTargetNode &flowIt ModelNode transition = flowView.addTransition(flowParent.modelNode(), flowItem.modelNode()); - modelNode().bindingProperty("target").setExpression(transition.validId()); } diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp index c84f234257..726d3d52af 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp @@ -24,6 +24,8 @@ #include <QDir> #include <QRandomGenerator> +#include <memory> + namespace QmlDesigner { static char imagePlaceHolder[] = "qrc:/qtquickplugin/images/template_image.png"; @@ -182,8 +184,8 @@ void QmlVisualNode::scatter(const ModelNode &targetNode, const std::optional<int if (!scatter) return; - if (offset.has_value()) { // offset - double offsetValue = offset.value(); + if (offset) { // offset + double offsetValue = *offset; this->translate(QVector3D(offsetValue, offsetValue, offsetValue)); } else { // scatter in range const double scatterRange = 20.; @@ -250,8 +252,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, NodeAbstractProperty parentProperty = parentQmlItemNode.defaultNodeAbstractProperty(); - - NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry); + NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry, view->model()); const PropertyName forceNonDefaultProperty = hints.forceNonDefaultProperty().toUtf8(); QmlObjectNode newNode = QmlItemNode::createQmlObjectNode(view, @@ -289,17 +290,17 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view, textEdit.setPlainText(source); NotIndentingTextEditModifier modifier(&textEdit); - QScopedPointer<RewriterView> rewriterView( - new RewriterView(view->externalDependencies(), RewriterView::Amend)); + std::unique_ptr<RewriterView> rewriterView = std::make_unique<RewriterView>( + view->externalDependencies(), RewriterView::Amend); rewriterView->setCheckSemanticErrors(false); rewriterView->setTextModifier(&modifier); rewriterView->setAllowComponentRoot(true); rewriterView->setPossibleImportsEnabled(false); - inputModel->setRewriterView(rewriterView.data()); + inputModel->setRewriterView(rewriterView.get()); if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) { ModelNode rootModelNode = rewriterView->rootModelNode(); - inputModel->detachView(rewriterView.data()); + inputModel->detachView(rewriterView.get()); QmlVisualNode(rootModelNode).setPosition(position); ModelMerger merger(view); return merger.insertModel(rootModelNode); @@ -329,7 +330,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, { QmlObjectNode newQmlObjectNode; - NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry); + NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry, view->model()); auto createNodeFunc = [=, &newQmlObjectNode, &parentProperty]() { #ifndef QDS_USE_PROJECTSTORAGE @@ -361,13 +362,17 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, propertyPairList.append(position.propertyPairList()); ModelNode::NodeSourceType nodeSourceType = ModelNode::NodeWithoutSource; - if (itemLibraryEntry.typeName() == "QtQml.Component") - nodeSourceType = ModelNode::NodeWithComponentSource; #ifdef QDS_USE_PROJECTSTORAGE + NodeMetaInfo metaInfo{itemLibraryEntry.typeId(), view->model()->projectStorage()}; + if (metaInfo.isQmlComponent()) + nodeSourceType = ModelNode::NodeWithComponentSource; newQmlObjectNode = QmlObjectNode(view->createModelNode( itemLibraryEntry.typeName(), propertyPairList, {}, {}, nodeSourceType)); #else + if (itemLibraryEntry.typeName() == "QtQml.Component") + nodeSourceType = ModelNode::NodeWithComponentSource; + newQmlObjectNode = QmlObjectNode(view->createModelNode(itemLibraryEntry.typeName(), majorVersion, minorVersion, diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index c4d96bb250..edee6840ef 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -58,7 +58,6 @@ void RewriteActionCompressor::compressImports(QList<RewriteAction *> &actions) c actionsToRemove.append(action); actionsToRemove.append(addImportAction); addedImports.remove(import); - delete addImportAction; } else { removedImports.insert(import, action); } @@ -67,13 +66,11 @@ void RewriteActionCompressor::compressImports(QList<RewriteAction *> &actions) c if (RewriteAction *duplicateAction = addedImports.value(import, 0)) { actionsToRemove.append(duplicateAction); addedImports.remove(import); - delete duplicateAction; addedImports.insert(import, action); } else if (RewriteAction *removeAction = removedImports.value(import, 0)) { actionsToRemove.append(action); actionsToRemove.append(removeAction); removedImports.remove(import); - delete removeAction; } else { addedImports.insert(import, action); } diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 4ae2261e60..3c481573d2 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -16,12 +16,14 @@ #include <filemanager/objectlengthcalculator.h> #include <modelnode.h> #include <modelnodepositionstorage.h> +#include <nodemetainfo.h> #include <nodeproperty.h> +#include <projectstorage/projectstorage.h> +#include <qmlobjectnode.h> +#include <qmltimelinekeyframegroup.h> #include <rewritingexception.h> #include <signalhandlerproperty.h> #include <variantproperty.h> -#include <qmlobjectnode.h> -#include <qmltimelinekeyframegroup.h> #include <qmljs/parser/qmljsengine_p.h> #include <qmljs/qmljsmodelmanagerinterface.h> @@ -56,9 +58,9 @@ RewriterView::RewriterView(ExternalDependenciesInterface &externalDependencies, DifferenceHandling differenceHandling) : AbstractView{externalDependencies} , m_differenceHandling(differenceHandling) - , m_positionStorage(new ModelNodePositionStorage) - , m_modelToTextMerger(new Internal::ModelToTextMerger(this)) - , m_textToModelMerger(new Internal::TextToModelMerger(this)) + , m_positionStorage(std::make_unique<ModelNodePositionStorage>()) + , m_modelToTextMerger(std::make_unique<Internal::ModelToTextMerger>(this)) + , m_textToModelMerger(std::make_unique<Internal::TextToModelMerger>(this)) { m_amendTimer.setSingleShot(true); @@ -78,12 +80,12 @@ RewriterView::~RewriterView() = default; Internal::ModelToTextMerger *RewriterView::modelToTextMerger() const { - return m_modelToTextMerger.data(); + return m_modelToTextMerger.get(); } Internal::TextToModelMerger *RewriterView::textToModelMerger() const { - return m_textToModelMerger.data(); + return m_textToModelMerger.get(); } void RewriterView::modelAttached(Model *model) @@ -92,7 +94,7 @@ void RewriterView::modelAttached(Model *model) AbstractView::modelAttached(model); - ModelAmender differenceHandler(m_textToModelMerger.data()); + ModelAmender differenceHandler(m_textToModelMerger.get()); const QString qmlSource = m_textModifier->text(); if (m_textToModelMerger->load(qmlSource, differenceHandler)) m_lastCorrectQmlSource = qmlSource; @@ -104,6 +106,7 @@ void RewriterView::modelAttached(Model *model) m_modelAttachPending = true; QTimer::singleShot(1000, this, [this, model](){ modelAttached(model); + restoreAuxiliaryData(); }); } } @@ -492,7 +495,7 @@ void RewriterView::amendQmlText() const QString newQmlText = m_textModifier->text(); - ModelAmender differenceHandler(m_textToModelMerger.data()); + ModelAmender differenceHandler(m_textToModelMerger.get()); if (m_textToModelMerger->load(newQmlText, differenceHandler)) m_lastCorrectQmlSource = newQmlText; emitCustomNotification(EndRewriterAmend); @@ -593,7 +596,7 @@ QString RewriterView::auxiliaryDataAsQML() const hasAuxData = true; QString strValue = value.toString(); - auto metaType = static_cast<QMetaType::Type>(value.type()); + const int metaType = value.typeId(); if (metaType == QMetaType::QString || metaType == QMetaType::QColor) { @@ -698,7 +701,7 @@ void RewriterView::forceAmend() Internal::ModelNodePositionStorage *RewriterView::positionStorage() const { - return m_positionStorage.data(); + return m_positionStorage.get(); } QList<DocumentMessage> RewriterView::warnings() const @@ -755,7 +758,7 @@ void RewriterView::resetToLastCorrectQml() { m_textModifier->textDocument()->undo(); m_textModifier->textDocument()->clearUndoRedoStacks(QTextDocument::RedoStack); - ModelAmender differenceHandler(m_textToModelMerger.data()); + ModelAmender differenceHandler(m_textToModelMerger.get()); Internal::WriteLocker::unlock(model()); m_textToModelMerger->load(m_textModifier->text(), differenceHandler); Internal::WriteLocker::lock(model()); @@ -933,10 +936,12 @@ bool RewriterView::renameId(const QString& oldId, const QString& newId) return false; } +#ifndef QDS_USE_PROJECTSTORAGE const QmlJS::ScopeChain *RewriterView::scopeChain() const { return textToModelMerger()->scopeChain(); } +#endif const QmlJS::Document *RewriterView::document() const { @@ -989,38 +994,74 @@ QString RewriterView::convertTypeToImportAlias(const QString &type) const return result; } -QString RewriterView::pathForImport(const Import &import) +QStringList RewriterView::importDirectories() const { - if (scopeChain() && scopeChain()->context() && document()) { - const QString importStr = import.isFileImport() ? import.file() : import.url(); - const QmlJS::Imports *imports = scopeChain()->context()->imports(document()); + const QList<Utils::FilePath> list(m_textToModelMerger->vContext().paths.begin(), + m_textToModelMerger->vContext().paths.end()); - QmlJS::ImportInfo importInfo; + return Utils::transform(list, [](const Utils::FilePath &p) { return p.toString(); }); +} - for (const QmlJS::Import &qmljsImport : imports->all()) { - if (qmljsImport.info.name() == importStr) - importInfo = qmljsImport.info; - } - const QString importPath = importInfo.path(); - return importPath; +QSet<QPair<QString, QString> > RewriterView::qrcMapping() const +{ + return m_textToModelMerger->qrcMapping(); +} + +namespace { +#ifdef QDS_USE_PROJECTSTORAGE + +ModuleIds generateModuleIds(const ModelNodes &nodes) +{ + ModuleIds moduleIds; + moduleIds.reserve(Utils::usize(nodes)); + for (const auto &node : nodes) { + auto exportedNames = node.metaInfo().allExportedTypeNames(); + if (exportedNames.size()) + moduleIds.push_back(exportedNames.front().moduleId); } - return QString(); + std::sort(moduleIds.begin(), moduleIds.end()); + moduleIds.erase(std::unique(moduleIds.begin(), moduleIds.end()), moduleIds.end()); + + return moduleIds; } -QStringList RewriterView::importDirectories() const +QStringList generateImports(ModuleIds moduleIds, const ProjectStorageType &projectStorage) { - const QList<Utils::FilePath> list(m_textToModelMerger->vContext().paths.begin(), - m_textToModelMerger->vContext().paths.end()); + QStringList imports; + imports.reserve(std::ssize(moduleIds)); - return Utils::transform(list, [](const Utils::FilePath &p) { return p.toString(); }); + for (auto moduleId : moduleIds) { + using Storage::ModuleKind; + auto module = projectStorage.module(moduleId); + switch (module.kind) { + case ModuleKind::QmlLibrary: + imports.push_back("import " + module.name.toQString()); + break; + case ModuleKind::PathLibrary: + imports.push_back("import \"" + module.name.toQString() + "\""); + break; + case ModuleKind::CppLibrary: + break; + } + } + + return imports; } -QSet<QPair<QString, QString> > RewriterView::qrcMapping() const +QStringList generateImports(const ModelNodes &nodes) { - return m_textToModelMerger->qrcMapping(); + if (nodes.empty()) + return {}; + + auto moduleIds = generateModuleIds(nodes); + + return generateImports(moduleIds, *nodes.front().model()->projectStorage()); } +#endif +} // namespace + void RewriterView::moveToComponent(const ModelNode &modelNode) { if (!modelNode.isValid()) @@ -1029,20 +1070,26 @@ void RewriterView::moveToComponent(const ModelNode &modelNode) int offset = nodeOffset(modelNode); const QList<ModelNode> nodes = modelNode.allSubModelNodesAndThisNode(); - QSet<QString> directPaths; +#ifdef QDS_USE_PROJECTSTORAGE + auto directPaths = generateImports(nodes); +#else + QSet<QString> directPathsSet; // Always add QtQuick import QString quickImport = model()->qtQuickItemMetaInfo().requiredImportString(); if (!quickImport.isEmpty()) - directPaths.insert(quickImport); + directPathsSet.insert(quickImport); for (const ModelNode &partialNode : nodes) { QString importStr = partialNode.metaInfo().requiredImportString(); if (importStr.size()) - directPaths << importStr; + directPathsSet << importStr; } - QString importData = Utils::sorted(directPaths.values()).join(QChar::LineFeed); + auto directPaths = directPathsSet.values(); +#endif + + QString importData = Utils::sorted(directPaths).join(QChar::LineFeed); if (importData.size()) importData.append(QString(2, QChar::LineFeed)); @@ -1108,7 +1155,7 @@ void RewriterView::qmlTextChanged() switch (m_differenceHandling) { case Validate: { - ModelValidator differenceHandler(m_textToModelMerger.data()); + ModelValidator differenceHandler(m_textToModelMerger.get()); if (m_textToModelMerger->load(newQmlText, differenceHandler)) m_lastCorrectQmlSource = newQmlText; break; diff --git a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp index 16877b61db..4f744d54e6 100644 --- a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp @@ -23,6 +23,8 @@ #include <QQueue> #include <QRegularExpression> +#include <memory> + namespace { QPoint pointForModelNode(const QmlDesigner::ModelNode &node) @@ -641,10 +643,10 @@ void StylesheetMerger::styleMerge(const QString &qmlTemplateString, textEditTemplate.setPlainText(imports + qmlTemplateString); NotIndentingTextEditModifier textModifierTemplate(&textEditTemplate); - QScopedPointer<RewriterView> templateRewriterView( - new RewriterView(externalDependencies, RewriterView::Amend)); + std::unique_ptr<RewriterView> templateRewriterView = std::make_unique<RewriterView>( + externalDependencies, RewriterView::Amend); templateRewriterView->setTextModifier(&textModifierTemplate); - templateModel->attachView(templateRewriterView.data()); + templateModel->attachView(templateRewriterView.get()); templateRewriterView->setCheckSemanticErrors(false); templateRewriterView->setPossibleImportsEnabled(false); @@ -665,12 +667,12 @@ void StylesheetMerger::styleMerge(const QString &qmlTemplateString, textEditStyle.setPlainText(parentRewriterView->textModifierContent()); NotIndentingTextEditModifier textModifierStyle(&textEditStyle); - QScopedPointer<RewriterView> styleRewriterView( - new RewriterView(externalDependencies, RewriterView::Amend)); + std::unique_ptr<RewriterView> styleRewriterView = std::make_unique<RewriterView>( + externalDependencies, RewriterView::Amend); styleRewriterView->setTextModifier(&textModifierStyle); - styleModel->attachView(styleRewriterView.data()); + styleModel->attachView(styleRewriterView.get()); - StylesheetMerger merger(templateRewriterView.data(), styleRewriterView.data()); + StylesheetMerger merger(templateRewriterView.get(), styleRewriterView.get()); try { merger.merge(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index f7be6cf5e4..ded7fbc5ef 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -57,7 +57,7 @@ using namespace QmlJS; using namespace Qt::StringLiterals; static Q_LOGGING_CATEGORY(rewriterBenchmark, "qtc.rewriter.load", QtWarningMsg) -static Q_LOGGING_CATEGORY(texttomodelMergerDebug, "qtc.texttomodelmerger.debug", QtDebugMsg) +static Q_LOGGING_CATEGORY(texttomodelMergerLog, "qtc.texttomodelmerger", QtWarningMsg) namespace { @@ -67,17 +67,6 @@ bool isSupportedAttachedProperties(const QString &propertyName) || propertyName.startsWith(QLatin1String("InsightCategory.")); } -bool isSupportedVersion(QmlDesigner::Version version) -{ - if (version.major == 2) - return version.minor <= 15; - - if (version.major == 6) - return version.minor <= 6; - - return false; -} - bool isGlobalQtEnums(QStringView value) { static constexpr auto list = Utils::to_array<std::u16string_view>( @@ -95,6 +84,9 @@ bool isGlobalQtEnums(QStringView value) u"TopToBottom", u"UpArrowCursor", u"Vertical", u"WaitCursor", u"WhatsThisCursor", u"WheelFocus"}); + if (value.toString().startsWith("Key_")) + return true; + return std::binary_search(std::begin(list), std::end(list), QmlDesigner::ModelUtils::toStdStringView(value)); @@ -102,32 +94,28 @@ bool isGlobalQtEnums(QStringView value) bool isKnownEnumScopes(QStringView value) { - static constexpr auto list = Utils::to_array<std::u16string_view>({u"TextInput", - u"TextEdit", - u"Material", - u"Universal", - u"Font", - u"Shape", - u"ShapePath", - u"AbstractButton", - u"Text", - u"ShaderEffectSource", - u"Grid", - u"ItemLayer", - u"ImageLayer", - u"SpriteLayer", - u"Light"}); + static constexpr auto list = Utils::to_array<std::u16string_view>( + {u"TextInput", + u"TextEdit", + u"Material", + u"Universal", + u"Font", + u"Shape", + u"ShapePath", + u"AbstractButton", + u"Text", + u"ShaderEffectSource", + u"Grid", + u"ItemLayer", + u"ImageLayer", + u"SpriteLayer", + u"Light", + u"ExtendedSceneEnvironment.GlowBlendMode"}); return std::find(std::begin(list), std::end(list), QmlDesigner::ModelUtils::toStdStringView(value)) != std::end(list); } -bool supportedQtQuickVersion(const QmlDesigner::Import &import) -{ - auto version = import.toVersion(); - return version.isEmpty() || isSupportedVersion(version); -} - QString stripQuotes(const QString &str) { if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"'))) @@ -431,14 +419,19 @@ namespace Internal { class ReadingContext { public: - ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc, - const ViewerContext &vContext, Model *model) + ReadingContext([[maybe_unused]] const Snapshot &snapshot, + [[maybe_unused]] const Document::Ptr &doc, + [[maybe_unused]] const ViewerContext &vContext, + Model *model) : m_doc(doc) +#ifndef QDS_USE_PROJECTSTORAGE , m_context( - Link(snapshot, vContext, ModelManagerInterface::instance()->builtins(doc)) - (doc, &m_diagnosticLinkMessages)) + Link(snapshot, + vContext, + ModelManagerInterface::instance()->builtins(doc))(doc, &m_diagnosticLinkMessages)) , m_scopeChain(doc, m_context) , m_scopeBuilder(&m_scopeChain) +#endif , m_model(model) { } @@ -446,12 +439,19 @@ public: ~ReadingContext() = default; Document::Ptr doc() const - { return m_doc; } + { + return m_doc; + } +#ifndef QDS_USE_PROJECTSTORAGE void enterScope(AST::Node *node) { m_scopeBuilder.push(node); } - void leaveScope() { m_scopeBuilder.pop(); } + void leaveScope() + { + m_scopeBuilder.pop(); + } +#endif std::tuple<NodeMetaInfo, TypeName> lookup(AST::UiQualifiedId *astTypeNode) { @@ -481,113 +481,6 @@ public: return node.metaInfo().hasProperty(propertyName.toUtf8()); } - /// When something is changed here, also change Check::checkScopeObjectMember in - /// qmljscheck.cpp - /// ### Maybe put this into the context as a helper function. - /// - bool lookupProperty(const QString &prefix, - const AST::UiQualifiedId *id, - const Value **property = nullptr, - const ObjectValue **parentObject = nullptr, - QString *name = nullptr) - { - QList<const ObjectValue *> scopeObjects = m_scopeChain.qmlScopeObjects(); - if (scopeObjects.isEmpty()) - return false; - - if (!id) - return false; // ### error? - - if (id->name.isEmpty()) // possible after error recovery - return false; - - QString propertyName; - if (prefix.isEmpty()) - propertyName = id->name.toString(); - else - propertyName = prefix; - - if (name) - *name = propertyName; - - if (propertyName == u"id" && !id->next) - return false; // ### should probably be a special value - - // attached properties - bool isAttachedProperty = false; - if (! propertyName.isEmpty() && propertyName[0].isUpper()) { - isAttachedProperty = true; - if (const ObjectValue *qmlTypes = m_scopeChain.qmlTypes()) - scopeObjects += qmlTypes; - } - - if (scopeObjects.isEmpty()) - return false; - - // global lookup for first part of id - const ObjectValue *objectValue = nullptr; - const Value *value = nullptr; - for (int i = scopeObjects.size() - 1; i >= 0; --i) { - objectValue = scopeObjects[i]; - value = objectValue->lookupMember(propertyName, m_context); - if (value) - break; - } - if (parentObject) - *parentObject = objectValue; - if (!value) { - qCInfo(texttomodelMergerDebug) << Q_FUNC_INFO << "Skipping invalid property name" << propertyName; - return false; - } - - // can't look up members for attached properties - if (isAttachedProperty) - return false; - - // resolve references - if (const Reference *ref = value->asReference()) - value = m_context->lookupReference(ref); - - // member lookup - const AST::UiQualifiedId *idPart = id; - if (prefix.isEmpty()) - idPart = idPart->next; - for (; idPart; idPart = idPart->next) { - objectValue = value_cast<ObjectValue>(value); - if (! objectValue) { -// if (idPart->name) -// qDebug() << idPart->name->asString() << "has no property named" -// << propertyName; - return false; - } - if (parentObject) - *parentObject = objectValue; - - if (idPart->name.isEmpty()) { - // somebody typed "id." and error recovery still gave us a valid tree, - // so just bail out here. - return false; - } - - propertyName = idPart->name.toString(); - if (name) - *name = propertyName; - - value = objectValue->lookupMember(propertyName, m_context); - if (! value) { -// if (idPart->name) -// qDebug() << "In" << idPart->name->asString() << ":" -// << objectValue->className() << "has no property named" -// << propertyName; - return false; - } - } - - if (property) - *property = value; - return true; - } - bool isArrayProperty(const AbstractProperty &property) { return ModelUtils::metainfo(property).isListProperty(); @@ -610,9 +503,9 @@ public: if (!propertyMetaInfo.isValid()) { const bool isAttached = !propertyName.isEmpty() && propertyName[0].isUpper(); // Only list elements might have unknown properties. - if (!node.metaInfo().isQtQuickListElement() && !isAttached) { - qCInfo(texttomodelMergerDebug) - << Q_FUNC_INFO << "Unknown property" + if (!node.metaInfo().isQtQmlModelsListElement() && !isAttached) { + qCInfo(texttomodelMergerLog) + << Q_FUNC_INFO << "\nUnknown property" << propertyPrefix + QLatin1Char('.') + toString(propertyId) << "on line" << propertyId->identifierToken.startLine << "column" << propertyId->identifierToken.startColumn; @@ -668,6 +561,11 @@ public: //Check for known enum scopes used globally if (isKnownEnumScopes(astValueList.constFirst())) return QVariant::fromValue(Enumeration(astValue)); + } else if (astValueList.size() == 3) { + QString enumName = astValueList.constFirst() + '.' + astValueList.at(1); + if (isKnownEnumScopes(enumName)) + return QVariant::fromValue( + Enumeration(enumName.toUtf8(), astValueList.constLast().toUtf8())); } auto eStmt = AST::cast<AST::ExpressionStatement *>(rhs); @@ -685,9 +583,12 @@ public: return QVariant(); } - +#ifndef QDS_USE_PROJECTSTORAGE const ScopeChain &scopeChain() const - { return m_scopeChain; } + { + return m_scopeChain; + } +#endif QList<DiagnosticMessage> diagnosticLinkMessages() const { return m_diagnosticLinkMessages; } @@ -695,9 +596,11 @@ public: private: Document::Ptr m_doc; QList<DiagnosticMessage> m_diagnosticLinkMessages; +#ifndef QDS_USE_PROJECTSTORAGE ContextPtr m_context; ScopeChain m_scopeChain; ScopeBuilder m_scopeBuilder; +#endif Model *m_model; }; @@ -841,6 +744,7 @@ constexpr auto skipModules = std::make_tuple(EndsWith(u".impl"), Equals(u"QtQuick.Controls.NativeStyle"), Equals(u"QtQuick.Controls.Universal"), Equals(u"QtQuick.Controls.Windows"), + Equals(u"QtQuick3D.MaterialEditor"), StartsWith(u"QtQuick.LocalStorage"), StartsWith(u"QtQuick.NativeStyle"), StartsWith(u"QtQuick.Pdf"), @@ -866,6 +770,7 @@ constexpr auto skipModules = std::make_tuple(EndsWith(u".impl"), StartsWith(u"QtWebSockets"), StartsWith(u"QtWebView")); +#ifndef QDS_USE_PROJECTSTORAGE bool skipModule(QStringView moduleName) { return std::apply([=](const auto &...skipModule) { return (skipModule(moduleName) || ...); }, @@ -931,9 +836,11 @@ QmlDesigner::Imports createQt5Modules() QmlDesigner::Import::createLibraryImport("QtQuick.Studio.MultiText", "1.0"), QmlDesigner::Import::createLibraryImport("Qt.SafeRenderer", "2.0")}; } +#endif } // namespace +#ifndef QDS_USE_PROJECTSTORAGE void TextToModelMerger::setupPossibleImports() { if (!m_rewriterView->possibleImportsEnabled()) @@ -942,10 +849,10 @@ void TextToModelMerger::setupPossibleImports() static QUrl lastProjectUrl; auto &externalDependencies = m_rewriterView->externalDependencies(); auto projectUrl = externalDependencies.projectUrl(); + auto allUsedImports = m_scopeChain->context()->imports(m_document.data())->all(); if (m_possibleModules.isEmpty() || projectUrl != lastProjectUrl) { - auto &externalDependencies = m_rewriterView->externalDependencies(); if (externalDependencies.isQt6Project()) { ModuleScanner moduleScanner{[&](QStringView moduleName) { @@ -975,7 +882,9 @@ void TextToModelMerger::setupPossibleImports() if (m_rewriterView->isAttached()) m_rewriterView->model()->setPossibleImports(modules); } +#endif +#ifndef QDS_USE_PROJECTSTORAGE void TextToModelMerger::setupUsedImports() { const QmlJS::Imports *imports = m_scopeChain->context()->imports(m_document.data()); @@ -1010,6 +919,7 @@ void TextToModelMerger::setupUsedImports() if (m_rewriterView->isAttached()) m_rewriterView->model()->setUsedImports(usedImports); } +#endif Document::MutablePtr TextToModelMerger::createParsedDocument(const QUrl &url, const QString &data, QList<DocumentMessage> *errors) { @@ -1100,15 +1010,16 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH m_vContext = ModelManagerInterface::instance()->projectVContext(Dialect::Qml, m_document); ReadingContext ctxt(snapshot, m_document, m_vContext, m_rewriterView->model()); - m_scopeChain = QSharedPointer<const ScopeChain>( - new ScopeChain(ctxt.scopeChain())); + +#ifndef QDS_USE_PROJECTSTORAGE + m_scopeChain = QSharedPointer<const ScopeChain>(new ScopeChain(ctxt.scopeChain())); if (view()->checkLinkErrors()) { qCInfo(rewriterBenchmark) << "linked:" << time.elapsed(); collectLinkErrors(&errors, ctxt); } - setupPossibleImports(); +#endif qCInfo(rewriterBenchmark) << "possible imports:" << time.elapsed(); @@ -1142,7 +1053,9 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH qCInfo(rewriterBenchmark) << "synced nodes:" << time.elapsed(); +#ifndef QDS_USE_PROJECTSTORAGE setupUsedImports(); +#endif setActive(false); @@ -1239,8 +1152,9 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, else if (!modelNode.nodeSource().isEmpty() || modelNode.nodeSourceType() != ModelNode::NodeWithoutSource) clearImplicitComponentDelayed(modelNode, differenceHandler.isAmender()); - +#ifndef QDS_USE_PROJECTSTORAGE context->enterScope(astNode); +#endif QSet<PropertyName> modelPropertyNames = Utils::toSet(modelNode.propertyNames()); if (!modelNode.id().isEmpty()) @@ -1254,7 +1168,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, if (auto array = AST::cast<AST::UiArrayBinding *>(member)) { const QString astPropertyName = toString(array->qualifiedId); - if (isPropertyChangesType(typeName) || isConnectionsType(typeName) || context->lookupProperty(QString(), array->qualifiedId)) { + if (isPropertyChangesType(typeName) || isConnectionsType(typeName) + || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) { AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); QList<AST::UiObjectMember *> arrayMembers; for (AST::UiArrayMemberList *iter = array->members; iter; iter = iter->next) @@ -1286,13 +1201,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, // Store Behaviours in the default property defaultPropertyItems.append(member); } else { - const Value *propertyType = nullptr; - const ObjectValue *containingObject = nullptr; - if (context->lookupProperty({}, - binding->qualifiedId, - &propertyType, - &containingObject) - || isPropertyChangesType(typeName) || isConnectionsType(typeName)) { + if (isPropertyChangesType(typeName) || isConnectionsType(typeName) + || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) { AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); if (context->isArrayProperty(modelProperty)) syncArrayProperty(modelProperty, {member}, context, differenceHandler); @@ -1396,7 +1306,9 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, differenceHandler.propertyAbsentFromQml(modelProperty); } +#ifndef QDS_USE_PROJECTSTORAGE context->leaveScope(); +#endif } static QVariant parsePropertyExpression(AST::ExpressionNode *expressionNode) @@ -1476,9 +1388,8 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN } if (isLiteralValue(script)) { - if (isPropertyChangesType(modelNode.type()) - || isConnectionsType(modelNode.type()) - || isListElementType(modelNode.type())) { + if (isPropertyChangesType(modelNode.type()) || isConnectionsType(modelNode.type()) + || isListElementType(modelNode.type())) { AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); QVariant variantValue = parsePropertyScriptBinding(script); if (!variantValue.isValid()) @@ -1512,15 +1423,14 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN syncVariantProperty(modelProperty, enumValue, TypeName(), differenceHandler); // TODO: parse type return astPropertyName.toUtf8(); } else { // Not an enum, so: - if (isPropertyChangesType(modelNode.type()) - || isConnectionsType(modelNode.type()) - || context->lookupProperty(prefix, script->qualifiedId) - || isSupportedAttachedProperties(astPropertyName)) { + if (isPropertyChangesType(modelNode.type()) || isConnectionsType(modelNode.type()) + || isSupportedAttachedProperties(astPropertyName) + || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) { AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); syncExpressionProperty(modelProperty, astValue, TypeName(), differenceHandler); // TODO: parse type return astPropertyName.toUtf8(); } else { - qWarning() << Q_FUNC_INFO << "Skipping invalid expression property" << astPropertyName + qCInfo(texttomodelMergerLog) << Q_FUNC_INFO << "\nSkipping invalid expression property" << astPropertyName << "for node type" << modelNode.type(); return PropertyName(); } @@ -1655,7 +1565,7 @@ void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty, const TypeName &astType, DifferenceHandler &differenceHandler) { - if (astValue.canConvert(QMetaType::QString)) + if (astValue.canConvert(QMetaType(QMetaType::QString))) populateQrcMapping(astValue.toString()); if (modelProperty.isVariantProperty()) { @@ -2232,42 +2142,31 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors) bool hasQtQuick = false; for (const QmlDesigner::Import &import : m_rewriterView->model()->imports()) { if (import.isLibraryImport() && import.url() == u"QtQuick") { - if (supportedQtQuickVersion(import)) { - hasQtQuick = true; - - auto &externalDependencies = m_rewriterView->externalDependencies(); - if (externalDependencies.hasStartupTarget()) { - const bool qt6import = !import.hasVersion() || import.majorVersion() == 6; - - if (!externalDependencies.isQt6Import() && (m_hasVersionlessImport || qt6import)) { - const QmlJS::DiagnosticMessage diagnosticMessage( - QmlJS::Severity::Error, - SourceLocation(0, 0, 0, 0), - QCoreApplication::translate( - "QmlDesigner::TextToModelMerger", - "Qt Quick 6 is not supported with a Qt 5 kit.")); - errors->prepend( - DocumentMessage(diagnosticMessage, - QUrl::fromLocalFile(m_document->fileName().path()))); - } - } else { + hasQtQuick = true; + + auto &externalDependencies = m_rewriterView->externalDependencies(); + if (externalDependencies.hasStartupTarget()) { + const bool qt6import = !import.hasVersion() || import.majorVersion() == 6; + + if (!externalDependencies.isQt6Import() && (m_hasVersionlessImport || qt6import)) { const QmlJS::DiagnosticMessage diagnosticMessage( QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), - QCoreApplication::translate("QmlDesigner::TextToModelMerger", - "The Design Mode requires a valid Qt kit.")); + QCoreApplication::translate( + "QmlDesigner::TextToModelMerger", + "Qt Quick 6 is not supported with a Qt 5 kit.")); errors->prepend( DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName().path()))); } } else { - const QmlJS::DiagnosticMessage - diagnosticMessage(QmlJS::Severity::Error, - SourceLocation(0, 0, 0, 0), - QCoreApplication::translate("QmlDesigner::TextToModelMerger", - "Unsupported Qt Quick version.")); - errors->append(DocumentMessage(diagnosticMessage, - QUrl::fromLocalFile(m_document->fileName().path()))); + const QmlJS::DiagnosticMessage diagnosticMessage( + QmlJS::Severity::Error, + SourceLocation(0, 0, 0, 0), + QCoreApplication::translate("QmlDesigner::TextToModelMerger", + "The Design Mode requires a valid Qt kit.")); + errors->prepend(DocumentMessage(diagnosticMessage, + QUrl::fromLocalFile(m_document->fileName().path()))); } } } @@ -2276,8 +2175,10 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors) errors->append(DocumentMessage(QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import for Qt Quick found."))); } -void TextToModelMerger::collectSemanticErrorsAndWarnings(QList<DocumentMessage> *errors, QList<DocumentMessage> *warnings) +void TextToModelMerger::collectSemanticErrorsAndWarnings( + [[maybe_unused]] QList<DocumentMessage> *errors, [[maybe_unused]] QList<DocumentMessage> *warnings) { +#ifndef QDS_USE_PROJECTSTORAGE Check check(m_document, m_scopeChain->context()); check.disableMessage(StaticAnalysis::ErrPrototypeCycle); check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototype); @@ -2306,6 +2207,7 @@ void TextToModelMerger::collectSemanticErrorsAndWarnings(QList<DocumentMessage> if (message.severity == Severity::Warning) warnings->append(DocumentMessage(message.toDiagnosticMessage(), fileNameUrl)); } +#endif } void TextToModelMerger::populateQrcMapping(const QString &filePath) @@ -2410,6 +2312,9 @@ QSet<QPair<QString, QString> > TextToModelMerger::qrcMapping() const QList<QmlTypeData> TextToModelMerger::getQMLSingletons() const { +#ifdef QDS_USE_PROJECTSTORAGE + return {}; +#else QList<QmlTypeData> list; if (!m_scopeChain || !m_scopeChain->document()) return list; @@ -2440,6 +2345,7 @@ QList<QmlTypeData> TextToModelMerger::getQMLSingletons() const } } return list; +#endif } void TextToModelMerger::clearPossibleImportKeys() diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h index f511906040..e22f747718 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h @@ -37,15 +37,19 @@ public: bool isActive() const; void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler); +#ifndef QDS_USE_PROJECTSTORAGE void setupPossibleImports(); +#endif void setupUsedImports(); bool load(const QString &data, DifferenceHandler &differenceHandler); RewriterView *view() const { return m_rewriterView; } +#ifndef QDS_USE_PROJECTSTORAGE const QmlJS::ScopeChain *scopeChain() const { return m_scopeChain.data(); } +#endif const QmlJS::Document *document() const { return m_document.data(); } @@ -141,7 +145,9 @@ private: private: RewriterView *m_rewriterView; bool m_isActive; +#ifndef QDS_USE_PROJECTSTORAGE QSharedPointer<const QmlJS::ScopeChain> m_scopeChain; +#endif QmlJS::Document::Ptr m_document; QTimer m_setupTimer; QSet<ModelNode> m_setupComponentList; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h index 03c25dfac7..76305b1fbe 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h @@ -84,16 +84,15 @@ inline constexpr char PrincipledMaterial[] = "PrincipledMaterial"; inline constexpr char PropertyAnimation[] = "PropertyAnimation"; inline constexpr char PropertyChanges[] = "PropertyChanges"; inline constexpr char QML[] = "QML"; -inline constexpr char QML_cppnative[] = "QML-cppnative"; inline constexpr char QQuick3DParticleAbstractShape[] = "QQuick3DParticleAbstractShape"; inline constexpr char QQuickStateOperation[] = "QQuickStateOperation"; inline constexpr char QtMultimedia[] = "QtMultimedia"; inline constexpr char QtObject[] = "QtObject"; inline constexpr char QtQml[] = "QtQml"; inline constexpr char QtQml_Models[] = "QtQml.Models"; +inline constexpr char QtQml_XmlListModel[] = "QtQml.XmlListModel"; inline constexpr char QtQuick3D[] = "QtQuick3D"; inline constexpr char QtQuick3D_Particles3D[] = "QtQuick3D.Particles3D"; -inline constexpr char QtQuick3D_Particles3D_cppnative[] = "QtQuick3D.Particles3D-cppnative"; inline constexpr char QtQuick[] = "QtQuick"; inline constexpr char QtQuick_Controls[] = "QtQuick.Controls"; inline constexpr char QtQuick_Dialogs[] = "QtQuick.Dialogs"; @@ -103,7 +102,6 @@ inline constexpr char QtQuick_Studio_Components[] = "QtQuick.Studio.Components"; inline constexpr char QtQuick_Templates[] = "QtQuick.Templates"; inline constexpr char QtQuick_Timeline[] = "QtQuick.Timeline"; inline constexpr char QtQuick_Window[] = "QtQuick.Window"; -inline constexpr char QtQuick_cppnative[] = "QtQuick-cppnative"; inline constexpr char Qt_SafeRenderer[] = "Qt.SafeRenderer"; inline constexpr char Rectangle[] = "Rectangle"; inline constexpr char Repeater[] = "Repeater"; @@ -131,6 +129,7 @@ inline constexpr char Transition[] = "Transition"; inline constexpr char UIntType[] = "uint"; inline constexpr char View3D[] = "View3D"; inline constexpr char Window[] = "Window"; +inline constexpr char XmlListModelRole[] = "XmlListModelRole"; inline constexpr char color[] = "color"; inline constexpr char date[] = "date"; inline constexpr char font[] = "font"; @@ -147,7 +146,7 @@ struct BaseCacheType QmlDesigner::TypeId typeId; }; -template<const char *moduleName_, const char *typeName_> +template<const char *moduleName_, ModuleKind moduleKind, const char *typeName_> struct CacheType : public BaseCacheType { }; @@ -155,105 +154,107 @@ struct CacheType : public BaseCacheType template<typename ProjectStorage> class CommonTypeCache { - using CommonTypes = std::tuple<CacheType<FlowView, FlowActionArea>, - CacheType<FlowView, FlowDecision>, - CacheType<FlowView, FlowItem>, - CacheType<FlowView, FlowTransition>, - CacheType<FlowView, FlowView>, - CacheType<FlowView, FlowWildcard>, - CacheType<QML, BoolType>, - CacheType<QML, Component>, - CacheType<QML, DoubleType>, - CacheType<QML, IntType>, - CacheType<QML, QtObject>, - CacheType<QML, date>, - CacheType<QML, string>, - CacheType<QML, url>, - CacheType<QML, var>, - CacheType<QML_cppnative, FloatType>, - CacheType<QML_cppnative, UIntType>, - CacheType<QtQml, Connections>, - CacheType<QtMultimedia, SoundEffect>, - CacheType<QtQml_Models, ListElement>, - CacheType<QtQml_Models, ListModel>, - CacheType<QtQuick, BorderImage>, - CacheType<QtQuick, GridView>, - CacheType<QtQuick, Image>, - CacheType<QtQuick, Item>, - CacheType<QtQuick, ListView>, - CacheType<QtQuick, Loader>, - CacheType<QtQuick, MouseArea>, - CacheType<QtQuick, Path>, - CacheType<QtQuick, PathView>, - CacheType<QtQuick, PauseAnimation>, - CacheType<QtQuick, Positioner>, - CacheType<QtQuick, PropertyAnimation>, - CacheType<QtQuick, PropertyChanges>, - CacheType<QtQuick, Rectangle>, - CacheType<QtQuick, Repeater>, - CacheType<QtQuick, State>, - CacheType<QtQuick, StateGroup>, - CacheType<QtQuick, Text>, - CacheType<QtQuick, TextEdit>, - CacheType<QtQuick, Transition>, - CacheType<QtQuick, color>, - CacheType<QtQuick, font>, - CacheType<QtQuick, vector2d>, - CacheType<QtQuick, vector3d>, - CacheType<QtQuick, vector4d>, - CacheType<QtQuick3D, BakedLightmap>, - CacheType<QtQuick3D, Buffer>, - CacheType<QtQuick3D, Camera>, - CacheType<QtQuick3D, Command>, - CacheType<QtQuick3D, CubeMapTexture>, - CacheType<QtQuick3D, DefaultMaterial>, - CacheType<QtQuick3D, DirectionalLight>, - CacheType<QtQuick3D, Effect>, - CacheType<QtQuick3D, InstanceList>, - CacheType<QtQuick3D, InstanceListEntry>, - CacheType<QtQuick3D, Light>, - CacheType<QtQuick3D, Material>, - CacheType<QtQuick3D, Model>, - CacheType<QtQuick3D, Node>, - CacheType<QtQuick3D, OrthographicCamera>, - CacheType<QtQuick3D, Pass>, - CacheType<QtQuick3D, PerspectiveCamera>, - CacheType<QtQuick3D, PointLight>, - CacheType<QtQuick3D, PrincipledMaterial>, - CacheType<QtQuick3D, SceneEnvironment>, - CacheType<QtQuick3D, Shader>, - CacheType<QtQuick3D, SpecularGlossyMaterial>, - CacheType<QtQuick3D, SpotLight>, - CacheType<QtQuick3D, Texture>, - CacheType<QtQuick3D, TextureInput>, - CacheType<QtQuick3D, View3D>, - CacheType<QtQuick3D_Particles3D, Affector3D>, - CacheType<QtQuick3D_Particles3D, Attractor3D>, - CacheType<QtQuick3D_Particles3D, Model>, - CacheType<QtQuick3D_Particles3D, Particle3D>, - CacheType<QtQuick3D_Particles3D, ParticleEmitter3D>, - CacheType<QtQuick3D_Particles3D, SpriteParticle3D>, - CacheType<QtQuick3D_Particles3D_cppnative, QQuick3DParticleAbstractShape>, - CacheType<QtQuick_Controls, Control>, - CacheType<QtQuick_Controls, Popup>, - CacheType<QtQuick_Controls, SplitView>, - CacheType<QtQuick_Controls, SwipeView>, - CacheType<QtQuick_Controls, TabBar>, - CacheType<QtQuick_Controls, TextArea>, - CacheType<QtQuick_Dialogs, Dialog>, - CacheType<QtQuick_Extras, Picture>, - CacheType<QtQuick_Layouts, Layout>, - CacheType<QtQuick_Studio_Components, GroupItem>, - CacheType<QtQuick_Studio_Components, JsonListModel>, - CacheType<QtQuick_Templates, Control>, - CacheType<QtQuick_Timeline, Keyframe>, - CacheType<QtQuick_Timeline, KeyframeGroup>, - CacheType<QtQuick_Timeline, Timeline>, - CacheType<QtQuick_Timeline, TimelineAnimation>, - CacheType<QtQuick_cppnative, QQuickStateOperation>, - CacheType<Qt_SafeRenderer, SafePicture>, - CacheType<Qt_SafeRenderer, SafeRendererPicture>, - CacheType<QtQuick_Window, Window>>; + using CommonTypes = std::tuple< + CacheType<FlowView, ModuleKind::QmlLibrary, FlowActionArea>, + CacheType<FlowView, ModuleKind::QmlLibrary, FlowDecision>, + CacheType<FlowView, ModuleKind::QmlLibrary, FlowItem>, + CacheType<FlowView, ModuleKind::QmlLibrary, FlowTransition>, + CacheType<FlowView, ModuleKind::QmlLibrary, FlowView>, + CacheType<FlowView, ModuleKind::QmlLibrary, FlowWildcard>, + CacheType<QML, ModuleKind::QmlLibrary, BoolType>, + CacheType<QML, ModuleKind::QmlLibrary, Component>, + CacheType<QML, ModuleKind::QmlLibrary, DoubleType>, + CacheType<QML, ModuleKind::QmlLibrary, IntType>, + CacheType<QML, ModuleKind::QmlLibrary, QtObject>, + CacheType<QML, ModuleKind::QmlLibrary, date>, + CacheType<QML, ModuleKind::QmlLibrary, string>, + CacheType<QML, ModuleKind::QmlLibrary, url>, + CacheType<QML, ModuleKind::QmlLibrary, var>, + CacheType<QML, ModuleKind::CppLibrary, FloatType>, + CacheType<QML, ModuleKind::CppLibrary, UIntType>, + CacheType<QtQml, ModuleKind::QmlLibrary, Connections>, + CacheType<QtMultimedia, ModuleKind::QmlLibrary, SoundEffect>, + CacheType<QtQml_Models, ModuleKind::QmlLibrary, ListElement>, + CacheType<QtQml_Models, ModuleKind::QmlLibrary, ListModel>, + CacheType<QtQml_XmlListModel, ModuleKind::QmlLibrary, XmlListModelRole>, + CacheType<QtQuick, ModuleKind::QmlLibrary, BorderImage>, + CacheType<QtQuick, ModuleKind::QmlLibrary, GridView>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Image>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Item>, + CacheType<QtQuick, ModuleKind::QmlLibrary, ListView>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Loader>, + CacheType<QtQuick, ModuleKind::QmlLibrary, MouseArea>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Path>, + CacheType<QtQuick, ModuleKind::QmlLibrary, PathView>, + CacheType<QtQuick, ModuleKind::QmlLibrary, PauseAnimation>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Positioner>, + CacheType<QtQuick, ModuleKind::QmlLibrary, PropertyAnimation>, + CacheType<QtQuick, ModuleKind::QmlLibrary, PropertyChanges>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Rectangle>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Repeater>, + CacheType<QtQuick, ModuleKind::QmlLibrary, State>, + CacheType<QtQuick, ModuleKind::QmlLibrary, StateGroup>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Text>, + CacheType<QtQuick, ModuleKind::QmlLibrary, TextEdit>, + CacheType<QtQuick, ModuleKind::QmlLibrary, Transition>, + CacheType<QtQuick, ModuleKind::QmlLibrary, color>, + CacheType<QtQuick, ModuleKind::QmlLibrary, font>, + CacheType<QtQuick, ModuleKind::QmlLibrary, vector2d>, + CacheType<QtQuick, ModuleKind::QmlLibrary, vector3d>, + CacheType<QtQuick, ModuleKind::QmlLibrary, vector4d>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, BakedLightmap>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Buffer>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Camera>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Command>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, CubeMapTexture>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, DefaultMaterial>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, DirectionalLight>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Effect>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, InstanceList>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, InstanceListEntry>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Light>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Material>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Model>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Node>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, OrthographicCamera>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Pass>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, PerspectiveCamera>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, PointLight>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, PrincipledMaterial>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, SceneEnvironment>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Shader>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, SpecularGlossyMaterial>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, SpotLight>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, Texture>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, TextureInput>, + CacheType<QtQuick3D, ModuleKind::QmlLibrary, View3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Affector3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Attractor3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Model>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Particle3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, ParticleEmitter3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, SpriteParticle3D>, + CacheType<QtQuick3D_Particles3D, ModuleKind::CppLibrary, QQuick3DParticleAbstractShape>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, Control>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, Popup>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, SplitView>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, SwipeView>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, TabBar>, + CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, TextArea>, + CacheType<QtQuick_Dialogs, ModuleKind::QmlLibrary, Dialog>, + CacheType<QtQuick_Extras, ModuleKind::QmlLibrary, Picture>, + CacheType<QtQuick_Layouts, ModuleKind::QmlLibrary, Layout>, + CacheType<QtQuick_Studio_Components, ModuleKind::QmlLibrary, GroupItem>, + CacheType<QtQuick_Studio_Components, ModuleKind::QmlLibrary, JsonListModel>, + CacheType<QtQuick_Templates, ModuleKind::QmlLibrary, Control>, + CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, Keyframe>, + CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, KeyframeGroup>, + CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, Timeline>, + CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, TimelineAnimation>, + CacheType<QtQuick, ModuleKind::CppLibrary, QQuickStateOperation>, + CacheType<Qt_SafeRenderer, ModuleKind::QmlLibrary, SafePicture>, + CacheType<Qt_SafeRenderer, ModuleKind::QmlLibrary, SafeRendererPicture>, + CacheType<QtQuick_Window, ModuleKind::QmlLibrary, Window>>; public: CommonTypeCache(const ProjectStorage &projectStorage) @@ -280,14 +281,14 @@ public: std::fill(std::begin(m_typesWithoutProperties), std ::end(m_typesWithoutProperties), TypeId{}); } - template<const char *moduleName, const char *typeName> + template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary> TypeId typeId() const { - auto &type = std::get<CacheType<moduleName, typeName>>(m_types); + auto &type = std::get<CacheType<moduleName, moduleKind, typeName>>(m_types); if (type.typeId) return type.typeId; - return refreshTypedId(type, moduleName, typeName); + return refreshTypedId(type, moduleName, moduleKind, typeName); } template<const char *typeName> @@ -304,11 +305,11 @@ public: else if constexpr (std::is_same_v<Type, int>) return typeId<QML, IntType>(); else if constexpr (std::is_same_v<Type, uint>) - return typeId<QML_cppnative, UIntType>(); + return typeId<QML, UIntType, ModuleKind::CppLibrary>(); else if constexpr (std::is_same_v<Type, bool>) return typeId<QML, BoolType>(); else if constexpr (std::is_same_v<Type, float>) - return typeId<QML_cppnative, FloatType>(); + return typeId<QML, FloatType, ModuleKind::CppLibrary>(); else if constexpr (std::is_same_v<Type, QString>) return typeId<QML, string>(); else if constexpr (std::is_same_v<Type, QDateTime>) @@ -338,10 +339,11 @@ public: private: TypeId refreshTypedId(BaseCacheType &type, ::Utils::SmallStringView moduleName, + ModuleKind moduleKind, ::Utils::SmallStringView typeName) const { if (!type.moduleId) - type.moduleId = m_projectStorage.moduleId(moduleName); + type.moduleId = m_projectStorage.moduleId(moduleName, moduleKind); type.typeId = m_projectStorage.typeId(type.moduleId, typeName, Storage::Version{}); @@ -350,10 +352,11 @@ private: TypeId refreshTypedIdWithoutTransaction(BaseCacheType &type, ::Utils::SmallStringView moduleName, - ::Utils::SmallStringView typeName) const + ::Utils::SmallStringView typeName, + ModuleKind moduleKind) const { if (!type.moduleId) - type.moduleId = m_projectStorage.fetchModuleIdUnguarded(moduleName); + type.moduleId = m_projectStorage.fetchModuleIdUnguarded(moduleName, moduleKind); type.typeId = m_projectStorage.fetchTypeIdByModuleIdAndExportedName(type.moduleId, typeName); @@ -368,26 +371,27 @@ private: std::copy(std::begin(typeIds), std::end(typeIds), std::begin(m_typesWithoutProperties)); } - template<const char *moduleName, const char *typeName> + template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary> TypeId typeIdWithoutTransaction() const { - auto &type = std::get<CacheType<moduleName, typeName>>(m_types); + auto &type = std::get<CacheType<moduleName, moduleKind, typeName>>(m_types); if (type.typeId) return type.typeId; - return refreshTypedIdWithoutTransaction(type, moduleName, typeName); + return refreshTypedIdWithoutTransaction(type, moduleName, typeName, moduleKind); } void updateTypeIdsWithoutProperties() { - setupTypeIdsWithoutProperties({typeIdWithoutTransaction<QML, BoolType>(), - typeIdWithoutTransaction<QML, IntType>(), - typeIdWithoutTransaction<QML_cppnative, UIntType>(), - typeIdWithoutTransaction<QML, DoubleType>(), - typeIdWithoutTransaction<QML_cppnative, FloatType>(), - typeIdWithoutTransaction<QML, date>(), - typeIdWithoutTransaction<QML, string>(), - typeIdWithoutTransaction<QML, url>()}); + setupTypeIdsWithoutProperties( + {typeIdWithoutTransaction<QML, BoolType>(), + typeIdWithoutTransaction<QML, IntType>(), + typeIdWithoutTransaction<QML, UIntType, ModuleKind::CppLibrary>(), + typeIdWithoutTransaction<QML, DoubleType>(), + typeIdWithoutTransaction<QML, FloatType, ModuleKind::CppLibrary>(), + typeIdWithoutTransaction<QML, date>(), + typeIdWithoutTransaction<QML, string>(), + typeIdWithoutTransaction<QML, url>()}); } private: diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h b/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h index f3e275b8f3..48b3ba2700 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h @@ -50,6 +50,18 @@ public: explicit operator bool() const { return isValid(); } + template<typename String> + friend void convertToString(String &string, const FileStatus &fileStatus) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("source id", fileStatus.sourceId), + keyValue("size", fileStatus.size), + keyValue("last modified", fileStatus.lastModified)); + + convertToString(string, dict); + } + public: SourceId sourceId; long long size = -1; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp index 1376b2c3d9..d11190fdc7 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp @@ -11,6 +11,7 @@ #include <QDateTime> #include <QDir> +#include <QDirIterator> #include <QFileInfo> namespace QmlDesigner { @@ -69,6 +70,18 @@ QString FileSystem::contentAsQString(const QString &filePath) const return {}; } +QStringList FileSystem::subdirectories(const QString &directoryPath) const +{ + QStringList directoryPaths; + directoryPaths.reserve(100); + QDirIterator directoryIterator{directoryPath, QDir::Dirs | QDir::NoDotAndDotDot}; + + while (directoryIterator.hasNext()) + directoryPaths.push_back(directoryIterator.next()); + + return directoryPaths; +} + void FileSystem::remove(const SourceIds &sourceIds) { for (SourceId sourceId : sourceIds) diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h index 078fd1ee98..1c881741c6 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h @@ -6,6 +6,7 @@ #include "filestatuscache.h" #include "filesysteminterface.h" #include "nonlockingmutex.h" +#include "projectstoragefwd.h" namespace Sqlite { class Database; @@ -16,12 +17,9 @@ namespace QmlDesigner { template<typename ProjectStorage, typename Mutex> class SourcePathCache; -template<typename Database> -class ProjectStorage; - class FileSystem : public FileSystemInterface { - using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>; + using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>; public: FileSystem(PathCache &sourcePathCache) @@ -33,6 +31,7 @@ public: long long lastModified(SourceId sourceId) const override; FileStatus fileStatus(SourceId sourceId) const override; QString contentAsQString(const QString &filePath) const override; + QStringList subdirectories(const QString &directoryPath) const override; void remove(const SourceIds &sourceIds) override; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h b/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h index 6a7c964fa6..ff7608c9a3 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h @@ -20,6 +20,7 @@ public: virtual FileStatus fileStatus(SourceId sourceId) const = 0; virtual void remove(const SourceIds &sourceIds) = 0; virtual QString contentAsQString(const QString &filePath) const = 0; + virtual QStringList subdirectories(const QString &directoryPath) const = 0; protected: ~FileSystemInterface() = default; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp index 3e493e8772..2283b64945 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp @@ -3,20 +3,4896 @@ #include "projectstorage.h" -#include <tracing/qmldesignertracing.h> - #include <sqlitedatabase.h> namespace QmlDesigner { -NanotraceHR::StringViewCategory<projectStorageTracingStatus()> &projectStorageCategory() +enum class SpecialIdState { Unresolved = -1 }; + +constexpr TypeId unresolvedTypeId = TypeId::createSpecialState(SpecialIdState::Unresolved); + +class UnresolvedTypeId : public TypeId +{ +public: + constexpr UnresolvedTypeId() + : TypeId{TypeId::createSpecialState(SpecialIdState::Unresolved)} + {} + + static constexpr UnresolvedTypeId create(DatabaseType idNumber) + { + UnresolvedTypeId id; + id.id = idNumber; + return id; + } +}; + +struct ProjectStorage::Statements { - thread_local NanotraceHR::StringViewCategory<projectStorageTracingStatus()> - projectStorageCategory_{"project storage"_t, Tracing::eventQueue(), projectStorageCategory}; + Statements(Sqlite::Database &database) + : database{database} + {} + + Sqlite::Database &database; + Sqlite::ReadWriteStatement<1, 2> insertTypeStatement{ + "INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database}; + Sqlite::WriteStatement<5> updatePrototypeAndExtensionStatement{ + "UPDATE types " + "SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 " + "WHERE typeId=?1 AND ( " + " prototypeId IS NOT ?2 " + " OR extensionId IS NOT ?3 " + " OR prototypeId IS NOT ?4 " + " OR extensionNameId IS NOT ?5)", + database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIdByExportedNameStatement{ + "SELECT typeId FROM exportedTypeNames WHERE name=?1", database}; + mutable Sqlite::ReadStatement<1, 2> selectTypeIdByModuleIdAndExportedNameStatement{ + "SELECT typeId FROM exportedTypeNames " + "WHERE moduleId=?1 AND name=?2 " + "ORDER BY majorVersion DESC, minorVersion DESC " + "LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 3> selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement{ + "SELECT typeId FROM exportedTypeNames " + "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3" + "ORDER BY minorVersion DESC " + "LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 4> selectTypeIdByModuleIdAndExportedNameAndVersionStatement{ + "SELECT typeId FROM exportedTypeNames " + "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3 AND minorVersion<=?4" + "ORDER BY minorVersion DESC " + "LIMIT 1", + database}; + mutable Sqlite::ReadStatement<3, 1> selectPropertyDeclarationResultByPropertyDeclarationIdStatement{ + "SELECT propertyTypeId, propertyDeclarationId, propertyTraits " + "FROM propertyDeclarations " + "WHERE propertyDeclarationId=?1 " + "LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{ + "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database}; + mutable Sqlite::ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{ + "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database}; + mutable Sqlite::ReadStatement<2> selectAllSourceContextsStatement{ + "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database}; + Sqlite::WriteStatement<1> insertIntoSourceContextsStatement{ + "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database}; + mutable Sqlite::ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{ + "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database}; + mutable Sqlite::ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{ + "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database}; + mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{ + "SELECT sourceContextId FROM sources WHERE sourceId = ?", database}; + Sqlite::WriteStatement<2> insertIntoSourcesStatement{ + "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; + mutable Sqlite::ReadStatement<3> selectAllSourcesStatement{ + "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; + mutable Sqlite::ReadStatement<8, 1> selectTypeByTypeIdStatement{ + "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " + "pd.name " + "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON " + "defaultPropertyId=propertyDeclarationId " + "WHERE t.typeId=?", + database}; + mutable Sqlite::ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{ + "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " + "exportedTypeNames WHERE typeId=?", + database}; + mutable Sqlite::ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{ + "SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) " + "FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND " + "sourceId=?2", + database}; + mutable Sqlite::ReadStatement<8> selectTypesStatement{ + "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " + "pd.name " + "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON " + "defaultPropertyId=propertyDeclarationId", + database}; + Sqlite::WriteStatement<2> updateTypeTraitStatement{ + "UPDATE types SET traits = ?2 WHERE typeId=?1", database}; + Sqlite::WriteStatement<2> updateTypeAnnotationTraitStatement{ + "WITH RECURSIVE " + " typeSelection(typeId) AS (" + " VALUES(?1) " + " UNION ALL " + " SELECT t.typeId " + " FROM types AS t JOIN typeSelection AS ts " + " WHERE prototypeId=ts.typeId " + " AND t.typeId NOT IN (SELECT typeId FROM typeAnnotations)) " + "UPDATE types AS t " + "SET annotationTraits = ?2 " + "FROM typeSelection ts " + "WHERE t.typeId=ts.typeId", + database}; + Sqlite::ReadStatement<1, 2> selectNotUpdatedTypesInSourcesStatement{ + "SELECT DISTINCT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN " + "carray(?2))", + database}; + Sqlite::WriteStatement<1> deleteTypeNamesByTypeIdStatement{ + "DELETE FROM exportedTypeNames WHERE typeId=?", database}; + Sqlite::WriteStatement<1> deleteEnumerationDeclarationByTypeIdStatement{ + "DELETE FROM enumerationDeclarations WHERE typeId=?", database}; + Sqlite::WriteStatement<1> deletePropertyDeclarationByTypeIdStatement{ + "DELETE FROM propertyDeclarations WHERE typeId=?", database}; + Sqlite::WriteStatement<1> deleteFunctionDeclarationByTypeIdStatement{ + "DELETE FROM functionDeclarations WHERE typeId=?", database}; + Sqlite::WriteStatement<1> deleteSignalDeclarationByTypeIdStatement{ + "DELETE FROM signalDeclarations WHERE typeId=?", database}; + Sqlite::WriteStatement<1> deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; + mutable Sqlite::ReadStatement<4, 1> selectPropertyDeclarationsByTypeIdStatement{ + "SELECT name, propertyTypeId, propertyTraits, (SELECT name FROM " + "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM " + "propertyDeclarations AS pd WHERE typeId=?", + database}; + Sqlite::ReadStatement<6, 1> selectPropertyDeclarationsForTypeIdStatement{ + "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, " + "propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " + "WHERE typeId=? ORDER BY name", + database}; + Sqlite::ReadWriteStatement<1, 5> insertPropertyDeclarationStatement{ + "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, " + "propertyImportedTypeNameId, aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5, NULL) " + "RETURNING propertyDeclarationId", + database}; + Sqlite::WriteStatement<4> updatePropertyDeclarationStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " + "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=NULL WHERE " + "propertyDeclarationId=?1", + database}; + Sqlite::WriteStatement<3> updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{ + "WITH RECURSIVE " + " properties(aliasPropertyDeclarationId) AS ( " + " SELECT propertyDeclarationId FROM propertyDeclarations WHERE " + " aliasPropertyDeclarationId=?1 " + " UNION ALL " + " SELECT pd.propertyDeclarationId FROM " + " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) " + "UPDATE propertyDeclarations AS pd " + "SET propertyTypeId=?2, propertyTraits=?3 " + "FROM properties AS p " + "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", + database}; + Sqlite::WriteStatement<1> updatePropertyAliasDeclarationRecursivelyStatement{ + "WITH RECURSIVE " + " propertyValues(propertyTypeId, propertyTraits) AS (" + " SELECT propertyTypeId, propertyTraits FROM propertyDeclarations " + " WHERE propertyDeclarationId=?1), " + " properties(aliasPropertyDeclarationId) AS ( " + " SELECT propertyDeclarationId FROM propertyDeclarations WHERE " + " aliasPropertyDeclarationId=?1 " + " UNION ALL " + " SELECT pd.propertyDeclarationId FROM " + " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) " + "UPDATE propertyDeclarations AS pd " + "SET propertyTypeId=pv.propertyTypeId, propertyTraits=pv.propertyTraits " + "FROM properties AS p, propertyValues AS pv " + "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", + database}; + Sqlite::WriteStatement<1> deletePropertyDeclarationStatement{ + "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; + Sqlite::ReadStatement<3, 1> selectPropertyDeclarationsWithAliasForTypeIdStatement{ + "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " + "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name", + database}; + Sqlite::WriteStatement<5> updatePropertyDeclarationWithAliasAndTypeStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " + "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=?5 WHERE " + "propertyDeclarationId=?1", + database}; + Sqlite::ReadWriteStatement<1, 2> insertAliasPropertyDeclarationStatement{ + "INSERT INTO propertyDeclarations(typeId, name) VALUES(?1, ?2) RETURNING " + "propertyDeclarationId", + database}; + mutable Sqlite::ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{ + "SELECT name, returnTypeName, signature, functionDeclarationId FROM " + "functionDeclarations WHERE typeId=? ORDER BY name, signature", + database}; + mutable Sqlite::ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{ + "SELECT name, returnTypeName, functionDeclarationId FROM " + "functionDeclarations WHERE typeId=? ORDER BY name", + database}; + mutable Sqlite::ReadStatement<3, 1> selectFunctionParameterDeclarationsStatement{ + "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " + "json_extract(json_each.value, '$.tr') FROM functionDeclarations, " + "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?", + database}; + Sqlite::WriteStatement<4> insertFunctionDeclarationStatement{ + "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, " + "?3, ?4)", + database}; + Sqlite::WriteStatement<3> updateFunctionDeclarationStatement{ + "UPDATE functionDeclarations " + "SET returnTypeName=?2, signature=?3 " + "WHERE functionDeclarationId=?1", + database}; + Sqlite::WriteStatement<1> deleteFunctionDeclarationStatement{ + "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database}; + mutable Sqlite::ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{ + "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER " + "BY name, signature", + database}; + mutable Sqlite::ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{ + "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name", + database}; + mutable Sqlite::ReadStatement<3, 1> selectSignalParameterDeclarationsStatement{ + "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " + "json_extract(json_each.value, '$.tr') FROM signalDeclarations, " + "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?", + database}; + Sqlite::WriteStatement<3> insertSignalDeclarationStatement{ + "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database}; + Sqlite::WriteStatement<2> updateSignalDeclarationStatement{ + "UPDATE signalDeclarations SET signature=?2 WHERE signalDeclarationId=?1", database}; + Sqlite::WriteStatement<1> deleteSignalDeclarationStatement{ + "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database}; + mutable Sqlite::ReadStatement<3, 1> selectEnumerationDeclarationsForTypeIdStatement{ + "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM " + "enumerationDeclarations WHERE typeId=? ORDER BY name", + database}; + mutable Sqlite::ReadStatement<2, 1> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{ + "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER " + "BY name", + database}; + mutable Sqlite::ReadStatement<3, 1> selectEnumeratorDeclarationStatement{ + "SELECT json_each.key, json_each.value, json_each.type!='null' FROM " + "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE " + "enumerationDeclarationId=?", + database}; + Sqlite::WriteStatement<3> insertEnumerationDeclarationStatement{ + "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, " + "?3)", + database}; + Sqlite::WriteStatement<2> updateEnumerationDeclarationStatement{ + "UPDATE enumerationDeclarations SET enumeratorDeclarations=?2 WHERE " + "enumerationDeclarationId=?1", + database}; + Sqlite::WriteStatement<1> deleteEnumerationDeclarationStatement{ + "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database}; + mutable Sqlite::ReadStatement<1, 2> selectModuleIdByNameStatement{ + "SELECT moduleId FROM modules WHERE kind=?1 AND name=?2 LIMIT 1", database}; + mutable Sqlite::ReadWriteStatement<1, 2> insertModuleNameStatement{ + "INSERT INTO modules(kind, name) VALUES(?1, ?2) RETURNING moduleId", database}; + mutable Sqlite::ReadStatement<2, 1> selectModuleStatement{ + "SELECT name, kind FROM modules WHERE moduleId =?1", database}; + mutable Sqlite::ReadStatement<3> selectAllModulesStatement{ + "SELECT name, kind, moduleId FROM modules", database}; + mutable Sqlite::ReadStatement<1, 2> selectTypeIdBySourceIdAndNameStatement{ + "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database}; + mutable Sqlite::ReadStatement<1, 3> selectTypeIdByModuleIdsAndExportedNameStatement{ + "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND " + "name=?3", + database}; + mutable Sqlite::ReadStatement<4> selectAllDocumentImportForSourceIdStatement{ + "SELECT moduleId, majorVersion, minorVersion, sourceId " + "FROM documentImports ", + database}; + mutable Sqlite::ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{ + "SELECT importId, sourceId, moduleId, majorVersion, minorVersion " + "FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, " + "moduleId, majorVersion, minorVersion", + database}; + Sqlite::ReadWriteStatement<1, 5> insertDocumentImportWithoutVersionStatement{ + "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, " + "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING importId", + database}; + Sqlite::ReadWriteStatement<1, 6> insertDocumentImportWithMajorVersionStatement{ + "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, " + "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6) RETURNING importId", + database}; + Sqlite::ReadWriteStatement<1, 7> insertDocumentImportWithVersionStatement{ + "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, " + "minorVersion, parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) RETURNING " + "importId", + database}; + Sqlite::WriteStatement<1> deleteDocumentImportStatement{ + "DELETE FROM documentImports WHERE importId=?1", database}; + Sqlite::WriteStatement<2> deleteDocumentImportsWithParentImportIdStatement{ + "DELETE FROM documentImports WHERE sourceId=?1 AND parentImportId=?2", database}; + Sqlite::WriteStatement<1> deleteDocumentImportsWithSourceIdsStatement{ + "DELETE FROM documentImports WHERE sourceId IN carray(?1)", database}; + mutable Sqlite::ReadStatement<1, 2> selectPropertyDeclarationIdByTypeIdAndNameStatement{ + "SELECT propertyDeclarationId " + "FROM propertyDeclarations " + "WHERE typeId=?1 AND name=?2 " + "LIMIT 1", + database}; + Sqlite::WriteStatement<2> updateAliasIdPropertyDeclarationStatement{ + "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2 WHERE " + "aliasPropertyDeclarationId=?1", + database}; + Sqlite::WriteStatement<2> updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=new.propertyTypeId, " + "propertyTraits=new.propertyTraits, aliasPropertyDeclarationId=?1 FROM (SELECT " + "propertyTypeId, propertyTraits FROM propertyDeclarations WHERE propertyDeclarationId=?1) " + "AS new WHERE aliasPropertyDeclarationId=?2", + database}; + Sqlite::WriteStatement<1> updateAliasPropertyDeclarationToNullStatement{ + "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL, propertyTypeId=NULL, " + "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT " + "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)", + database}; + Sqlite::ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ + "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " + " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId " + "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target " + " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR " + " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId " + "WHERE alias.propertyTypeId=?1 " + "UNION ALL " + "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " + " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId " + "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target " + " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR " + " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId " + "WHERE target.typeId=?1 " + "UNION ALL " + "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " + " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId " + "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target " + " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR " + " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId " + "WHERE alias.propertyImportedTypeNameId IN " + " (SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) " + " WHERE typeId=?1)", + database}; + Sqlite::ReadStatement<3, 1> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{ + "WITH RECURSIVE " + " properties(propertyDeclarationId, propertyImportedTypeNameId, typeId, " + " aliasPropertyDeclarationId) AS (" + " SELECT propertyDeclarationId, propertyImportedTypeNameId, typeId, " + " aliasPropertyDeclarationId FROM propertyDeclarations WHERE " + " aliasPropertyDeclarationId=?1" + " UNION ALL " + " SELECT pd.propertyDeclarationId, pd.propertyImportedTypeNameId, pd.typeId, " + " pd.aliasPropertyDeclarationId FROM propertyDeclarations AS pd JOIN properties AS " + " p ON pd.aliasPropertyDeclarationId=p.propertyDeclarationId)" + "SELECT propertyDeclarationId, propertyImportedTypeNameId, aliasPropertyDeclarationId " + " FROM properties", + database}; + Sqlite::ReadWriteStatement<3, 1> updatesPropertyDeclarationPropertyTypeToNullStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=NULL WHERE propertyTypeId=?1 AND " + "aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, " + "propertyImportedTypeNameId", + database}; + mutable Sqlite::ReadStatement<1, 1> selectPropertyNameStatement{ + "SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; + Sqlite::WriteStatement<2> updatePropertyDeclarationTypeStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database}; + Sqlite::ReadWriteStatement<2, 2> updatePrototypeIdToTypeIdStatement{ + "UPDATE types " + "SET prototypeId=?2 " + "WHERE prototypeId=?1 " + "RETURNING typeId, prototypeNameId", + database}; + Sqlite::ReadWriteStatement<2, 2> updateExtensionIdToTypeIdStatement{ + "UPDATE types " + "SET extensionId=?2 " + "WHERE extensionId=?1 " + "RETURNING typeId, extensionNameId", + database}; + Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement{ + "SELECT typeId, prototypeNameId " + "FROM types " + "WHERE prototypeNameId IN ( " + " SELECT importedTypeNameId " + " FROM " + " importedTypeNames WHERE name=?1) " + " AND prototypeId=?2", + database}; + Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement{ + "SELECT typeId , prototypeNameId " + "FROM types " + "WHERE prototypeId=?1 AND sourceId=?2", + database}; + Sqlite::ReadStatement<2, 2> selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement{ + "SELECT typeId, extensionNameId " + "FROM types " + "WHERE extensionId=?1 AND sourceId=?2", + database}; + Sqlite::ReadWriteStatement<3, 3> updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement{ + "UPDATE types " + "SET prototypeId=?2, extensionId=?3 " + "WHERE sourceId=?1 " + "RETURNING typeId, prototypeNameId, extensionNameId", + database}; + Sqlite::ReadStatement<2, 2> selectTypeIdForExtensionIdAndTypeNameStatement{ + "SELECT typeId , prototypeNameId " + "FROM types " + "WHERE extensionNameId IN ( " + " SELECT importedTypeNameId " + " FROM importedTypeNames " + " WHERE name=?1) " + " AND extensionId=?2", + database}; + Sqlite::WriteStatement<2> updateTypePrototypeStatement{ + "UPDATE types SET prototypeId=?2 WHERE typeId=?1", database}; + Sqlite::WriteStatement<2> updateTypeExtensionStatement{ + "UPDATE types SET extensionId=?2 WHERE typeId=?1", database}; + mutable Sqlite::ReadStatement<1, 1> selectPrototypeAndExtensionIdsStatement{ + "WITH RECURSIVE " + " prototypes(typeId) AS ( " + " SELECT prototypeId FROM types WHERE typeId=?1 " + " UNION ALL " + " SELECT extensionId FROM types WHERE typeId=?1 " + " UNION ALL " + " SELECT prototypeId FROM types JOIN prototypes USING(typeId) " + " UNION ALL " + " SELECT extensionId FROM types JOIN prototypes USING(typeId)) " + "SELECT typeId FROM prototypes WHERE typeId IS NOT NULL", + database}; + Sqlite::WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ + "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, " + "propertyImportedTypeNameId=?3 WHERE propertyDeclarationId=?1 AND " + "(aliasPropertyDeclarationId IS NOT ?2 OR propertyImportedTypeNameId IS NOT ?3)", + database}; + Sqlite::WriteStatement<1> updatetPropertiesDeclarationValuesOfAliasStatement{ + "WITH RECURSIVE " + " properties(propertyDeclarationId, propertyTypeId, propertyTraits) AS ( " + " SELECT aliasPropertyDeclarationId, propertyTypeId, propertyTraits FROM " + " propertyDeclarations WHERE propertyDeclarationId=?1 " + " UNION ALL " + " SELECT pd.aliasPropertyDeclarationId, pd.propertyTypeId, pd.propertyTraits FROM " + " propertyDeclarations AS pd JOIN properties USING(propertyDeclarationId)) " + "UPDATE propertyDeclarations AS pd SET propertyTypeId=p.propertyTypeId, " + " propertyTraits=p.propertyTraits " + "FROM properties AS p " + "WHERE pd.propertyDeclarationId=?1 AND p.propertyDeclarationId IS NULL AND " + " (pd.propertyTypeId IS NOT p.propertyTypeId OR pd.propertyTraits IS NOT " + " p.propertyTraits)", + database}; + Sqlite::WriteStatement<1> updatePropertyDeclarationAliasIdToNullStatement{ + "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL WHERE " + "propertyDeclarationId=?1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectPropertyDeclarationIdsForAliasChainStatement{ + "WITH RECURSIVE " + " properties(propertyDeclarationId) AS ( " + " SELECT aliasPropertyDeclarationId FROM propertyDeclarations WHERE " + " propertyDeclarationId=?1 " + " UNION ALL " + " SELECT aliasPropertyDeclarationId FROM propertyDeclarations JOIN properties " + " USING(propertyDeclarationId)) " + "SELECT propertyDeclarationId FROM properties", + database}; + mutable Sqlite::ReadStatement<3> selectAllFileStatusesStatement{ + "SELECT sourceId, size, lastModified FROM fileStatuses ORDER BY sourceId", database}; + mutable Sqlite::ReadStatement<3, 1> selectFileStatusesForSourceIdsStatement{ + "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId IN carray(?1) ORDER " + "BY sourceId", + database}; + mutable Sqlite::ReadStatement<3, 1> selectFileStatusesForSourceIdStatement{ + "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId=?1 ORDER BY sourceId", + database}; + Sqlite::WriteStatement<3> insertFileStatusStatement{ + "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES(?1, ?2, ?3)", database}; + Sqlite::WriteStatement<1> deleteFileStatusStatement{ + "DELETE FROM fileStatuses WHERE sourceId=?1", database}; + Sqlite::WriteStatement<3> updateFileStatusStatement{ + "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database}; + Sqlite::ReadStatement<1, 1> selectTypeIdBySourceIdStatement{ + "SELECT typeId FROM types WHERE sourceId=?", database}; + mutable Sqlite::ReadStatement<1, 3> selectImportedTypeNameIdStatement{ + "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 " + "AND name=?3 LIMIT 1", + database}; + mutable Sqlite::ReadWriteStatement<1, 3> insertImportedTypeNameIdStatement{ + "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) " + "RETURNING importedTypeNameId", + database}; + mutable Sqlite::ReadStatement<1, 2> selectImportIdBySourceIdAndModuleIdStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion " + "IS NULL AND minorVersion IS NULL LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 3> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion IS NULL LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 4> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ + "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " + "majorVersion=?3 AND minorVersion=?4 LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectKindFromImportedTypeNamesStatement{ + "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; + mutable Sqlite::ReadStatement<1, 1> selectNameFromImportedTypeNamesStatement{ + "SELECT name FROM importedTypeNames WHERE importedTypeNameId=?1", database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ + "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " + "importOrSourceId=di.importId JOIN documentImports AS di2 ON di.sourceId=di2.sourceId AND " + "di.moduleId=di2.sourceModuleId " + "JOIN exportedTypeNames AS etn ON di2.moduleId=etn.moduleId WHERE " + "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND " + "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " + "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " + "etn.minorVersion DESC NULLS FIRST LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIdForImportedTypeNameNamesStatement{ + "WITH " + " importTypeNames(moduleId, name, kind, majorVersion, minorVersion) AS ( " + " SELECT moduleId, name, di.kind, majorVersion, minorVersion " + " FROM importedTypeNames AS itn JOIN documentImports AS di ON " + " importOrSourceId=sourceId " + " WHERE " + " importedTypeNameId=?1 AND itn.kind=1) " + "SELECT typeId FROM importTypeNames AS itn " + " JOIN exportedTypeNames AS etn USING(moduleId, name) " + "WHERE (itn.majorVersion IS NULL OR (itn.majorVersion=etn.majorVersion " + " AND (itn.minorVersion IS NULL OR itn.minorVersion>=etn.minorVersion))) " + "ORDER BY itn.kind, etn.majorVersion DESC NULLS FIRST, etn.minorVersion DESC NULLS FIRST " + "LIMIT 1", + database}; + Sqlite::WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database}; + Sqlite::WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; + mutable Sqlite::ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{ + "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " + "exportedTypeNameId FROM exportedTypeNames WHERE typeId in carray(?1) ORDER BY moduleId, " + "name, majorVersion, minorVersion", + database}; + Sqlite::WriteStatement<5> insertExportedTypeNamesWithVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4, ?5)", + database}; + Sqlite::WriteStatement<4> insertExportedTypeNamesWithMajorVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) " + "VALUES(?1, ?2, ?3, ?4)", + database}; + Sqlite::WriteStatement<3> insertExportedTypeNamesWithoutVersionStatement{ + "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database}; + Sqlite::WriteStatement<1> deleteExportedTypeNameStatement{ + "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database}; + Sqlite::WriteStatement<2> updateExportedTypeNameTypeIdStatement{ + "UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database}; + mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfosForSourceIdsStatement{ + "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE " + "directorySourceId IN carray(?1) ORDER BY directorySourceId, sourceId", + database}; + Sqlite::WriteStatement<4> insertDirectoryInfoStatement{ + "INSERT INTO directoryInfos(directorySourceId, sourceId, " + "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)", + database}; + Sqlite::WriteStatement<2> deleteDirectoryInfoStatement{ + "DELETE FROM directoryInfos WHERE directorySourceId=?1 AND sourceId=?2", database}; + Sqlite::WriteStatement<4> updateDirectoryInfoStatement{ + "UPDATE directoryInfos SET moduleId=?3, fileType=?4 WHERE directorySourceId=?1 AND sourceId=?2", + database}; + mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfosForSourceIdStatement{ + "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE " + "directorySourceId=?1", + database}; + mutable Sqlite::ReadStatement<4, 2> selectDirectoryInfosForSourceIdAndFileTypeStatement{ + "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE " + "directorySourceId=?1 AND fileType=?2", + database}; + mutable Sqlite::ReadStatement<1, 2> selectDirectoryInfosSourceIdsForSourceIdAndFileTypeStatement{ + "SELECT sourceId FROM directoryInfos WHERE directorySourceId=?1 AND fileType=?2", database}; + mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfoForSourceIdStatement{ + "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE " + "sourceId=?1 LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{ + "SELECT typeId FROM types WHERE sourceId IN carray(?1)", database}; + mutable Sqlite::ReadStatement<6, 1> selectModuleExportedImportsForSourceIdStatement{ + "SELECT moduleExportedImportId, moduleId, exportedModuleId, ifnull(majorVersion, -1), " + "ifnull(minorVersion, -1), isAutoVersion FROM moduleExportedImports WHERE moduleId IN " + "carray(?1) ORDER BY moduleId, exportedModuleId", + database}; + Sqlite::WriteStatement<3> insertModuleExportedImportWithoutVersionStatement{ + "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion) " + "VALUES (?1, ?2, ?3)", + database}; + Sqlite::WriteStatement<4> insertModuleExportedImportWithMajorVersionStatement{ + "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, " + "majorVersion) VALUES (?1, ?2, ?3, ?4)", + database}; + Sqlite::WriteStatement<5> insertModuleExportedImportWithVersionStatement{ + "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, " + "majorVersion, minorVersion) VALUES (?1, ?2, ?3, ?4, ?5)", + database}; + Sqlite::WriteStatement<1> deleteModuleExportedImportStatement{ + "DELETE FROM moduleExportedImports WHERE moduleExportedImportId=?1", database}; + mutable Sqlite::ReadStatement<3, 3> selectModuleExportedImportsForModuleIdStatement{ + "WITH RECURSIVE " + " imports(moduleId, majorVersion, minorVersion, moduleExportedImportId) AS ( " + " SELECT exportedModuleId, " + " iif(isAutoVersion=1, ?2, majorVersion), " + " iif(isAutoVersion=1, ?3, minorVersion), " + " moduleExportedImportId " + " FROM moduleExportedImports WHERE moduleId=?1 " + " UNION ALL " + " SELECT exportedModuleId, " + " iif(mei.isAutoVersion=1, i.majorVersion, mei.majorVersion), " + " iif(mei.isAutoVersion=1, i.minorVersion, mei.minorVersion), " + " mei.moduleExportedImportId " + " FROM moduleExportedImports AS mei JOIN imports AS i USING(moduleId)) " + "SELECT DISTINCT moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " + "FROM imports", + database}; + mutable Sqlite::ReadStatement<1, 1> selectLocalPropertyDeclarationIdsForTypeStatement{ + "SELECT propertyDeclarationId " + "FROM propertyDeclarations " + "WHERE typeId=? " + "ORDER BY propertyDeclarationId", + database}; + mutable Sqlite::ReadStatement<1, 2> selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement{ + "SELECT propertyDeclarationId " + "FROM propertyDeclarations " + "WHERE typeId=?1 AND name=?2 LIMIT 1", + database}; + mutable Sqlite::ReadStatement<4, 1> selectPropertyDeclarationForPropertyDeclarationIdStatement{ + "SELECT typeId, name, propertyTraits, propertyTypeId " + "FROM propertyDeclarations " + "WHERE propertyDeclarationId=?1 LIMIT 1", + database}; + mutable Sqlite::ReadStatement<1, 1> selectSignalDeclarationNamesForTypeStatement{ + "WITH RECURSIVE " + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" + " UNION ALL " + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " typeChain(typeId) AS (" + " VALUES(?1)" + " UNION ALL " + " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " + " USING(typeId)) " + "SELECT name FROM typeChain JOIN signalDeclarations " + " USING(typeId) ORDER BY name", + database}; + mutable Sqlite::ReadStatement<1, 1> selectFuncionDeclarationNamesForTypeStatement{ + "WITH RECURSIVE " + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" + " UNION ALL " + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " typeChain(typeId) AS (" + " VALUES(?1)" + " UNION ALL " + " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " + " USING(typeId))" + "SELECT name FROM typeChain JOIN functionDeclarations " + " USING(typeId) ORDER BY name", + database}; + mutable Sqlite::ReadStatement<2> selectTypesWithDefaultPropertyStatement{ + "SELECT typeId, defaultPropertyId FROM types ORDER BY typeId", database}; + Sqlite::WriteStatement<2> updateDefaultPropertyIdStatement{ + "UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database}; + Sqlite::WriteStatement<1> updateDefaultPropertyIdToNullStatement{ + "UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database}; + mutable Sqlite::ReadStatement<3, 1> selectInfoTypeByTypeIdStatement{ + "SELECT sourceId, traits, annotationTraits FROM types WHERE typeId=?", database}; + mutable Sqlite::ReadStatement<1, 1> selectSourceIdByTypeIdStatement{ + "SELECT sourceId FROM types WHERE typeId=?", database}; + mutable Sqlite::ReadStatement<1, 1> selectPrototypeAnnotationTraitsByTypeIdStatement{ + "SELECT annotationTraits " + "FROM types " + "WHERE typeId=(SELECT prototypeId FROM types WHERE typeId=?)", + database}; + mutable Sqlite::ReadStatement<1, 1> selectDefaultPropertyDeclarationIdStatement{ + "SELECT defaultPropertyId FROM types WHERE typeId=?", database}; + mutable Sqlite::ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{ + "WITH RECURSIVE " + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" + " UNION ALL " + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " prototypes(typeId, level) AS (" + " SELECT prototypeId, 0 FROM all_prototype_and_extension WHERE typeId=?" + " UNION ALL " + " SELECT prototypeId, p.level+1 FROM all_prototype_and_extension JOIN " + " prototypes AS p USING(typeId)) " + "SELECT typeId FROM prototypes ORDER BY level", + database}; + Sqlite::WriteStatement<2> upsertPropertyEditorPathIdStatement{ + "INSERT INTO propertyEditorPaths(typeId, pathSourceId) VALUES(?1, ?2) ON CONFLICT DO " + "UPDATE SET pathSourceId=excluded.pathSourceId WHERE pathSourceId IS NOT " + "excluded.pathSourceId", + database}; + mutable Sqlite::ReadStatement<1, 1> selectPropertyEditorPathIdStatement{ + "SELECT pathSourceId FROM propertyEditorPaths WHERE typeId=?", database}; + mutable Sqlite::ReadStatement<3, 1> selectPropertyEditorPathsForForSourceIdsStatement{ + "SELECT typeId, pathSourceId, directoryId " + "FROM propertyEditorPaths " + "WHERE directoryId IN carray(?1) " + "ORDER BY typeId", + database}; + Sqlite::WriteStatement<3> insertPropertyEditorPathStatement{ + "INSERT INTO propertyEditorPaths(typeId, pathSourceId, directoryId) VALUES (?1, ?2, ?3)", + database}; + Sqlite::WriteStatement<3> updatePropertyEditorPathsStatement{ + "UPDATE propertyEditorPaths " + "SET pathSourceId=?2, directoryId=?3 " + "WHERE typeId=?1", + database}; + Sqlite::WriteStatement<1> deletePropertyEditorPathStatement{ + "DELETE FROM propertyEditorPaths WHERE typeId=?1", database}; + mutable Sqlite::ReadStatement<5, 1> selectTypeAnnotationsForSourceIdsStatement{ + "SELECT typeId, typeName, iconPath, itemLibrary, hints FROM typeAnnotations WHERE " + "sourceId IN carray(?1) ORDER BY typeId", + database}; + Sqlite::WriteStatement<7> insertTypeAnnotationStatement{ + "INSERT INTO " + " typeAnnotations(typeId, sourceId, directorySourceId, typeName, iconPath, itemLibrary, " + " hints) " + "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)", + database}; + Sqlite::WriteStatement<5> updateTypeAnnotationStatement{ + "UPDATE typeAnnotations " + "SET typeName=?2, iconPath=?3, itemLibrary=?4, hints=?5 " + "WHERE typeId=?1", + database}; + Sqlite::WriteStatement<1> deleteTypeAnnotationStatement{ + "DELETE FROM typeAnnotations WHERE typeId=?1", database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIconPathStatement{ + "SELECT iconPath FROM typeAnnotations WHERE typeId=?1", database}; + mutable Sqlite::ReadStatement<2, 1> selectTypeHintsStatement{ + "SELECT hints.key, hints.value " + "FROM typeAnnotations, json_each(typeAnnotations.hints) AS hints " + "WHERE typeId=?1 AND hints IS NOT NULL", + database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeAnnotationSourceIdsStatement{ + "SELECT sourceId FROM typeAnnotations WHERE directorySourceId=?1 ORDER BY sourceId", database}; + mutable Sqlite::ReadStatement<1, 0> selectTypeAnnotationDirectorySourceIdsStatement{ + "SELECT DISTINCT directorySourceId FROM typeAnnotations ORDER BY directorySourceId", database}; + mutable Sqlite::ReadStatement<10> selectItemLibraryEntriesStatement{ + "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', " + " i.value->>'$.category', i.value->>'$.import', i.value->>'$.toolTip', " + " i.value->>'$.properties', i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " + "FROM typeAnnotations AS ta , json_each(ta.itemLibrary) AS i " + "WHERE ta.itemLibrary IS NOT NULL", + database}; + mutable Sqlite::ReadStatement<10, 1> selectItemLibraryEntriesByTypeIdStatement{ + "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', " + " i.value->>'$.category', i.value->>'$.import', i.value->>'$.toolTip', " + " i.value->>'$.properties', i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " + "FROM typeAnnotations AS ta, json_each(ta.itemLibrary) AS i " + "WHERE typeId=?1 AND ta.itemLibrary IS NOT NULL", + database}; + mutable Sqlite::ReadStatement<10, 1> selectItemLibraryEntriesBySourceIdStatement{ + "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', " + "i.value->>'$.category', " + " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', " + " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " + "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i " + "WHERE typeId IN (SELECT DISTINCT typeId " + " FROM documentImports AS di JOIN exportedTypeNames " + " USING(moduleId) " + " WHERE di.sourceId=?)", + database}; + mutable Sqlite::ReadStatement<3, 1> selectItemLibraryPropertiesStatement{ + "SELECT p.value->>0, p.value->>1, p.value->>2 FROM json_each(?1) AS p", database}; + mutable Sqlite::ReadStatement<1, 1> selectItemLibraryExtraFilePathsStatement{ + "SELECT p.value FROM json_each(?1) AS p", database}; + mutable Sqlite::ReadStatement<1, 1> selectTypeIdsByModuleIdStatement{ + "SELECT DISTINCT typeId FROM exportedTypeNames WHERE moduleId=?", database}; + mutable Sqlite::ReadStatement<1, 1> selectHeirTypeIdsStatement{ + "WITH RECURSIVE " + " typeSelection(typeId) AS (" + " SELECT typeId FROM types WHERE prototypeId=?1 OR extensionId=?1" + " UNION ALL " + " SELECT t.typeId " + " FROM types AS t JOIN typeSelection AS ts " + " WHERE prototypeId=ts.typeId OR extensionId=ts.typeId)" + "SELECT typeId FROM typeSelection", + database}; +}; + +class ProjectStorage::Initializer +{ +public: + Initializer(Database &database, bool isInitialized) + { + if (!isInitialized) { + auto moduleIdColumn = createModulesTable(database); + createSourceContextsTable(database); + createSourcesTable(database); + createTypesAndePropertyDeclarationsTables(database, moduleIdColumn); + createExportedTypeNamesTable(database, moduleIdColumn); + createImportedTypeNamesTable(database); + createEnumerationsTable(database); + createFunctionsTable(database); + createSignalsTable(database); + createModuleExportedImportsTable(database, moduleIdColumn); + createDocumentImportsTable(database, moduleIdColumn); + createFileStatusesTable(database); + createDirectoryInfosTable(database); + createPropertyEditorPathsTable(database); + createTypeAnnotionsTable(database); + } + database.setIsInitialized(true); + } + + void createSourceContextsTable(Database &database) + { + Sqlite::Table table; + table.setUseIfNotExists(true); + table.setName("sourceContexts"); + table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); + const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath"); + + table.addUniqueIndex({sourceContextPathColumn}); + + table.initialize(database); + } + + void createSourcesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("sources"); + table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + const auto &sourceContextIdColumn = table.addColumn( + "sourceContextId", + Sqlite::StrictColumnType::Integer, + {Sqlite::NotNull{}, + Sqlite::ForeignKey{"sourceContexts", + "sourceContextId", + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade}}); + const auto &sourceNameColumn = table.addColumn("sourceName", Sqlite::StrictColumnType::Text); + table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn}); + + table.initialize(database); + } + + void createTypesAndePropertyDeclarationsTables( + Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable typesTable; + typesTable.setUseIfNotExists(true); + typesTable.setName("types"); + typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text); + typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer); + auto &prototypeIdColumn = typesTable.addColumn("prototypeId", + Sqlite::StrictColumnType::Integer); + auto &prototypeNameIdColumn = typesTable.addColumn("prototypeNameId", + Sqlite::StrictColumnType::Integer); + auto &extensionIdColumn = typesTable.addColumn("extensionId", + Sqlite::StrictColumnType::Integer); + auto &extensionNameIdColumn = typesTable.addColumn("extensionNameId", + Sqlite::StrictColumnType::Integer); + auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId", + Sqlite::StrictColumnType::Integer); + typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer); + typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); + typesTable.addIndex({defaultPropertyIdColumn}); + typesTable.addIndex({prototypeIdColumn, sourceIdColumn}); + typesTable.addIndex({extensionIdColumn, sourceIdColumn}); + typesTable.addIndex({prototypeNameIdColumn}); + typesTable.addIndex({extensionNameIdColumn}); + + typesTable.initialize(database); + + { + Sqlite::StrictTable propertyDeclarationTable; + propertyDeclarationTable.setUseIfNotExists(true); + propertyDeclarationTable.setName("propertyDeclarations"); + propertyDeclarationTable.addColumn("propertyDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId"); + auto &nameColumn = propertyDeclarationTable.addColumn("name"); + auto &propertyTypeIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "propertyTypeId", + typesTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + propertyDeclarationTable.addColumn("propertyTraits", Sqlite::StrictColumnType::Integer); + propertyDeclarationTable.addColumn("propertyImportedTypeNameId", + Sqlite::StrictColumnType::Integer); + auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "aliasPropertyDeclarationId", + propertyDeclarationTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn( + "aliasPropertyDeclarationTailId", + propertyDeclarationTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + + propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); + propertyDeclarationTable.addIndex({propertyTypeIdColumn}); + propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, + "aliasPropertyDeclarationId IS NOT NULL"); + propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn}, + "aliasPropertyDeclarationTailId IS NOT NULL"); + + propertyDeclarationTable.initialize(database); + } + } + + void createExportedTypeNamesTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("exportedTypeNames"); + table.addColumn("exportedTypeNameId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::NoAction); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({moduleIdColumn, nameColumn}, + "majorVersion IS NULL AND minorVersion IS NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NULL"); + table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + + table.addIndex({typeIdColumn}); + table.addIndex({moduleIdColumn, nameColumn}); + + table.initialize(database); + } + + void createImportedTypeNamesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("importedTypeNames"); + table.addColumn("importedTypeNameId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &importOrSourceIdColumn = table.addColumn("importOrSourceId"); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn}); + table.addIndex({nameColumn}); + + table.initialize(database); + } + + void createEnumerationsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("enumerationDeclarations"); + table.addColumn("enumerationDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({typeIdColumn, nameColumn}); + + table.initialize(database); + } + + void createFunctionsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("functionDeclarations"); + table.addColumn("functionDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); + table.addColumn("returnTypeName"); + + table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); + + table.initialize(database); + } + + void createSignalsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("signalDeclarations"); + table.addColumn("signalDeclarationId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); + + table.initialize(database); + } + + Sqlite::StrictColumn createModulesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("modules"); + auto &modelIdColumn = table.addColumn("moduleId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); + auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({kindColumn, nameColumn}); - return projectStorageCategory_; + table.initialize(database); + + return std::move(modelIdColumn); + } + + void createModuleExportedImportsTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("moduleExportedImports"); + table.addColumn("moduleExportedImportId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &sourceIdColumn = table.addColumn("exportedModuleId", Sqlite::StrictColumnType::Integer); + table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer); + table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex({sourceIdColumn, moduleIdColumn}); + + table.initialize(database); + } + + void createDocumentImportsTable(Database &database, + const Sqlite::StrictColumn &foreignModuleIdColumn) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("documentImports"); + table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId", + foreignModuleIdColumn, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade, + Sqlite::Enforment::Immediate); + auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); + auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); + auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); + auto &parentImportIdColumn = table.addColumn("parentImportId", + Sqlite::StrictColumnType::Integer); + + table.addUniqueIndex( + {sourceIdColumn, moduleIdColumn, kindColumn, sourceModuleIdColumn, parentImportIdColumn}, + "majorVersion IS NULL AND minorVersion IS NULL"); + table.addUniqueIndex({sourceIdColumn, + moduleIdColumn, + kindColumn, + sourceModuleIdColumn, + majorVersionColumn, + parentImportIdColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NULL"); + table.addUniqueIndex({sourceIdColumn, + moduleIdColumn, + kindColumn, + sourceModuleIdColumn, + majorVersionColumn, + minorVersionColumn, + parentImportIdColumn}, + "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); + + table.addIndex({sourceIdColumn, kindColumn}); + + table.initialize(database); + } + + void createFileStatusesTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setName("fileStatuses"); + table.addColumn("sourceId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}, + Sqlite::ForeignKey{"sources", + "sourceId", + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Cascade}}); + table.addColumn("size", Sqlite::StrictColumnType::Integer); + table.addColumn("lastModified", Sqlite::StrictColumnType::Integer); + + table.initialize(database); + } + + void createDirectoryInfosTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("directoryInfos"); + auto &directorySourceIdColumn = table.addColumn("directorySourceId", + Sqlite::StrictColumnType::Integer); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + table.addColumn("moduleId", Sqlite::StrictColumnType::Integer); + auto &fileTypeColumn = table.addColumn("fileType", Sqlite::StrictColumnType::Integer); + + table.addPrimaryKeyContraint({directorySourceIdColumn, sourceIdColumn}); + table.addUniqueIndex({sourceIdColumn}); + table.addIndex({directorySourceIdColumn, fileTypeColumn}); + + table.initialize(database); + } + + void createPropertyEditorPathsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("propertyEditorPaths"); + table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer); + auto &directoryIdColumn = table.addColumn("directoryId", Sqlite::StrictColumnType::Integer); + + table.addIndex({directoryIdColumn}); + + table.initialize(database); + } + + void createTypeAnnotionsTable(Database &database) + { + Sqlite::StrictTable table; + table.setUseIfNotExists(true); + table.setUseWithoutRowId(true); + table.setName("typeAnnotations"); + auto &typeIdColumn = table.addColumn("typeId", + Sqlite::StrictColumnType::Integer, + {Sqlite::PrimaryKey{}}); + auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); + auto &directorySourceIdColumn = table.addColumn("directorySourceId", + Sqlite::StrictColumnType::Integer); + table.addColumn("typeName", Sqlite::StrictColumnType::Text); + table.addColumn("iconPath", Sqlite::StrictColumnType::Text); + table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text); + table.addColumn("hints", Sqlite::StrictColumnType::Text); + + table.addUniqueIndex({sourceIdColumn, typeIdColumn}); + table.addIndex({directorySourceIdColumn}); + + table.initialize(database); + } +}; + +ProjectStorage::ProjectStorage(Database &database, + ProjectStorageErrorNotifierInterface &errorNotifier, + bool isInitialized) + : database{database} + , errorNotifier{&errorNotifier} + , exclusiveTransaction{database} + , initializer{std::make_unique<ProjectStorage::Initializer>(database, isInitialized)} + , moduleCache{ModuleStorageAdapter{*this}} + , s{std::make_unique<ProjectStorage::Statements>(database)} +{ + NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()}; + + exclusiveTransaction.commit(); + + database.walCheckpointFull(); + + moduleCache.populate(); } -} // namespace QmlDesigner +ProjectStorage::~ProjectStorage() = default; + +void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackage package) +{ + NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()}; + + TypeIds deletedTypeIds; + Sqlite::withImmediateTransaction(database, [&] { + AliasPropertyDeclarations insertedAliasPropertyDeclarations; + AliasPropertyDeclarations updatedAliasPropertyDeclarations; + + AliasPropertyDeclarations relinkableAliasPropertyDeclarations; + PropertyDeclarations relinkablePropertyDeclarations; + Prototypes relinkablePrototypes; + Prototypes relinkableExtensions; + + TypeIds updatedTypeIds; + updatedTypeIds.reserve(package.types.size()); + + TypeIds typeIdsToBeDeleted; + + std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end()); + + synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds); + synchronizeImports(package.imports, + package.updatedSourceIds, + package.moduleDependencies, + package.updatedModuleDependencySourceIds, + package.moduleExportedImports, + package.updatedModuleIds, + relinkablePrototypes, + relinkableExtensions); + synchronizeTypes(package.types, + updatedTypeIds, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + package.updatedSourceIds); + synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds); + synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, + package.updatedPropertyEditorQmlPathSourceIds); + + deleteNotUpdatedTypes(updatedTypeIds, + package.updatedSourceIds, + typeIdsToBeDeleted, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + deletedTypeIds); + + relink(relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + deletedTypeIds); + + linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); + + synchronizeDirectoryInfos(package.directoryInfos, package.updatedDirectoryInfoSourceIds); + + commonTypeCache_.resetTypeIds(); + }); + + callRefreshMetaInfoCallback(deletedTypeIds); +} + +void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize document imports"_t, + projectStorageCategory(), + keyValue("imports", imports), + keyValue("source id", sourceId)}; + + Sqlite::withImmediateTransaction(database, [&] { + AliasPropertyDeclarations relinkableAliasPropertyDeclarations; + PropertyDeclarations relinkablePropertyDeclarations; + Prototypes relinkablePrototypes; + Prototypes relinkableExtensions; + TypeIds deletedTypeIds; + + synchronizeDocumentImports(imports, + {sourceId}, + Storage::Synchronization::ImportKind::Import, + Relink::Yes, + relinkablePrototypes, + relinkableExtensions); + + relink(relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions, + deletedTypeIds); + }); +} + +void ProjectStorage::addObserver(ProjectStorageObserver *observer) +{ + NanotraceHR::Tracer tracer{"add observer"_t, projectStorageCategory()}; + observers.push_back(observer); +} + +void ProjectStorage::removeObserver(ProjectStorageObserver *observer) +{ + NanotraceHR::Tracer tracer{"remove observer"_t, projectStorageCategory()}; + observers.removeOne(observer); +} + +ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName, Storage::ModuleKind kind) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get module id"_t, + projectStorageCategory(), + keyValue("module name", moduleName)}; + + auto moduleId = moduleCache.id({moduleName, kind}); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Storage::Module ProjectStorage::module(ModuleId moduleId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get module name"_t, + projectStorageCategory(), + keyValue("module id", moduleId)}; + + if (!moduleId) + throw ModuleDoesNotExists{}; + + auto module = moduleCache.value(moduleId); + + tracer.end(keyValue("module name", module.name)); + tracer.end(keyValue("module kind", module.kind)); + + return {module.name, module.kind}; +} + +TypeId ProjectStorage::typeId(ModuleId moduleId, + Utils::SmallStringView exportedTypeName, + Storage::Version version) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type id by exported name"_t, + projectStorageCategory(), + keyValue("module id", moduleId), + keyValue("exported type name", exportedTypeName), + keyValue("version", version)}; + + TypeId typeId; + + if (version.minor) { + typeId = s->selectTypeIdByModuleIdAndExportedNameAndVersionStatement.valueWithTransaction<TypeId>( + moduleId, exportedTypeName, version.major.value, version.minor.value); + + } else if (version.major) { + typeId = s->selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement + .valueWithTransaction<TypeId>(moduleId, exportedTypeName, version.major.value); + + } else { + typeId = s->selectTypeIdByModuleIdAndExportedNameStatement + .valueWithTransaction<TypeId>(moduleId, exportedTypeName); + } + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::typeId(ImportedTypeNameId typeNameId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type id by imported type name"_t, + projectStorageCategory(), + keyValue("imported type name id", typeNameId)}; + + auto typeId = Sqlite::withDeferredTransaction(database, [&] { return fetchTypeId(typeNameId); }); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +QVarLengthArray<TypeId, 256> ProjectStorage::typeIds(ModuleId moduleId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type ids by module id"_t, + projectStorageCategory(), + keyValue("module id", moduleId)}; + + auto typeIds = s->selectTypeIdsByModuleIdStatement + .valuesWithTransaction<QVarLengthArray<TypeId, 256>>(moduleId); + + tracer.end(keyValue("type ids", typeIds)); + + return typeIds; +} + +Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get exported type names by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto exportedTypenames = s->selectExportedTypesByTypeIdStatement + .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId); + + tracer.end(keyValue("exported type names", exportedTypenames)); + + return exportedTypenames; +} + +Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId, SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get exported type names by source id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("source id", sourceId)}; + + auto exportedTypenames = s->selectExportedTypesByTypeIdAndSourceIdStatement + .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId, + sourceId); + + tracer.end(keyValue("exported type names", exportedTypenames)); + + return exportedTypenames; +} + +ImportId ProjectStorage::importId(const Storage::Import &import) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get import id by import"_t, + projectStorageCategory(), + keyValue("import", import)}; + + auto importId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportId(import.sourceId, import); + }); + + tracer.end(keyValue("import id", importId)); + + return importId; +} + +ImportedTypeNameId ProjectStorage::importedTypeNameId(ImportId importId, + Utils::SmallStringView typeName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get imported type name id by import id"_t, + projectStorageCategory(), + keyValue("import id", importId), + keyValue("imported type name", typeName)}; + + auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported, + importId, + typeName); + }); + + tracer.end(keyValue("imported type name id", importedTypeNameId)); + + return importedTypeNameId; +} + +ImportedTypeNameId ProjectStorage::importedTypeNameId(SourceId sourceId, + Utils::SmallStringView typeName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get imported type name id by source id"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("imported type name", typeName)}; + + auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] { + return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, + sourceId, + typeName); + }); + + tracer.end(keyValue("imported type name id", importedTypeNameId)); + + return importedTypeNameId; +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::propertyDeclarationIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration ids"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationIds = Sqlite::withDeferredTransaction(database, [&] { + return fetchPropertyDeclarationIds(typeId); + }); + + std::sort(propertyDeclarationIds.begin(), propertyDeclarationIds.end()); + + tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + + return propertyDeclarationIds; +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::localPropertyDeclarationIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get local property declaration ids"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationIds = s->selectLocalPropertyDeclarationIdsForTypeStatement + .valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>( + typeId); + + tracer.end(keyValue("property declaration ids", propertyDeclarationIds)); + + return propertyDeclarationIds; +} + +PropertyDeclarationId ProjectStorage::propertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", propertyName)}; + + auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { + return fetchPropertyDeclarationId(typeId, propertyName); + }); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +PropertyDeclarationId ProjectStorage::localPropertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get local property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", propertyName)}; + + auto propertyDeclarationId = s->selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement + .valueWithTransaction<PropertyDeclarationId>(typeId, + propertyName); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +PropertyDeclarationId ProjectStorage::defaultPropertyDeclarationId(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get default property declaration id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] { + return fetchDefaultPropertyDeclarationId(typeId); + }); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + return propertyDeclarationId; +} + +std::optional<Storage::Info::PropertyDeclaration> ProjectStorage::propertyDeclaration( + PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property declaration"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + + auto propertyDeclaration = s->selectPropertyDeclarationForPropertyDeclarationIdStatement + .optionalValueWithTransaction<Storage::Info::PropertyDeclaration>( + propertyDeclarationId); + + tracer.end(keyValue("property declaration", propertyDeclaration)); + + return propertyDeclaration; +} + +std::optional<Storage::Info::Type> ProjectStorage::type(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory(), keyValue("type id", typeId)}; + + auto type = s->selectInfoTypeByTypeIdStatement.optionalValueWithTransaction<Storage::Info::Type>( + typeId); + + tracer.end(keyValue("type", type)); + + return type; +} + +Utils::PathString ProjectStorage::typeIconPath(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type icon path"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto typeIconPath = s->selectTypeIconPathStatement.valueWithTransaction<Utils::PathString>(typeId); + + tracer.end(keyValue("type icon path", typeIconPath)); + + return typeIconPath; +} + +Storage::Info::TypeHints ProjectStorage::typeHints(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type hints"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto typeHints = s->selectTypeHintsStatement.valuesWithTransaction<Storage::Info::TypeHints, 4>( + typeId); + + tracer.end(keyValue("type hints", typeHints)); + + return typeHints; +} + +SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(SourceId directoryId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, + projectStorageCategory(), + keyValue("source id", directoryId)}; + + auto sourceIds = s->selectTypeAnnotationSourceIdsStatement.valuesWithTransaction<SmallSourceIds<4>>( + directoryId); + + tracer.end(keyValue("source ids", sourceIds)); + + return sourceIds; +} + +SmallSourceIds<64> ProjectStorage::typeAnnotationDirectorySourceIds() const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, projectStorageCategory()}; + + auto sourceIds = s->selectTypeAnnotationDirectorySourceIdsStatement + .valuesWithTransaction<SmallSourceIds<64>>(); + + tracer.end(keyValue("source ids", sourceIds)); + + return sourceIds; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId_, + Utils::SmallStringView typeName, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back( + typeId_, typeName, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + s->selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(ImportId importId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by import id"_t, + projectStorageCategory(), + keyValue("import id", importId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId_, + Utils::SmallStringView typeName, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back( + typeId_, typeName, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + s->selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, importId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get item library entries by source id"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId, + Utils::SmallStringView typeName, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back( + typeId, typeName, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + s->selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +Storage::Info::ItemLibraryEntries ProjectStorage::allItemLibraryEntries() const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId, + Utils::SmallStringView typeName, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { + auto &last = entries.emplace_back( + typeId, typeName, name, iconPath, category, import, toolTip, templatePath); + if (properties.size()) + s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties); + if (extraFilePaths.size()) + s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); + }; + + s->selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + +std::vector<Utils::SmallString> ProjectStorage::signalDeclarationNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get signal names"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto signalDeclarationNames = s->selectSignalDeclarationNamesForTypeStatement + .valuesWithTransaction<Utils::SmallString, 32>(typeId); + + tracer.end(keyValue("signal names", signalDeclarationNames)); + + return signalDeclarationNames; +} + +std::vector<Utils::SmallString> ProjectStorage::functionDeclarationNames(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get function names"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto functionDeclarationNames = s->selectFuncionDeclarationNamesForTypeStatement + .valuesWithTransaction<Utils::SmallString, 32>(typeId); + + tracer.end(keyValue("function names", functionDeclarationNames)); + + return functionDeclarationNames; +} + +std::optional<Utils::SmallString> ProjectStorage::propertyName( + PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property name"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + + auto propertyName = s->selectPropertyNameStatement.optionalValueWithTransaction<Utils::SmallString>( + propertyDeclarationId); + + tracer.end(keyValue("property name", propertyName)); + + return propertyName; +} + +SmallTypeIds<16> ProjectStorage::prototypeIds(TypeId type) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes"_t, projectStorageCategory(), keyValue("type id", type)}; + + auto prototypeIds = s->selectPrototypeAndExtensionIdsStatement + .valuesWithTransaction<SmallTypeIds<16>>(type); + + tracer.end(keyValue("type ids", prototypeIds)); + + return prototypeIds; +} + +SmallTypeIds<16> ProjectStorage::prototypeAndSelfIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()}; + + SmallTypeIds<16> prototypeAndSelfIds; + prototypeAndSelfIds.push_back(typeId); + + s->selectPrototypeAndExtensionIdsStatement.readToWithTransaction(prototypeAndSelfIds, typeId); + + tracer.end(keyValue("type ids", prototypeAndSelfIds)); + + return prototypeAndSelfIds; +} + +SmallTypeIds<64> ProjectStorage::heirIds(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()}; + + auto heirIds = s->selectHeirTypeIdsStatement.valuesWithTransaction<SmallTypeIds<64>>(typeId); + + tracer.end(keyValue("type ids", heirIds)); + + return heirIds; +} + +bool ProjectStorage::isBasedOn(TypeId) const +{ + return false; +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1) const +{ + return isBasedOn_(typeId, id1); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const +{ + return isBasedOn_(typeId, id1, id2); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const +{ + return isBasedOn_(typeId, id1, id2, id3); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4); +} + +bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5); +} + +bool ProjectStorage::isBasedOn( + TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6); +} + +bool ProjectStorage::isBasedOn( + TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6, TypeId id7) const +{ + return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7); +} + +TypeId ProjectStorage::fetchTypeIdByExportedName(Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + projectStorageCategory(), + keyValue("exported type name", name)}; + + auto typeId = s->selectTypeIdByExportedNameStatement.valueWithTransaction<TypeId>(name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, + Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by module ids and exported name"_t, + projectStorageCategory(), + keyValue("module ids", NanotraceHR::array(moduleIds)), + keyValue("exported type name", name)}; + auto typeId = s->selectTypeIdByModuleIdsAndExportedNameStatement.valueWithTransaction<TypeId>( + static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +TypeId ProjectStorage::fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by name"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("internal type name", name)}; + + auto typeId = s->selectTypeIdBySourceIdAndNameStatement.valueWithTransaction<TypeId>(sourceId, + name); + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +Storage::Synchronization::Type ProjectStorage::fetchTypeByTypeId(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type by type id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto type = Sqlite::withDeferredTransaction(database, [&] { + auto type = s->selectTypeByTypeIdStatement.value<Storage::Synchronization::Type>(typeId); + + type.exportedTypes = fetchExportedTypes(typeId); + type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); + type.functionDeclarations = fetchFunctionDeclarations(type.typeId); + type.signalDeclarations = fetchSignalDeclarations(type.typeId); + type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); + + return type; + }); + + tracer.end(keyValue("type", type)); + + return type; +} + +Storage::Synchronization::Types ProjectStorage::fetchTypes() +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch types"_t, projectStorageCategory()}; + + auto types = Sqlite::withDeferredTransaction(database, [&] { + auto types = s->selectTypesStatement.values<Storage::Synchronization::Type, 64>(); + + for (Storage::Synchronization::Type &type : types) { + type.exportedTypes = fetchExportedTypes(type.typeId); + type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); + type.functionDeclarations = fetchFunctionDeclarations(type.typeId); + type.signalDeclarations = fetchSignalDeclarations(type.typeId); + type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); + } + + return types; + }); + + tracer.end(keyValue("type", types)); + + return types; +} + +SourceContextId ProjectStorage::fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()}; + + auto sourceContextId = readSourceContextId(sourceContextPath); + + return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath); +} + +SourceContextId ProjectStorage::fetchSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + SourceContextId sourceContextId; + try { + sourceContextId = Sqlite::withDeferredTransaction(database, [&] { + return fetchSourceContextIdUnguarded(sourceContextPath); + }); + } catch (const Sqlite::ConstraintPreventsModification &) { + sourceContextId = fetchSourceContextId(sourceContextPath); + } + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +Utils::PathString ProjectStorage::fetchSourceContextPath(SourceContextId sourceContextId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context path"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId)}; + + auto path = Sqlite::withDeferredTransaction(database, [&] { + auto optionalSourceContextPath = s->selectSourceContextPathFromSourceContextsBySourceContextIdStatement + .optionalValue<Utils::PathString>(sourceContextId); + + if (!optionalSourceContextPath) + throw SourceContextIdDoesNotExists(); + + return std::move(*optionalSourceContextPath); + }); + + tracer.end(keyValue("source context path", path)); + + return path; +} + +Cache::SourceContexts ProjectStorage::fetchAllSourceContexts() const +{ + NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()}; + + return s->selectAllSourceContextsStatement.valuesWithTransaction<Cache::SourceContext, 128>(); +} + +SourceId ProjectStorage::fetchSourceId(SourceContextId sourceContextId, + Utils::SmallStringView sourceName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source id"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId), + keyValue("source name", sourceName)}; + + auto sourceId = Sqlite::withDeferredTransaction(database, [&] { + return fetchSourceIdUnguarded(sourceContextId, sourceName); + }); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Cache::SourceNameAndSourceContextId ProjectStorage::fetchSourceNameAndSourceContextId(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source name and source context id"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto value = s->selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement + .valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId); + + if (!value.sourceContextId) + throw SourceIdDoesNotExists(); + + tracer.end(keyValue("source name", value.sourceName), + keyValue("source context id", value.sourceContextId)); + + return value; +} + +void ProjectStorage::clearSources() +{ + Sqlite::withImmediateTransaction(database, [&] { + s->deleteAllSourceContextsStatement.execute(); + s->deleteAllSourcesStatement.execute(); + }); +} + +SourceContextId ProjectStorage::fetchSourceContextId(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source context id"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto sourceContextId = s->selectSourceContextIdFromSourcesBySourceIdStatement + .valueWithTransaction<SourceContextId>(sourceId); + + if (!sourceContextId) + throw SourceIdDoesNotExists(); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +Cache::Sources ProjectStorage::fetchAllSources() const +{ + NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()}; + + return s->selectAllSourcesStatement.valuesWithTransaction<Cache::Source, 1024>(); +} + +SourceId ProjectStorage::fetchSourceIdUnguarded(SourceContextId sourceContextId, + Utils::SmallStringView sourceName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch source id unguarded"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId), + keyValue("source name", sourceName)}; + + auto sourceId = readSourceId(sourceContextId, sourceName); + + if (!sourceId) + sourceId = writeSourceId(sourceContextId, sourceName); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +FileStatuses ProjectStorage::fetchAllFileStatuses() const +{ + NanotraceHR::Tracer tracer{"fetch all file statuses"_t, projectStorageCategory()}; + + return s->selectAllFileStatusesStatement.valuesWithTransaction<FileStatus>(); +} + +FileStatus ProjectStorage::fetchFileStatus(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch file status"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto fileStatus = s->selectFileStatusesForSourceIdStatement.valueWithTransaction<FileStatus>( + sourceId); + + tracer.end(keyValue("file status", fileStatus)); + + return fileStatus; +} + +std::optional<Storage::Synchronization::DirectoryInfo> ProjectStorage::fetchDirectoryInfo(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch directory info"_t, + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto directoryInfo = s->selectDirectoryInfoForSourceIdStatement + .optionalValueWithTransaction<Storage::Synchronization::DirectoryInfo>( + sourceId); + + tracer.end(keyValue("directory info", directoryInfo)); + + return directoryInfo; +} + +Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(SourceId directorySourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch directory infos by source id"_t, + projectStorageCategory(), + keyValue("source id", directorySourceId)}; + + auto directoryInfos = s->selectDirectoryInfosForSourceIdStatement + .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 1024>( + directorySourceId); + + tracer.end(keyValue("directory infos", directoryInfos)); + + return directoryInfos; +} + +Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( + SourceId directorySourceId, Storage::Synchronization::FileType fileType) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch directory infos by source id and file type"_t, + projectStorageCategory(), + keyValue("source id", directorySourceId), + keyValue("file type", fileType)}; + + auto directoryInfos = s->selectDirectoryInfosForSourceIdAndFileTypeStatement + .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 16>( + directorySourceId, fileType); + + tracer.end(keyValue("directory infos", directoryInfos)); + + return directoryInfos; +} + +Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( + const SourceIds &directorySourceIds) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch directory infos by source ids"_t, + projectStorageCategory(), + keyValue("source ids", directorySourceIds)}; + + auto directoryInfos = s->selectDirectoryInfosForSourceIdsStatement + .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 64>( + toIntegers(directorySourceIds)); + + tracer.end(keyValue("directory infos", directoryInfos)); + + return directoryInfos; +} + +SmallSourceIds<32> ProjectStorage::fetchSubdirectorySourceIds(SourceId directorySourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch subdirectory source ids"_t, + projectStorageCategory(), + keyValue("source id", directorySourceId)}; + + auto sourceIds = s->selectDirectoryInfosSourceIdsForSourceIdAndFileTypeStatement + .valuesWithTransaction<SmallSourceIds<32>>( + directorySourceId, Storage::Synchronization::FileType::Directory); + + tracer.end(keyValue("source ids", sourceIds)); + + return sourceIds; +} + +void ProjectStorage::setPropertyEditorPathId(TypeId typeId, SourceId pathId) +{ + Sqlite::ImmediateSessionTransaction transaction{database}; + + s->upsertPropertyEditorPathIdStatement.write(typeId, pathId); + + transaction.commit(); +} + +SourceId ProjectStorage::propertyEditorPathId(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"property editor path id"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto sourceId = s->selectPropertyEditorPathIdStatement.valueWithTransaction<SourceId>(typeId); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Storage::Imports ProjectStorage::fetchDocumentImports() const +{ + NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()}; + + return s->selectAllDocumentImportForSourceIdStatement.valuesWithTransaction<Storage::Imports>(); +} + +void ProjectStorage::resetForTestsOnly() +{ + database.clearAllTablesForTestsOnly(); + commonTypeCache_.clearForTestsOnly(); + moduleCache.clearForTestOnly(); +} + +ModuleId ProjectStorage::fetchModuleId(Utils::SmallStringView moduleName, + Storage::ModuleKind moduleKind) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module id"_t, + projectStorageCategory(), + keyValue("module name", moduleName), + keyValue("module kind", moduleKind)}; + + auto moduleId = Sqlite::withDeferredTransaction(database, [&] { + return fetchModuleIdUnguarded(moduleName, moduleKind); + }); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Storage::Module ProjectStorage::fetchModule(ModuleId id) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module name"_t, + projectStorageCategory(), + keyValue("module id", id)}; + + auto module = Sqlite::withDeferredTransaction(database, [&] { return fetchModuleUnguarded(id); }); + + tracer.end(keyValue("module name", module.name)); + tracer.end(keyValue("module name", module.kind)); + + return module; +} + +ProjectStorage::ModuleCacheEntries ProjectStorage::fetchAllModules() const +{ + NanotraceHR::Tracer tracer{"fetch all modules"_t, projectStorageCategory()}; + + return s->selectAllModulesStatement.valuesWithTransaction<ModuleCacheEntry, 128>(); +} + +void ProjectStorage::callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"call refresh meta info callback"_t, + projectStorageCategory(), + keyValue("type ids", deletedTypeIds)}; + + if (deletedTypeIds.size()) { + for (ProjectStorageObserver *observer : observers) + observer->removedTypeIds(deletedTypeIds); + } +} + +SourceIds ProjectStorage::filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, + SourceIds &sourceIdsOfTypes) +{ + std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end()); + + SourceIds sourceIdsWithoutTypeSourceIds; + sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size()); + std::set_difference(updatedSourceIds.begin(), + updatedSourceIds.end(), + sourceIdsOfTypes.begin(), + sourceIdsOfTypes.end(), + std::back_inserter(sourceIdsWithoutTypeSourceIds)); + + return sourceIdsWithoutTypeSourceIds; +} + +TypeIds ProjectStorage::fetchTypeIds(const SourceIds &sourceIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type ids"_t, + projectStorageCategory(), + keyValue("source ids", sourceIds)}; + + return s->selectTypeIdsForSourceIdsStatement.values<TypeId, 128>(toIntegers(sourceIds)); +} + +void ProjectStorage::unique(SourceIds &sourceIds) +{ + std::sort(sourceIds.begin(), sourceIds.end()); + auto newEnd = std::unique(sourceIds.begin(), sourceIds.end()); + sourceIds.erase(newEnd, sourceIds.end()); +} + +void ProjectStorage::synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize type traits"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("type traits", traits)}; + + s->updateTypeAnnotationTraitStatement.write(typeId, traits.annotation); +} + +void ProjectStorage::updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations) +{ + NanotraceHR::Tracer tracer{"update type id in type annotations"_t, projectStorageCategory()}; + + for (auto &annotation : typeAnnotations) { + annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId, + annotation.typeName); + } + + typeAnnotations.erase(std::remove_if(typeAnnotations.begin(), + typeAnnotations.end(), + [](const auto &annotation) { return !annotation.typeId; }), + typeAnnotations.end()); +} + +void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations, + const SourceIds &updatedTypeAnnotationSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()}; + + using Storage::Synchronization::TypeAnnotation; + + updateTypeIdInTypeAnnotations(typeAnnotations); + + auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; }; + + std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) { + return first.typeId < second.typeId; + }); + + auto range = s->selectTypeAnnotationsForSourceIdsStatement.range<TypeAnnotationView>( + toIntegers(updatedTypeAnnotationSourceIds)); + + auto insert = [&](const TypeAnnotation &annotation) { + if (!annotation.sourceId) + throw TypeAnnotationHasInvalidSourceId{}; + + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert type annotations"_t, + projectStorageCategory(), + keyValue("type annotation", annotation)}; + + s->insertTypeAnnotationStatement.write(annotation.typeId, + annotation.sourceId, + annotation.directorySourceId, + annotation.typeName, + annotation.iconPath, + createEmptyAsNull(annotation.itemLibraryJson), + createEmptyAsNull(annotation.hintsJson)); + + synchronizeTypeTraits(annotation.typeId, annotation.traits); + }; + + auto update = [&](const TypeAnnotationView &annotationFromDatabase, + const TypeAnnotation &annotation) { + + if (annotationFromDatabase.typeName != annotation.typeName + || annotationFromDatabase.iconPath != annotation.iconPath + || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson + || annotationFromDatabase.hintsJson != annotation.hintsJson) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update type annotations"_t, + projectStorageCategory(), + keyValue("type annotation from database", + annotationFromDatabase), + keyValue("type annotation", annotation)}; + + s->updateTypeAnnotationStatement.write(annotation.typeId, + annotation.typeName, + annotation.iconPath, + createEmptyAsNull(annotation.itemLibraryJson), + createEmptyAsNull(annotation.hintsJson)); + + synchronizeTypeTraits(annotation.typeId, annotation.traits); + + return Sqlite::UpdateChange::Update; + } + + synchronizeTypeTraits(annotation.typeId, annotation.traits); + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const TypeAnnotationView &annotationFromDatabase) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove type annotations"_t, + projectStorageCategory(), + keyValue("type annotation", annotationFromDatabase)}; + + auto prototypeAnnotationTraits = s->selectPrototypeAnnotationTraitsByTypeIdStatement + .value<long long>(annotationFromDatabase.typeId); + s->deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId); + + s->updateTypeAnnotationTraitStatement.write(annotationFromDatabase.typeId, + prototypeAnnotationTraits); + }; + + Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeTypeTrait(const Storage::Synchronization::Type &type) +{ + s->updateTypeTraitStatement.write(type.typeId, type.traits.type); +} + +void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types, + TypeIds &updatedTypeIds, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + const SourceIds &updatedSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()}; + + Storage::Synchronization::ExportedTypes exportedTypes; + exportedTypes.reserve(types.size() * 3); + SourceIds sourceIdsOfTypes; + sourceIdsOfTypes.reserve(updatedSourceIds.size()); + SourceIds notUpdatedExportedSourceIds; + notUpdatedExportedSourceIds.reserve(updatedSourceIds.size()); + SourceIds exportedSourceIds; + exportedSourceIds.reserve(types.size()); + + for (auto &type : types) { + if (!type.sourceId) + throw TypeHasInvalidSourceId{}; + + TypeId typeId = declareType(type); + synchronizeTypeTrait(type); + sourceIdsOfTypes.push_back(type.sourceId); + updatedTypeIds.push_back(typeId); + if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) { + exportedSourceIds.push_back(type.sourceId); + extractExportedTypes(typeId, type, exportedTypes); + } + } + + std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) { + return first.typeId < second.typeId; + }); + + unique(exportedSourceIds); + + SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, sourceIdsOfTypes); + exportedSourceIds.insert(exportedSourceIds.end(), + sourceIdsWithoutType.begin(), + sourceIdsWithoutType.end()); + TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds); + synchronizeExportedTypes(exportedTypeIds, + exportedTypes, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions); + + syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); + resetDefaultPropertiesIfChanged(types); + resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); + syncDeclarations(types, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + relinkablePropertyDeclarations); + syncDefaultProperties(types); +} + +void ProjectStorage::synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, + const SourceIds &updatedDirectoryInfoSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize directory infos"_t, projectStorageCategory()}; + + auto compareKey = [](auto &&first, auto &&second) { + auto directorySourceIdDifference = first.directorySourceId - second.directorySourceId; + if (directorySourceIdDifference != 0) + return directorySourceIdDifference; + + return first.sourceId - second.sourceId; + }; + + std::sort(directoryInfos.begin(), directoryInfos.end(), [&](auto &&first, auto &&second) { + return std::tie(first.directorySourceId, first.sourceId) + < std::tie(second.directorySourceId, second.sourceId); + }); + + auto range = s->selectDirectoryInfosForSourceIdsStatement.range<Storage::Synchronization::DirectoryInfo>( + toIntegers(updatedDirectoryInfoSourceIds)); + + auto insert = [&](const Storage::Synchronization::DirectoryInfo &directoryInfo) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert directory info"_t, + projectStorageCategory(), + keyValue("directory info", directoryInfo)}; + + if (!directoryInfo.directorySourceId) + throw DirectoryInfoHasInvalidProjectSourceId{}; + if (!directoryInfo.sourceId) + throw DirectoryInfoHasInvalidSourceId{}; + + s->insertDirectoryInfoStatement.write(directoryInfo.directorySourceId, + directoryInfo.sourceId, + directoryInfo.moduleId, + directoryInfo.fileType); + }; + + auto update = [&](const Storage::Synchronization::DirectoryInfo &directoryInfoFromDatabase, + const Storage::Synchronization::DirectoryInfo &directoryInfo) { + if (directoryInfoFromDatabase.fileType != directoryInfo.fileType + || !compareInvalidAreTrue(directoryInfoFromDatabase.moduleId, directoryInfo.moduleId)) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update directory info"_t, + projectStorageCategory(), + keyValue("directory info", directoryInfo), + keyValue("directory info from database", + directoryInfoFromDatabase)}; + + s->updateDirectoryInfoStatement.write(directoryInfo.directorySourceId, + directoryInfo.sourceId, + directoryInfo.moduleId, + directoryInfo.fileType); + return Sqlite::UpdateChange::Update; + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::DirectoryInfo &directoryInfo) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove directory info"_t, + projectStorageCategory(), + keyValue("directory info", directoryInfo)}; + + s->deleteDirectoryInfoStatement.write(directoryInfo.directorySourceId, directoryInfo.sourceId); + }; + + Sqlite::insertUpdateDelete(range, directoryInfos, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeFileStatuses(FileStatuses &fileStatuses, + const SourceIds &updatedSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()}; + + auto compareKey = [](auto &&first, auto &&second) { return first.sourceId - second.sourceId; }; + + std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) { + return first.sourceId < second.sourceId; + }); + + auto range = s->selectFileStatusesForSourceIdsStatement.range<FileStatus>( + toIntegers(updatedSourceIds)); + + auto insert = [&](const FileStatus &fileStatus) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus)}; + + if (!fileStatus.sourceId) + throw FileStatusHasInvalidSourceId{}; + s->insertFileStatusStatement.write(fileStatus.sourceId, + fileStatus.size, + fileStatus.lastModified); + }; + + auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) { + if (fileStatusFromDatabase.lastModified != fileStatus.lastModified + || fileStatusFromDatabase.size != fileStatus.size) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus), + keyValue("file status from database", fileStatusFromDatabase)}; + + s->updateFileStatusStatement.write(fileStatus.sourceId, + fileStatus.size, + fileStatus.lastModified); + return Sqlite::UpdateChange::Update; + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const FileStatus &fileStatus) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove file status"_t, + projectStorageCategory(), + keyValue("file status", fileStatus)}; + + s->deleteFileStatusStatement.write(fileStatus.sourceId); + }; + + Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeImports(Storage::Imports &imports, + const SourceIds &updatedSourceIds, + Storage::Imports &moduleDependencies, + const SourceIds &updatedModuleDependencySourceIds, + Storage::Synchronization::ModuleExportedImports &moduleExportedImports, + const ModuleIds &updatedModuleIds, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()}; + + synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds); + NanotraceHR::Tracer importTracer{"synchronize qml document imports"_t, projectStorageCategory()}; + synchronizeDocumentImports(imports, + updatedSourceIds, + Storage::Synchronization::ImportKind::Import, + Relink::No, + relinkablePrototypes, + relinkableExtensions); + importTracer.end(); + NanotraceHR::Tracer moduleDependenciesTracer{"synchronize module depdencies"_t, + projectStorageCategory()}; + synchronizeDocumentImports(moduleDependencies, + updatedModuleDependencySourceIds, + Storage::Synchronization::ImportKind::ModuleDependency, + Relink::Yes, + relinkablePrototypes, + relinkableExtensions); + moduleDependenciesTracer.end(); +} + +void ProjectStorage::synchromizeModuleExportedImports( + Storage::Synchronization::ModuleExportedImports &moduleExportedImports, + const ModuleIds &updatedModuleIds) +{ + NanotraceHR::Tracer tracer{"synchronize module exported imports"_t, projectStorageCategory()}; + std::sort(moduleExportedImports.begin(), + moduleExportedImports.end(), + [](auto &&first, auto &&second) { + return std::tie(first.moduleId, first.exportedModuleId) + < std::tie(second.moduleId, second.exportedModuleId); + }); + + auto range = s->selectModuleExportedImportsForSourceIdStatement + .range<Storage::Synchronization::ModuleExportedImportView>( + toIntegers(updatedModuleIds)); + + auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view, + const Storage::Synchronization::ModuleExportedImport &import) -> long long { + auto moduleIdDifference = view.moduleId - import.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + return view.exportedModuleId - import.exportedModuleId; + }; + + auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert module exported import"_t, + projectStorageCategory(), + keyValue("module exported import", import), + keyValue("module id", import.moduleId)}; + tracer.tick("exported module"_t, keyValue("module id", import.exportedModuleId)); + + if (import.version.minor) { + s->insertModuleExportedImportWithVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion, + import.version.major.value, + import.version.minor.value); + } else if (import.version.major) { + s->insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion, + import.version.major.value); + } else { + s->insertModuleExportedImportWithoutVersionStatement.write(import.moduleId, + import.exportedModuleId, + import.isAutoVersion); + } + }; + + auto update = [](const Storage::Synchronization::ModuleExportedImportView &, + const Storage::Synchronization::ModuleExportedImport &) { + return Sqlite::UpdateChange::No; + }; -template class QmlDesigner::ProjectStorage<Sqlite::Database>; + auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove module exported import"_t, + projectStorageCategory(), + keyValue("module exported import view", view), + keyValue("module id", view.moduleId)}; + tracer.tick("exported module"_t, keyValue("module id", view.exportedModuleId)); + + s->deleteModuleExportedImportStatement.write(view.moduleExportedImportId); + }; + + Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove); +} + +ModuleId ProjectStorage::fetchModuleIdUnguarded(Utils::SmallStringView name, + Storage::ModuleKind kind) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module id ungarded"_t, + projectStorageCategory(), + keyValue("module name", name), + keyValue("module kind", kind)}; + + auto moduleId = s->selectModuleIdByNameStatement.value<ModuleId>(kind, name); + + if (!moduleId) + moduleId = s->insertModuleNameStatement.value<ModuleId>(kind, name); + + tracer.end(keyValue("module id", moduleId)); + + return moduleId; +} + +Storage::Module ProjectStorage::fetchModuleUnguarded(ModuleId id) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch module ungarded"_t, + projectStorageCategory(), + keyValue("module id", id)}; + + auto module = s->selectModuleStatement.value<Storage::Module>(id); + + if (!module) + throw ModuleDoesNotExists{}; + + tracer.end(keyValue("module name", module.name)); + tracer.end(keyValue("module name", module.kind)); + + return module; +} + +void ProjectStorage::handleAliasPropertyDeclarationsWithPropertyType( + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle alias property declarations with property type"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("relinkable alias property declarations", + relinkableAliasPropertyDeclarations)}; + + auto callback = [&](TypeId typeId_, + PropertyDeclarationId propertyDeclarationId, + ImportedTypeNameId propertyImportedTypeNameId, + PropertyDeclarationId aliasPropertyDeclarationId, + PropertyDeclarationId aliasPropertyDeclarationTailId) { + auto aliasPropertyName = s->selectPropertyNameStatement.value<Utils::SmallString>( + aliasPropertyDeclarationId); + Utils::SmallString aliasPropertyNameTail; + if (aliasPropertyDeclarationTailId) + aliasPropertyNameTail = s->selectPropertyNameStatement.value<Utils::SmallString>( + aliasPropertyDeclarationTailId); + + relinkableAliasPropertyDeclarations.emplace_back(TypeId{typeId_}, + PropertyDeclarationId{propertyDeclarationId}, + ImportedTypeNameId{propertyImportedTypeNameId}, + std::move(aliasPropertyName), + std::move(aliasPropertyNameTail)); + + s->updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); + }; + + s->selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback, typeId); +} + +void ProjectStorage::handlePropertyDeclarationWithPropertyType( + TypeId typeId, PropertyDeclarations &relinkablePropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle property declarations with property type"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("relinkable property declarations", + relinkablePropertyDeclarations)}; + + s->updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, + typeId); +} + +void ProjectStorage::handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle prototypes"_t, + projectStorageCategory(), + keyValue("type id", prototypeId), + keyValue("relinkable prototypes", relinkablePrototypes)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { + if (prototypeNameId) + relinkablePrototypes.emplace_back(typeId, prototypeNameId); + }; + + s->updatePrototypeIdToTypeIdStatement.readCallback(callback, prototypeId, unresolvedTypeId); +} + +void ProjectStorage::handlePrototypesWithExportedTypeNameAndTypeId( + Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkablePrototypes) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle invalid prototypes"_t, + projectStorageCategory(), + keyValue("type id", exportedTypeName), + keyValue("relinkable prototypes", relinkablePrototypes)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { + relinkablePrototypes.emplace_back(typeId, prototypeNameId); + }; + + s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement.readCallback(callback, + exportedTypeName, + typeId); +} + +void ProjectStorage::handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle extension"_t, + projectStorageCategory(), + keyValue("type id", extensionId), + keyValue("relinkable extensions", relinkableExtensions)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { + if (extensionNameId) + relinkableExtensions.emplace_back(typeId, extensionNameId); + }; + + s->updateExtensionIdToTypeIdStatement.readCallback(callback, extensionId, unresolvedTypeId); +} + +void ProjectStorage::handleExtensionsWithExportedTypeNameAndTypeId( + Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle invalid extensions"_t, + projectStorageCategory(), + keyValue("type id", exportedTypeName), + keyValue("relinkable extensions", relinkableExtensions)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { + relinkableExtensions.emplace_back(typeId, extensionNameId); + }; + + s->selectTypeIdForExtensionIdAndTypeNameStatement.readCallback(callback, exportedTypeName, typeId); +} + +void ProjectStorage::deleteType(TypeId typeId, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"delete type"_t, projectStorageCategory(), keyValue("type id", typeId)}; + + handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); + handlePrototypes(typeId, relinkablePrototypes); + handleExtensions(typeId, relinkableExtensions); + s->deleteTypeNamesByTypeIdStatement.write(typeId); + s->deleteEnumerationDeclarationByTypeIdStatement.write(typeId); + s->deletePropertyDeclarationByTypeIdStatement.write(typeId); + s->deleteFunctionDeclarationByTypeIdStatement.write(typeId); + s->deleteSignalDeclarationByTypeIdStatement.write(typeId); + s->deleteTypeStatement.write(typeId); +} + +void ProjectStorage::relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, + const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"relink alias properties"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasPropertyDeclarations), + keyValue("deleted type ids", deletedTypeIds)}; + + std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); + + Utils::set_greedy_difference( + aliasPropertyDeclarations.cbegin(), + aliasPropertyDeclarations.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const AliasPropertyDeclaration &alias) { + auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); + + if (!typeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)}; + + auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( + typeId, alias.aliasPropertyName); + + s->updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId, + propertyTypeId, + propertyTraits, + alias.aliasImportedTypeNameId, + aliasId); + }, + TypeCompare<AliasPropertyDeclaration>{}); +} + +void ProjectStorage::relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, + const TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"relink property declarations"_t, + projectStorageCategory(), + keyValue("relinkable property declarations", + relinkablePropertyDeclaration), + keyValue("deleted type ids", deletedTypeIds)}; + + std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); + + Utils::set_greedy_difference( + relinkablePropertyDeclaration.cbegin(), + relinkablePropertyDeclaration.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const PropertyDeclaration &property) { + TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)}; + + s->updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId, + propertyTypeId); + }, + TypeCompare<PropertyDeclaration>{}); +} + +template<typename Callable> +void ProjectStorage::relinkPrototypes(Prototypes &relinkablePrototypes, + const TypeIds &deletedTypeIds, + Callable updateStatement) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"relink prototypes"_t, + projectStorageCategory(), + keyValue("relinkable prototypes", relinkablePrototypes), + keyValue("deleted type ids", deletedTypeIds)}; + + std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end()); + relinkablePrototypes.erase(std::unique(relinkablePrototypes.begin(), relinkablePrototypes.end()), + relinkablePrototypes.end()); + + Utils::set_greedy_difference( + relinkablePrototypes.cbegin(), + relinkablePrototypes.cend(), + deletedTypeIds.begin(), + deletedTypeIds.end(), + [&](const Prototype &prototype) { + TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); + + if (!prototypeId) + errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName(prototype.prototypeNameId), + fetchTypeSourceId(prototype.typeId)); + + updateStatement(prototype.typeId, prototypeId); + checkForPrototypeChainCycle(prototype.typeId); + }, + TypeCompare<Prototype>{}); +} + +void ProjectStorage::deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, + const SourceIds &updatedSourceIds, + const TypeIds &typeIdsToBeDeleted, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + TypeIds &deletedTypeIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"delete not updated types"_t, + projectStorageCategory(), + keyValue("updated type ids", updatedTypeIds), + keyValue("updated source ids", updatedSourceIds), + keyValue("type ids to be deleted", typeIdsToBeDeleted)}; + + auto callback = [&](TypeId typeId) { + deletedTypeIds.push_back(typeId); + deleteType(typeId, + relinkableAliasPropertyDeclarations, + relinkablePropertyDeclarations, + relinkablePrototypes, + relinkableExtensions); + }; + + s->selectNotUpdatedTypesInSourcesStatement.readCallback(callback, + toIntegers(updatedSourceIds), + toIntegers(updatedTypeIds)); + for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) + callback(typeIdToBeDeleted); +} + +void ProjectStorage::relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, + TypeIds &deletedTypeIds) +{ + NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()}; + + std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); + + relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { + s->updateTypePrototypeStatement.write(typeId, prototypeId); + }); + relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { + s->updateTypeExtensionStatement.write(typeId, prototypeId); + }); + relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds); + relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); +} + +PropertyDeclarationId ProjectStorage::fetchAliasId(TypeId aliasTypeId, + Utils::SmallStringView aliasPropertyName, + Utils::SmallStringView aliasPropertyNameTail) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch alias id"_t, + projectStorageCategory(), + keyValue("alias type id", aliasTypeId), + keyValue("alias property name", aliasPropertyName), + keyValue("alias property name tail", aliasPropertyNameTail)}; + + if (aliasPropertyNameTail.empty()) + return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); + + auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); + + return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId, + aliasPropertyNameTail); +} + +void ProjectStorage::linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"link alias property declarations alias ids"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + + for (const auto &aliasDeclaration : aliasDeclarations) { + auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); + + if (!aliasTypeId) { + throw TypeNameDoesNotExists{ + fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)}; + } + + auto aliasId = fetchAliasId(aliasTypeId, + aliasDeclaration.aliasPropertyName, + aliasDeclaration.aliasPropertyNameTail); + + s->updatePropertyDeclarationAliasIdAndTypeNameIdStatement.write( + aliasDeclaration.propertyDeclarationId, aliasId, aliasDeclaration.aliasImportedTypeNameId); + } +} + +void ProjectStorage::updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update alias property declarations"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + + for (const auto &aliasDeclaration : aliasDeclarations) { + s->updatetPropertiesDeclarationValuesOfAliasStatement.write( + aliasDeclaration.propertyDeclarationId); + s->updatePropertyAliasDeclarationRecursivelyStatement.write( + aliasDeclaration.propertyDeclarationId); + } +} + +void ProjectStorage::checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check alias property declarations cycles"_t, + projectStorageCategory(), + keyValue("alias property declarations", aliasDeclarations)}; + for (const auto &aliasDeclaration : aliasDeclarations) + checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); +} + +void ProjectStorage::linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()}; + + linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); + linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); + + checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations); + checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations); + + updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations); + updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); +} + +void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds, + Storage::Synchronization::ExportedTypes &exportedTypes, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()}; + + std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { + if (first.moduleId < second.moduleId) + return true; + else if (first.moduleId > second.moduleId) + return false; + + auto nameCompare = Sqlite::compare(first.name, second.name); + + if (nameCompare < 0) + return true; + else if (nameCompare > 0) + return false; + + return first.version < second.version; + }); + + auto range = s->selectExportedTypesForSourceIdsStatement + .range<Storage::Synchronization::ExportedTypeView>(toIntegers(updatedTypeIds)); + + auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view, + const Storage::Synchronization::ExportedType &type) -> long long { + auto moduleIdDifference = view.moduleId - type.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + auto nameDifference = Sqlite::compare(view.name, type.name); + if (nameDifference != 0) + return nameDifference; + + auto versionDifference = view.version.major.value - type.version.major.value; + if (versionDifference != 0) + return versionDifference; + + return view.version.minor.value - type.version.minor.value; + }; + + auto insert = [&](const Storage::Synchronization::ExportedType &type) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert exported type"_t, + projectStorageCategory(), + keyValue("exported type", type), + keyValue("type id", type.typeId), + keyValue("module id", type.moduleId)}; + if (!type.moduleId) + throw QmlDesigner::ModuleDoesNotExists{}; + + try { + if (type.version) { + s->insertExportedTypeNamesWithVersionStatement.write(type.moduleId, + type.name, + type.version.major.value, + type.version.minor.value, + type.typeId); + + } else if (type.version.major) { + s->insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId, + type.name, + type.version.major.value, + type.typeId); + } else { + s->insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId, + type.name, + type.typeId); + } + } catch (const Sqlite::ConstraintPreventsModification &) { + throw QmlDesigner::ExportedTypeCannotBeInserted{type.name}; + } + + handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes); + handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions); + }; + + auto update = [&](const Storage::Synchronization::ExportedTypeView &view, + const Storage::Synchronization::ExportedType &type) { + if (view.typeId != type.typeId) { + NanotraceHR::Tracer tracer{"update exported type"_t, + projectStorageCategory(), + keyValue("exported type", type), + keyValue("exported type view", view), + keyValue("type id", type.typeId), + keyValue("module id", type.typeId)}; + + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); + s->updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); + return Sqlite::UpdateChange::Update; + } + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) { + NanotraceHR::Tracer tracer{"remove exported type"_t, + projectStorageCategory(), + keyValue("exported type", view), + keyValue("type id", view.typeId), + keyValue("module id", view.moduleId)}; + + handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); + handleAliasPropertyDeclarationsWithPropertyType(view.typeId, + relinkableAliasPropertyDeclarations); + handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); + + s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId); + }; + + Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizePropertyDeclarationsInsertAlias( + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId, + TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property declaration to alias"_t, + projectStorageCategory(), + keyValue("property declaration", value)}; + + auto callback = [&](PropertyDeclarationId propertyDeclarationId) { + insertedAliasPropertyDeclarations.emplace_back(typeId, + propertyDeclarationId, + fetchImportedTypeNameId(value.typeName, + sourceId), + value.aliasPropertyName, + value.aliasPropertyNameTail); + return Sqlite::CallbackControl::Abort; + }; + + s->insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name); +} + +QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::fetchPropertyDeclarationIds( + TypeId baseTypeId) const +{ + QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds; + + s->selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, baseTypeId); + + auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + s->selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, prototype); + } + + return propertyDeclarationIds; +} + +PropertyDeclarationId ProjectStorage::fetchNextPropertyDeclarationId( + TypeId baseTypeId, Utils::SmallStringView propertyName) const +{ + auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + auto propertyDeclarationId = s->selectPropertyDeclarationIdByTypeIdAndNameStatement + .value<PropertyDeclarationId>(prototype, propertyName); + + if (propertyDeclarationId) + return propertyDeclarationId; + } + + return PropertyDeclarationId{}; +} + +PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const +{ + auto propertyDeclarationId = s->selectPropertyDeclarationIdByTypeIdAndNameStatement + .value<PropertyDeclarationId>(typeId, propertyName); + + if (propertyDeclarationId) + return propertyDeclarationId; + + return fetchNextPropertyDeclarationId(typeId, propertyName); +} + +PropertyDeclarationId ProjectStorage::fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const +{ + auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId); + + for (TypeId prototype : range) { + auto propertyDeclarationId = s->selectDefaultPropertyDeclarationIdStatement + .value<PropertyDeclarationId>(prototype); + + if (propertyDeclarationId) + return propertyDeclarationId; + } + + return PropertyDeclarationId{}; +} + +PropertyDeclarationId ProjectStorage::fetchDefaultPropertyDeclarationId(TypeId typeId) const +{ + auto propertyDeclarationId = s->selectDefaultPropertyDeclarationIdStatement + .value<PropertyDeclarationId>(typeId); + + if (propertyDeclarationId) + return propertyDeclarationId; + + return fetchNextDefaultPropertyDeclarationId(typeId); +} + +void ProjectStorage::synchronizePropertyDeclarationsInsertProperty( + const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property declaration"_t, + projectStorageCategory(), + keyValue("property declaration", value)}; + + auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); + auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; + + auto propertyDeclarationId = s->insertPropertyDeclarationStatement.value<PropertyDeclarationId>( + typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId); + + auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, value.name); + if (nextPropertyDeclarationId) { + s->updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId, + propertyDeclarationId); + s->updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement + .write(propertyDeclarationId, propertyTypeId, value.traits); + } +} + +void ProjectStorage::synchronizePropertyDeclarationsUpdateAlias( + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property declaration to alias"_t, + projectStorageCategory(), + keyValue("property declaration", value), + keyValue("property declaration view", view)}; + + updatedAliasPropertyDeclarations.emplace_back(view.typeId, + view.id, + fetchImportedTypeNameId(value.typeName, sourceId), + value.aliasPropertyName, + value.aliasPropertyNameTail, + view.aliasId); +} + +Sqlite::UpdateChange ProjectStorage::synchronizePropertyDeclarationsUpdateProperty( + const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value, + SourceId sourceId, + PropertyDeclarationIds &propertyDeclarationIds) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property declaration"_t, + projectStorageCategory(), + keyValue("property declaration", value), + keyValue("property declaration view", view)}; + + auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); + + auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); + + if (!propertyTypeId) + throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId}; + + if (view.traits == value.traits && propertyTypeId == view.typeId + && propertyImportedTypeNameId == view.typeNameId) + return Sqlite::UpdateChange::No; + + s->updatePropertyDeclarationStatement.write(view.id, + propertyTypeId, + value.traits, + propertyImportedTypeNameId); + s->updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id, + propertyTypeId, + value.traits); + propertyDeclarationIds.push_back(view.id); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; +} + +void ProjectStorage::synchronizePropertyDeclarations( + TypeId typeId, + Storage::Synchronization::PropertyDeclarations &propertyDeclarations, + SourceId sourceId, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()}; + + std::sort(propertyDeclarations.begin(), propertyDeclarations.end(), [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = s->selectPropertyDeclarationsForTypeIdStatement + .range<Storage::Synchronization::PropertyDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) { + if (value.kind == Storage::Synchronization::PropertyKind::Alias) { + synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations, + value, + sourceId, + typeId); + } else { + synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId); + } + }; + + auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + if (value.kind == Storage::Synchronization::PropertyKind::Alias) { + synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations, + view, + value, + sourceId); + propertyDeclarationIds.push_back(view.id); + } else { + return synchronizePropertyDeclarationsUpdateProperty(view, + value, + sourceId, + propertyDeclarationIds); + } + + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove property declaration"_t, + projectStorageCategory(), + keyValue("property declaratio viewn", view)}; + + auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, view.name); + + if (nextPropertyDeclarationId) { + s->updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement + .write(nextPropertyDeclarationId, view.id); + } + + s->updateDefaultPropertyIdToNullStatement.write(view.id); + s->deletePropertyDeclarationStatement.write(view.id); + propertyDeclarationIds.push_back(view.id); + }; + + Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull( + Storage::Synchronization::Type &type, PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, + projectStorageCategory()}; + + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; + + std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = s->selectPropertyDeclarationsWithAliasForTypeIdStatement + .range<AliasPropertyDeclarationView>(type.typeId); + + auto compareKey = [](const AliasPropertyDeclarationView &view, + const Storage::Synchronization::PropertyDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {}; + + auto update = [&](const AliasPropertyDeclarationView &, + const Storage::Synchronization::PropertyDeclaration &) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const AliasPropertyDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t, + projectStorageCategory(), + keyValue("alias property declaration view", view)}; + + s->updatePropertyDeclarationAliasIdToNullStatement.write(view.id); + propertyDeclarationIds.push_back(view.id); + }; + + Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull( + Storage::Synchronization::Types &types, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) +{ + NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t, projectStorageCategory()}; + + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size()); + + for (auto &&type : types) + resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); + + removeRelinkableEntries(relinkableAliasPropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<AliasPropertyDeclaration>{}); +} + +void ProjectStorage::handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId, + TypeId prototypeId, + Prototypes &relinkablePrototypes) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("type id", prototypeId)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { + if (prototypeNameId) + relinkablePrototypes.emplace_back(typeId, prototypeNameId); + }; + + s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement.readCallback(callback, + prototypeId, + sourceId); +} + +void ProjectStorage::handlePrototypesAndExtensionsWithSourceId(SourceId sourceId, + TypeId prototypeId, + TypeId extensionId, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle prototypes with source id"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("prototype id", prototypeId), + keyValue("extension id", extensionId)}; + + auto callback = + [&](TypeId typeId, ImportedTypeNameId prototypeNameId, ImportedTypeNameId extensionNameId) { + if (prototypeNameId) + relinkablePrototypes.emplace_back(typeId, prototypeNameId); + if (extensionNameId) + relinkableExtensions.emplace_back(typeId, extensionNameId); + }; + + s->updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement.readCallback(callback, + sourceId, + prototypeId, + extensionId); +} + +void ProjectStorage::handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId, + TypeId extensionId, + Prototypes &relinkableExtensions) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t, + projectStorageCategory(), + keyValue("source id", sourceId), + keyValue("type id", extensionId)}; + + auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { + if (extensionNameId) + relinkableExtensions.emplace_back(typeId, extensionNameId); + }; + + s->selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement.readCallback(callback, + extensionId, + sourceId); +} + +ImportId ProjectStorage::insertDocumentImport(const Storage::Import &import, + Storage::Synchronization::ImportKind importKind, + ModuleId sourceModuleId, + ImportId parentImportId, + Relink relink, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + if (relink == Relink::Yes) { + handlePrototypesWithSourceIdAndPrototypeId(import.sourceId, + unresolvedTypeId, + relinkablePrototypes); + handleExtensionsWithSourceIdAndExtensionId(import.sourceId, + unresolvedTypeId, + relinkableExtensions); + } + + if (import.version.minor) { + return s->insertDocumentImportWithVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + import.version.major.value, + import.version.minor.value, + parentImportId); + } else if (import.version.major) { + return s->insertDocumentImportWithMajorVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + import.version.major.value, + parentImportId); + } else { + return s->insertDocumentImportWithoutVersionStatement.value<ImportId>(import.sourceId, + import.moduleId, + sourceModuleId, + importKind, + parentImportId); + } +} + +void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports, + const SourceIds &updatedSourceIds, + Storage::Synchronization::ImportKind importKind, + Relink relink, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) { + return std::tie(first.sourceId, first.moduleId, first.version) + < std::tie(second.sourceId, second.moduleId, second.version); + }); + + auto range = s->selectDocumentImportForSourceIdStatement + .range<Storage::Synchronization::ImportView>(toIntegers(updatedSourceIds), + importKind); + + auto compareKey = [](const Storage::Synchronization::ImportView &view, + const Storage::Import &import) -> long long { + auto sourceIdDifference = view.sourceId - import.sourceId; + if (sourceIdDifference != 0) + return sourceIdDifference; + + auto moduleIdDifference = view.moduleId - import.moduleId; + if (moduleIdDifference != 0) + return moduleIdDifference; + + auto versionDifference = view.version.major.value - import.version.major.value; + if (versionDifference != 0) + return versionDifference; + + return view.version.minor.value - import.version.minor.value; + }; + + auto insert = [&](const Storage::Import &import) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert import"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("import kind", importKind), + keyValue("source id", import.sourceId), + keyValue("module id", import.moduleId)}; + + auto importId = insertDocumentImport(import, + importKind, + import.moduleId, + ImportId{}, + relink, + relinkablePrototypes, + relinkableExtensions); + auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) { + Storage::Import additionImport{exportedModuleId, + Storage::Version{majorVersion, minorVersion}, + import.sourceId}; + + auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import + ? Storage::Synchronization::ImportKind::ModuleExportedImport + : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency; + + NanotraceHR::Tracer tracer{"insert indirect import"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("import kind", exportedImportKind), + keyValue("source id", import.sourceId), + keyValue("module id", import.moduleId)}; + + auto indirectImportId = insertDocumentImport(additionImport, + exportedImportKind, + import.moduleId, + importId, + relink, + relinkablePrototypes, + relinkableExtensions); + + tracer.end(keyValue("import id", indirectImportId)); + }; + + s->selectModuleExportedImportsForModuleIdStatement.readCallback(callback, + import.moduleId, + import.version.major.value, + import.version.minor.value); + tracer.end(keyValue("import id", importId)); + }; + + auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::ImportView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove import"_t, + projectStorageCategory(), + keyValue("import", view), + keyValue("import id", view.importId), + keyValue("source id", view.sourceId), + keyValue("module id", view.moduleId)}; + + s->deleteDocumentImportStatement.write(view.importId); + s->deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId); + if (relink == Relink::Yes) { + handlePrototypesAndExtensionsWithSourceId(view.sourceId, + unresolvedTypeId, + unresolvedTypeId, + relinkablePrototypes, + relinkableExtensions); + } + }; + + Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove); +} + +Utils::PathString ProjectStorage::createJson(const Storage::Synchronization::ParameterDeclarations ¶meters) +{ + NanotraceHR::Tracer tracer{"create json from parameter declarations"_t, projectStorageCategory()}; + + Utils::PathString json; + json.append("["); + + Utils::SmallStringView comma{""}; + + for (const auto ¶meter : parameters) { + json.append(comma); + comma = ","; + json.append(R"({"n":")"); + json.append(parameter.name); + json.append(R"(","tn":")"); + json.append(parameter.typeName); + if (parameter.traits == Storage::PropertyDeclarationTraits::None) { + json.append("\"}"); + } else { + json.append(R"(","tr":)"); + json.append(Utils::SmallString::number(Utils::to_underlying(parameter.traits))); + json.append("}"); + } + } + + json.append("]"); + + return json; +} + +TypeId ProjectStorage::fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, + Utils::SmallStringView name) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id by module id and exported name"_t, + projectStorageCategory(), + keyValue("module id", moduleId), + keyValue("exported name", name)}; + + return s->selectTypeIdByModuleIdAndExportedNameStatement.value<TypeId>(moduleId, name); +} + +void ProjectStorage::addTypeIdToPropertyEditorQmlPaths( + Storage::Synchronization::PropertyEditorQmlPaths &paths) +{ + NanotraceHR::Tracer tracer{"add type id to property editor qml paths"_t, projectStorageCategory()}; + + for (auto &path : paths) + path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName); +} + +void ProjectStorage::synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, + SourceIds updatedPropertyEditorQmlPathsSourceIds) +{ + using Storage::Synchronization::PropertyEditorQmlPath; + std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) { + return first.typeId < second.typeId; + }); + + auto range = s->selectPropertyEditorPathsForForSourceIdsStatement.range<PropertyEditorQmlPathView>( + toIntegers(updatedPropertyEditorQmlPathsSourceIds)); + + auto compareKey = [](const PropertyEditorQmlPathView &view, + const PropertyEditorQmlPath &value) -> long long { + return view.typeId - value.typeId; + }; + + auto insert = [&](const PropertyEditorQmlPath &path) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path", path)}; + + if (path.typeId) + s->insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId); + }; + + auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path", value), + keyValue("property editor qml path view", view)}; + + if (value.pathId != view.pathId || value.directoryId != view.directoryId) { + s->updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + } + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const PropertyEditorQmlPathView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove property editor paths"_t, + projectStorageCategory(), + keyValue("property editor qml path view", view)}; + + s->deletePropertyEditorPathStatement.write(view.typeId); + }; + + Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizePropertyEditorQmlPaths( + Storage::Synchronization::PropertyEditorQmlPaths &paths, + SourceIds updatedPropertyEditorQmlPathsSourceIds) +{ + NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t, projectStorageCategory()}; + + addTypeIdToPropertyEditorQmlPaths(paths); + synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds); +} + +void ProjectStorage::synchronizeFunctionDeclarations( + TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()}; + + std::sort(functionsDeclarations.begin(), + functionsDeclarations.end(), + [](auto &&first, auto &&second) { + auto compare = Sqlite::compare(first.name, second.name); + + if (compare == 0) { + Utils::PathString firstSignature{createJson(first.parameters)}; + Utils::PathString secondSignature{createJson(second.parameters)}; + + return Sqlite::compare(firstSignature, secondSignature) < 0; + } + + return compare < 0; + }); + + auto range = s->selectFunctionDeclarationsForTypeIdStatement + .range<Storage::Synchronization::FunctionDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view, + const Storage::Synchronization::FunctionDeclaration &value) { + auto nameKey = Sqlite::compare(view.name, value.name); + if (nameKey != 0) + return nameKey; + + Utils::PathString valueSignature{createJson(value.parameters)}; + + return Sqlite::compare(view.signature, valueSignature); + }; + + auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert function declaration"_t, + projectStorageCategory(), + keyValue("function declaration", value)}; + + Utils::PathString signature{createJson(value.parameters)}; + + s->insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature); + }; + + auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view, + const Storage::Synchronization::FunctionDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update function declaration"_t, + projectStorageCategory(), + keyValue("function declaration", value), + keyValue("function declaration view", view)}; + + Utils::PathString signature{createJson(value.parameters)}; + + if (value.returnTypeName == view.returnTypeName && signature == view.signature) + return Sqlite::UpdateChange::No; + + s->updateFunctionDeclarationStatement.write(view.id, value.returnTypeName, signature); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove function declaration"_t, + projectStorageCategory(), + keyValue("function declaration view", view)}; + + s->deleteFunctionDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::synchronizeSignalDeclarations( + TypeId typeId, Storage::Synchronization::SignalDeclarations &signalDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()}; + + std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) { + auto compare = Sqlite::compare(first.name, second.name); + + if (compare == 0) { + Utils::PathString firstSignature{createJson(first.parameters)}; + Utils::PathString secondSignature{createJson(second.parameters)}; + + return Sqlite::compare(firstSignature, secondSignature) < 0; + } + + return compare < 0; + }); + + auto range = s->selectSignalDeclarationsForTypeIdStatement + .range<Storage::Synchronization::SignalDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view, + const Storage::Synchronization::SignalDeclaration &value) { + auto nameKey = Sqlite::compare(view.name, value.name); + if (nameKey != 0) + return nameKey; + + Utils::PathString valueSignature{createJson(value.parameters)}; + + return Sqlite::compare(view.signature, valueSignature); + }; + + auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert signal declaration"_t, + projectStorageCategory(), + keyValue("signal declaration", value)}; + + Utils::PathString signature{createJson(value.parameters)}; + + s->insertSignalDeclarationStatement.write(typeId, value.name, signature); + }; + + auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view, + [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) { + return Sqlite::UpdateChange::No; + }; + + auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove signal declaration"_t, + projectStorageCategory(), + keyValue("signal declaration view", view)}; + + s->deleteSignalDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove); +} + +Utils::PathString ProjectStorage::createJson( + const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"create json from enumerator declarations"_t, projectStorageCategory()}; + + Utils::PathString json; + json.append("{"); + + Utils::SmallStringView comma{"\""}; + + for (const auto &enumerator : enumeratorDeclarations) { + json.append(comma); + comma = ",\""; + json.append(enumerator.name); + if (enumerator.hasValue) { + json.append("\":\""); + json.append(Utils::SmallString::number(enumerator.value)); + json.append("\""); + } else { + json.append("\":null"); + } + } + + json.append("}"); + + return json; +} + +void ProjectStorage::synchronizeEnumerationDeclarations( + TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize enumeration declaration"_t, projectStorageCategory()}; + + std::sort(enumerationDeclarations.begin(), + enumerationDeclarations.end(), + [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = s->selectEnumerationDeclarationsForTypeIdStatement + .range<Storage::Synchronization::EnumerationDeclarationView>(typeId); + + auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view, + const Storage::Synchronization::EnumerationDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"insert enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration", value)}; + + Utils::PathString signature{createJson(value.enumeratorDeclarations)}; + + s->insertEnumerationDeclarationStatement.write(typeId, value.name, signature); + }; + + auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view, + const Storage::Synchronization::EnumerationDeclaration &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"update enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration", value), + keyValue("enumeration declaration view", view)}; + + Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)}; + + if (enumeratorDeclarations == view.enumeratorDeclarations) + return Sqlite::UpdateChange::No; + + s->updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"remove enumeration declaration"_t, + projectStorageCategory(), + keyValue("enumeration declaration view", view)}; + + s->deleteEnumerationDeclarationStatement.write(view.id); + }; + + Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove); +} + +void ProjectStorage::extractExportedTypes(TypeId typeId, + const Storage::Synchronization::Type &type, + Storage::Synchronization::ExportedTypes &exportedTypes) +{ + for (const auto &exportedType : type.exportedTypes) + exportedTypes.emplace_back(exportedType.name, exportedType.version, typeId, exportedType.moduleId); +} + +TypeId ProjectStorage::declareType(Storage::Synchronization::Type &type) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"declare type"_t, + projectStorageCategory(), + keyValue("source id", type.sourceId), + keyValue("type name", type.typeName)}; + + if (type.typeName.isEmpty()) { + type.typeId = s->selectTypeIdBySourceIdStatement.value<TypeId>(type.sourceId); + + tracer.end(keyValue("type id", type.typeId)); + + return type.typeId; + } + + type.typeId = s->insertTypeStatement.value<TypeId>(type.sourceId, type.typeName); + + if (!type.typeId) + type.typeId = s->selectTypeIdBySourceIdAndNameStatement.value<TypeId>(type.sourceId, + type.typeName); + + tracer.end(keyValue("type id", type.typeId)); + + return type.typeId; +} + +void ProjectStorage::syncDeclarations(Storage::Synchronization::Type &type, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarationIds &propertyDeclarationIds) +{ + NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()}; + + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + synchronizePropertyDeclarations(type.typeId, + type.propertyDeclarations, + type.sourceId, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); + synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); + synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); +} + +void ProjectStorage::syncDeclarations(Storage::Synchronization::Types &types, + AliasPropertyDeclarations &insertedAliasPropertyDeclarations, + AliasPropertyDeclarations &updatedAliasPropertyDeclarations, + PropertyDeclarations &relinkablePropertyDeclarations) +{ + NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()}; + + PropertyDeclarationIds propertyDeclarationIds; + propertyDeclarationIds.reserve(types.size() * 10); + + for (auto &&type : types) + syncDeclarations(type, + insertedAliasPropertyDeclarations, + updatedAliasPropertyDeclarations, + propertyDeclarationIds); + + removeRelinkableEntries(relinkablePropertyDeclarations, + propertyDeclarationIds, + PropertyCompare<PropertyDeclaration>{}); +} + +void ProjectStorage::syncDefaultProperties(Storage::Synchronization::Types &types) +{ + NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()}; + + auto range = s->selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>(); + + auto compareKey = [](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + return view.typeId - value.typeId; + }; + + auto insert = [&](const Storage::Synchronization::Type &) { + + }; + + auto update = [&](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize default properties by update"_t, + projectStorageCategory(), + keyValue("type id", value.typeId), + keyValue("value", value), + keyValue("view", view)}; + + PropertyDeclarationId valueDefaultPropertyId; + if (value.defaultPropertyName.size()) + valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded(value.typeId, + value.defaultPropertyName) + .propertyDeclarationId; + + if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) + return Sqlite::UpdateChange::No; + + s->updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId); + + tracer.end(keyValue("updated", "yes"), + keyValue("default property id", valueDefaultPropertyId)); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const TypeWithDefaultPropertyView &) {}; + + Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); +} + +void ProjectStorage::resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types) +{ + NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()}; + + auto range = s->selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>(); + + auto compareKey = [](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + return view.typeId - value.typeId; + }; + + auto insert = [&](const Storage::Synchronization::Type &) { + + }; + + auto update = [&](const TypeWithDefaultPropertyView &view, + const Storage::Synchronization::Type &value) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"reset changed default properties by update"_t, + projectStorageCategory(), + keyValue("type id", value.typeId), + keyValue("value", value), + keyValue("view", view)}; + + PropertyDeclarationId valueDefaultPropertyId; + if (value.defaultPropertyName.size()) { + auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( + value.typeId, value.defaultPropertyName); + if (optionalValueDefaultPropertyId) + valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId; + } + + if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) + return Sqlite::UpdateChange::No; + + s->updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{}); + + tracer.end(keyValue("updated", "yes")); + + return Sqlite::UpdateChange::Update; + }; + + auto remove = [&](const TypeWithDefaultPropertyView &) {}; + + Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); +} + +void ProjectStorage::checkForPrototypeChainCycle(TypeId typeId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check for prototype chain cycle"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto callback = [=](TypeId currentTypeId) { + if (typeId == currentTypeId) + throw PrototypeChainCycle{}; + }; + + s->selectPrototypeAndExtensionIdsStatement.readCallback(callback, typeId); +} + +void ProjectStorage::checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"check for alias chain cycle"_t, + projectStorageCategory(), + keyValue("property declaration id", propertyDeclarationId)}; + auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) { + if (propertyDeclarationId == currentPropertyDeclarationId) + throw AliasChainCycle{}; + }; + + s->selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback, + propertyDeclarationId); +} + +std::pair<TypeId, ImportedTypeNameId> ProjectStorage::fetchImportedTypeNameIdAndTypeId( + const Storage::Synchronization::ImportedTypeName &importedTypeName, SourceId sourceId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id and type id"_t, + projectStorageCategory(), + keyValue("imported type name", importedTypeName), + keyValue("source id", sourceId)}; + + TypeId typeId; + ImportedTypeNameId typeNameId; + auto typeName = std::visit([](auto &&importedTypeName) { return importedTypeName.name; }, + importedTypeName); + if (!typeName.empty()) { + typeNameId = fetchImportedTypeNameId(importedTypeName, sourceId); + + typeId = fetchTypeId(typeNameId); + + tracer.end(keyValue("type id", typeId), keyValue("type name id", typeNameId)); + + if (!typeId) { + errorNotifier->typeNameCannotBeResolved(typeName, sourceId); + return {unresolvedTypeId, typeNameId}; + } + } + + return {typeId, typeNameId}; +} + +void ProjectStorage::syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds) +{ + if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) + return; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"synchronize prototype and extension"_t, + projectStorageCategory(), + keyValue("prototype", type.prototype), + keyValue("extension", type.extension), + keyValue("type id", type.typeId), + keyValue("source id", type.sourceId)}; + + auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype, + type.sourceId); + auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension, + type.sourceId); + + s->updatePrototypeAndExtensionStatement.write(type.typeId, + prototypeId, + prototypeTypeNameId, + extensionId, + extensionTypeNameId); + + if (prototypeId || extensionId) + checkForPrototypeChainCycle(type.typeId); + + typeIds.push_back(type.typeId); + + tracer.end(keyValue("prototype id", prototypeId), + keyValue("prototype type name id", prototypeTypeNameId), + keyValue("extension id", extensionId), + keyValue("extension type name id", extensionTypeNameId)); +} + +void ProjectStorage::syncPrototypesAndExtensions(Storage::Synchronization::Types &types, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) +{ + NanotraceHR::Tracer tracer{"synchronize prototypes and extensions"_t, projectStorageCategory()}; + + TypeIds typeIds; + typeIds.reserve(types.size()); + + for (auto &type : types) + syncPrototypeAndExtension(type, typeIds); + + removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{}); + removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{}); +} + +ImportId ProjectStorage::fetchImportId(SourceId sourceId, const Storage::Import &import) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("import", import), + keyValue("source id", sourceId)}; + + ImportId importId; + if (import.version) { + importId = s->selectImportIdBySourceIdAndModuleIdAndVersionStatement.value<ImportId>( + sourceId, import.moduleId, import.version.major.value, import.version.minor.value); + } else if (import.version.major) { + importId = s->selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement + .value<ImportId>(sourceId, import.moduleId, import.version.major.value); + } else { + importId = s->selectImportIdBySourceIdAndModuleIdStatement.value<ImportId>(sourceId, + import.moduleId); + } + + tracer.end(keyValue("import id", importId)); + + return importId; +} + +ImportedTypeNameId ProjectStorage::fetchImportedTypeNameId( + const Storage::Synchronization::ImportedTypeName &name, SourceId sourceId) +{ + struct Inspect + { + auto operator()(const Storage::Synchronization::ImportedType &importedType) + { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("imported type name", importedType.name), + keyValue("source id", sourceId), + keyValue("type name kind", "exported"sv)}; + + return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, + sourceId, + importedType.name); + } + + auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType) + { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("imported type name", importedType.name), + keyValue("import", importedType.import), + keyValue("type name kind", "qualified exported"sv)}; + + ImportId importId = storage.fetchImportId(sourceId, importedType.import); + + auto importedTypeNameId = storage.fetchImportedTypeNameId( + Storage::Synchronization::TypeNameKind::QualifiedExported, importId, importedType.name); + + tracer.end(keyValue("import id", importId), keyValue("source id", sourceId)); + + return importedTypeNameId; + } + + ProjectStorage &storage; + SourceId sourceId; + }; + + return std::visit(Inspect{*this, sourceId}, name); +} + +TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id with type name kind"_t, + projectStorageCategory(), + keyValue("type name id", typeNameId)}; + + auto kind = s->selectKindFromImportedTypeNamesStatement.value<Storage::Synchronization::TypeNameKind>( + typeNameId); + + auto typeId = fetchTypeId(typeNameId, kind); + + tracer.end(keyValue("type id", typeId), keyValue("type name kind", kind)); + + return typeId; +} + +Utils::SmallString ProjectStorage::fetchImportedTypeName(ImportedTypeNameId typeNameId) const +{ + return s->selectNameFromImportedTypeNamesStatement.value<Utils::SmallString>(typeNameId); +} + +SourceId ProjectStorage::fetchTypeSourceId(TypeId typeId) const +{ + return s->selectSourceIdByTypeIdStatement.value<SourceId>(typeId); +} + +TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId, + Storage::Synchronization::TypeNameKind kind) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch type id"_t, + projectStorageCategory(), + keyValue("type name id", typeNameId), + keyValue("type name kind", kind)}; + + TypeId typeId; + if (kind == Storage::Synchronization::TypeNameKind::Exported) { + typeId = s->selectTypeIdForImportedTypeNameNamesStatement.value<UnresolvedTypeId>(typeNameId); + } else { + typeId = s->selectTypeIdForQualifiedImportedTypeNameNamesStatement.value<UnresolvedTypeId>( + typeNameId); + } + + tracer.end(keyValue("type id", typeId)); + + return typeId; +} + +std::optional<ProjectStorage::FetchPropertyDeclarationResult> +ProjectStorage::fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, + Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch optional property declaration by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); + auto propertyDeclaration = s->selectPropertyDeclarationResultByPropertyDeclarationIdStatement + .optionalValue<FetchPropertyDeclarationResult>( + propertyDeclarationId); + + tracer.end(keyValue("property declaration", propertyDeclaration)); + + return propertyDeclaration; +} + +ProjectStorage::FetchPropertyDeclarationResult ProjectStorage::fetchPropertyDeclarationByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declaration by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, name); + tracer.end(keyValue("property declaration", propertyDeclaration)); + + if (propertyDeclaration) + return *propertyDeclaration; + + throw PropertyNameDoesNotExists{}; +} + +PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationIdByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declaration id by type id and name ungarded"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("property name", name)}; + + auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name); + + tracer.end(keyValue("property declaration id", propertyDeclarationId)); + + if (propertyDeclarationId) + return propertyDeclarationId; + + throw PropertyNameDoesNotExists{}; +} + +SourceContextId ProjectStorage::readSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"read source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + auto sourceContextId = s->selectSourceContextIdFromSourceContextsBySourceContextPathStatement + .value<SourceContextId>(sourceContextPath); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +SourceContextId ProjectStorage::writeSourceContextId(Utils::SmallStringView sourceContextPath) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"write source context id"_t, + projectStorageCategory(), + keyValue("source context path", sourceContextPath)}; + + s->insertIntoSourceContextsStatement.write(sourceContextPath); + + auto sourceContextId = SourceContextId::create(static_cast<int>(database.lastInsertedRowId())); + + tracer.end(keyValue("source context id", sourceContextId)); + + return sourceContextId; +} + +SourceId ProjectStorage::writeSourceId(SourceContextId sourceContextId, + Utils::SmallStringView sourceName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"write source id"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId), + keyValue("source name", sourceName)}; + + s->insertIntoSourcesStatement.write(sourceContextId, sourceName); + + auto sourceId = SourceId::create(static_cast<int>(database.lastInsertedRowId())); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +SourceId ProjectStorage::readSourceId(SourceContextId sourceContextId, + Utils::SmallStringView sourceName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"read source id"_t, + projectStorageCategory(), + keyValue("source context id", sourceContextId), + keyValue("source name", sourceName)}; + + auto sourceId = s->selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement + .value<SourceId>(sourceContextId, sourceName); + + tracer.end(keyValue("source id", sourceId)); + + return sourceId; +} + +Storage::Synchronization::ExportedTypes ProjectStorage::fetchExportedTypes(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch exported type"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto exportedTypes = s->selectExportedTypesByTypeIdStatement + .values<Storage::Synchronization::ExportedType, 12>(typeId); + + tracer.end(keyValue("exported types", exportedTypes)); + + return exportedTypes; +} + +Storage::Synchronization::PropertyDeclarations ProjectStorage::fetchPropertyDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch property declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + auto propertyDeclarations = s->selectPropertyDeclarationsByTypeIdStatement + .values<Storage::Synchronization::PropertyDeclaration, 24>(typeId); + + tracer.end(keyValue("property declarations", propertyDeclarations)); + + return propertyDeclarations; +} + +Storage::Synchronization::FunctionDeclarations ProjectStorage::fetchFunctionDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch signal declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::FunctionDeclarations functionDeclarations; + + auto callback = [&](Utils::SmallStringView name, + Utils::SmallStringView returnType, + FunctionDeclarationId functionDeclarationId) { + auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType); + functionDeclaration.parameters = s->selectFunctionParameterDeclarationsStatement + .values<Storage::Synchronization::ParameterDeclaration, 8>( + functionDeclarationId); + }; + + s->selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); + + tracer.end(keyValue("function declarations", functionDeclarations)); + + return functionDeclarations; +} + +Storage::Synchronization::SignalDeclarations ProjectStorage::fetchSignalDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch signal declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::SignalDeclarations signalDeclarations; + + auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) { + auto &signalDeclaration = signalDeclarations.emplace_back(name); + signalDeclaration.parameters = s->selectSignalParameterDeclarationsStatement + .values<Storage::Synchronization::ParameterDeclaration, 8>( + signalDeclarationId); + }; + + s->selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); + + tracer.end(keyValue("signal declarations", signalDeclarations)); + + return signalDeclarations; +} + +Storage::Synchronization::EnumerationDeclarations ProjectStorage::fetchEnumerationDeclarations(TypeId typeId) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch enumeration declarations"_t, + projectStorageCategory(), + keyValue("type id", typeId)}; + + Storage::Synchronization::EnumerationDeclarations enumerationDeclarations; + + auto callback = [&](Utils::SmallStringView name, + EnumerationDeclarationId enumerationDeclarationId) { + enumerationDeclarations.emplace_back( + name, + s->selectEnumeratorDeclarationStatement + .values<Storage::Synchronization::EnumeratorDeclaration, 8>(enumerationDeclarationId)); + }; + + s->selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement + .readCallback(callback, typeId); + + tracer.end(keyValue("enumeration declarations", enumerationDeclarations)); + + return enumerationDeclarations; +} + +template<typename... TypeIds> +bool ProjectStorage::isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + projectStorageCategory(), + keyValue("type id", typeId), + keyValue("base type ids", NanotraceHR::array(baseTypeIds...))}; + + static_assert(((std::is_same_v<TypeId, TypeIds>) &&...), "Parameter must be a TypeId!"); + + if (((typeId == baseTypeIds) || ...)) { + tracer.end(keyValue("is based on", true)); + return true; + } + + auto range = s->selectPrototypeAndExtensionIdsStatement.rangeWithTransaction<TypeId>(typeId); + + auto isBasedOn = std::any_of(range.begin(), range.end(), [&](TypeId currentTypeId) { + return ((currentTypeId == baseTypeIds) || ...); + }); + + tracer.end(keyValue("is based on", isBasedOn)); + + return isBasedOn; +} + +template<typename Id> +ImportedTypeNameId ProjectStorage::fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind kind, + Id id, + Utils::SmallStringView typeName) +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"fetch imported type name id"_t, + projectStorageCategory(), + keyValue("imported type name", typeName), + keyValue("kind", kind)}; + + auto importedTypeNameId = s->selectImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind, + id, + typeName); + + if (!importedTypeNameId) + importedTypeNameId = s->insertImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind, + id, + typeName); + + tracer.end(keyValue("imported type name id", importedTypeNameId)); + + return importedTypeNameId; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index a770577a65..54d9101596 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -4,11 +4,15 @@ #pragma once #include "commontypecache.h" +#include "projectstorageerrornotifier.h" #include "projectstorageexceptions.h" #include "projectstorageinterface.h" +#include "projectstoragetypes.h" #include "sourcepathcachetypes.h" #include "storagecache.h" +#include <tracing/qmldesignertracing.h> + #include <sqlitealgorithms.h> #include <sqlitedatabase.h> #include <sqlitetable.h> @@ -28,516 +32,167 @@ namespace QmlDesigner { using namespace NanotraceHR::Literals; -constexpr NanotraceHR::Tracing projectStorageTracingStatus() -{ -#ifdef ENABLE_PROJECT_STORAGE_TRACING - return NanotraceHR::Tracing::IsEnabled; -#else - return NanotraceHR::Tracing::IsDisabled; -#endif -} - -[[gnu::pure]] NanotraceHR::StringViewCategory<projectStorageTracingStatus()> &projectStorageCategory(); +using ProjectStorageTracing::projectStorageCategory; -template<typename Database> class ProjectStorage final : public ProjectStorageInterface { - friend Storage::Info::CommonTypeCache<Database>; - -public: - template<int ResultCount, int BindParameterCount = 0> - using ReadStatement = typename Database::template ReadStatement<ResultCount, BindParameterCount>; - template<int ResultCount, int BindParameterCount = 0> - using ReadWriteStatement = typename Database::template ReadWriteStatement<ResultCount, BindParameterCount>; - template<int BindParameterCount> - using WriteStatement = typename Database::template WriteStatement<BindParameterCount>; - - ProjectStorage(Database &database, bool isInitialized) - : database{database} - , exclusiveTransaction{database} - , initializer{database, isInitialized} - { - NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()}; + using Database = Sqlite::Database; + friend Storage::Info::CommonTypeCache<ProjectStorageType>; - exclusiveTransaction.commit(); + enum class Relink { No, Yes }; - database.walCheckpointFull(); - - moduleCache.populate(); - } - - void synchronize(Storage::Synchronization::SynchronizationPackage package) override - { - NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()}; - - TypeIds deletedTypeIds; - Sqlite::withImmediateTransaction(database, [&] { - AliasPropertyDeclarations insertedAliasPropertyDeclarations; - AliasPropertyDeclarations updatedAliasPropertyDeclarations; - - AliasPropertyDeclarations relinkableAliasPropertyDeclarations; - PropertyDeclarations relinkablePropertyDeclarations; - Prototypes relinkablePrototypes; - Prototypes relinkableExtensions; - - TypeIds updatedTypeIds; - updatedTypeIds.reserve(package.types.size()); - - TypeIds typeIdsToBeDeleted; - - std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end()); - - synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds); - synchronizeImports(package.imports, - package.updatedSourceIds, - package.moduleDependencies, - package.updatedModuleDependencySourceIds, - package.moduleExportedImports, - package.updatedModuleIds); - synchronizeTypes(package.types, - updatedTypeIds, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - package.updatedSourceIds); - synchronizeTypeAnnotations(package.typeAnnotations, - package.updatedTypeAnnotationSourceIds); - synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, - package.updatedPropertyEditorQmlPathSourceIds); - - deleteNotUpdatedTypes(updatedTypeIds, - package.updatedSourceIds, - typeIdsToBeDeleted, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - deletedTypeIds); - - relink(relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions, - deletedTypeIds); - - linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); - - synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds); - - commonTypeCache_.resetTypeIds(); - }); - - callRefreshMetaInfoCallback(deletedTypeIds); - } +public: + ProjectStorage(Database &database, + ProjectStorageErrorNotifierInterface &errorNotifier, + bool isInitialized); + ~ProjectStorage(); - void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override - { - NanotraceHR::Tracer tracer{"synchronize document imports"_t, projectStorageCategory()}; + void synchronize(Storage::Synchronization::SynchronizationPackage package) override; - Sqlite::withImmediateTransaction(database, [&] { - synchronizeDocumentImports(imports, - {sourceId}, - Storage::Synchronization::ImportKind::Import); - }); - } + void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override; - void addObserver(ProjectStorageObserver *observer) override { observers.push_back(observer); } - - void removeObserver(ProjectStorageObserver *observer) override + void setErrorNotifier(ProjectStorageErrorNotifierInterface &errorNotifier) { - observers.removeOne(observer); + this->errorNotifier = &errorNotifier; } - ModuleId moduleId(Utils::SmallStringView moduleName) const override - { - NanotraceHR::Tracer tracer{"get module id"_t, projectStorageCategory()}; - - return moduleCache.id(moduleName); - } + void addObserver(ProjectStorageObserver *observer) override; - Utils::SmallString moduleName(ModuleId moduleId) const - { - NanotraceHR::Tracer tracer{"get module name"_t, projectStorageCategory()}; + void removeObserver(ProjectStorageObserver *observer) override; - if (!moduleId) - throw ModuleDoesNotExists{}; + ModuleId moduleId(Utils::SmallStringView moduleName, Storage::ModuleKind kind) const override; - return moduleCache.value(moduleId); - } + Storage::Module module(ModuleId moduleId) const override; TypeId typeId(ModuleId moduleId, Utils::SmallStringView exportedTypeName, - Storage::Version version) const override - { - NanotraceHR::Tracer tracer{"get type id by exported name"_t, projectStorageCategory()}; + Storage::Version version) const override; - if (version.minor) - return selectTypeIdByModuleIdAndExportedNameAndVersionStatement - .template valueWithTransaction<TypeId>(moduleId, - exportedTypeName, - version.major.value, - version.minor.value); + TypeId typeId(ImportedTypeNameId typeNameId) const override; - if (version.major) - return selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement - .template valueWithTransaction<TypeId>(moduleId, exportedTypeName, version.major.value); + QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override; - return selectTypeIdByModuleIdAndExportedNameStatement - .template valueWithTransaction<TypeId>(moduleId, exportedTypeName); - } - - TypeId typeId(ImportedTypeNameId typeNameId) const override - { - NanotraceHR::Tracer tracer{"get type id by imported type name"_t, projectStorageCategory()}; - - return Sqlite::withDeferredTransaction(database, [&] { return fetchTypeId(typeNameId); }); - } - - QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override - { - NanotraceHR::Tracer tracer{"get type ids by module id"_t, projectStorageCategory()}; - - return selectTypeIdsByModuleIdStatement - .template valuesWithTransaction<QVarLengthArray<TypeId, 256>>(moduleId); - } - - Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get exported type names by type id"_t, projectStorageCategory()}; + Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override; - return selectExportedTypesByTypeIdStatement - .template valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId); - } + Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, SourceId sourceId) const override; - Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, - SourceId sourceId) const override - { - NanotraceHR::Tracer tracer{"get exported type names by source id"_t, projectStorageCategory()}; - - return selectExportedTypesByTypeIdAndSourceIdStatement - .template valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId, sourceId); - } + ImportId importId(const Storage::Import &import) const override; - ImportId importId(const Storage::Import &import) const override - { - NanotraceHR::Tracer tracer{"get import id by import"_t, projectStorageCategory()}; + ImportedTypeNameId importedTypeNameId(ImportId importId, Utils::SmallStringView typeName) override; - return Sqlite::withDeferredTransaction(database, [&] { - return fetchImportId(import.sourceId, import); - }); - } + ImportedTypeNameId importedTypeNameId(SourceId sourceId, Utils::SmallStringView typeName) override; - ImportedTypeNameId importedTypeNameId(ImportId importId, - Utils::SmallStringView typeName) override - { - NanotraceHR::Tracer tracer{"get imported type name id by import id"_t, - projectStorageCategory()}; + QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override; - return Sqlite::withDeferredTransaction(database, [&] { - return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported, - importId, - typeName); - }); - } - - ImportedTypeNameId importedTypeNameId(SourceId sourceId, - Utils::SmallStringView typeName) override - { - NanotraceHR::Tracer tracer{"get imported type name id by source id"_t, - projectStorageCategory()}; - - return Sqlite::withDeferredTransaction(database, [&] { - return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, - sourceId, - typeName); - }); - } - - QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get property declaration ids"_t, projectStorageCategory()}; - - return selectPropertyDeclarationIdsForTypeStatement - .template valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>(typeId); - } - - QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get local property declaration ids"_t, projectStorageCategory()}; - - return selectLocalPropertyDeclarationIdsForTypeStatement - .template valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>(typeId); - } + QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override; PropertyDeclarationId propertyDeclarationId(TypeId typeId, - Utils::SmallStringView propertyName) const override - { - NanotraceHR::Tracer tracer{"get property declaration id"_t, projectStorageCategory()}; - - return selectPropertyDeclarationIdForTypeAndPropertyNameStatement - .template valueWithTransaction<PropertyDeclarationId>(typeId, propertyName); - } + Utils::SmallStringView propertyName) const override; PropertyDeclarationId localPropertyDeclarationId(TypeId typeId, - Utils::SmallStringView propertyName) const - { - NanotraceHR::Tracer tracer{"get local property declaration id"_t, projectStorageCategory()}; + Utils::SmallStringView propertyName) const; - return selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement - .template valueWithTransaction<PropertyDeclarationId>(typeId, propertyName); - } + PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const override; std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration( - PropertyDeclarationId propertyDeclarationId) const override - { - NanotraceHR::Tracer tracer{"get property declaration"_t, projectStorageCategory()}; - - return selectPropertyDeclarationForPropertyDeclarationIdStatement - .template optionalValueWithTransaction<Storage::Info::PropertyDeclaration>( - propertyDeclarationId); - } - - std::optional<Storage::Info::Type> type(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory()}; - - return selectInfoTypeByTypeIdStatement.template optionalValueWithTransaction<Storage::Info::Type>( - typeId); - } + PropertyDeclarationId propertyDeclarationId) const override; - Utils::PathString typeIconPath(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get type icon path"_t, projectStorageCategory()}; - - return selectTypeIconPathStatement.template valueWithTransaction<Utils::PathString>(typeId); - } - - Storage::Info::TypeHints typeHints(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get type hints"_t, projectStorageCategory()}; + std::optional<Storage::Info::Type> type(TypeId typeId) const override; - return selectTypeHintsStatement.template valuesWithTransaction<Storage::Info::TypeHints, 4>( - typeId); - } + Utils::PathString typeIconPath(TypeId typeId) const override; - Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get item library entries by type id"_t, projectStorageCategory()}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId_, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId_, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId); - - return entries; - } + Storage::Info::TypeHints typeHints(TypeId typeId) const override; - Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override - { - NanotraceHR::Tracer tracer{"get item library entries by source id"_t, - projectStorageCategory()}; + SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const override; - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId); - - return entries; - } + SmallSourceIds<64> typeAnnotationDirectorySourceIds() const override; - Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override - { - NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()}; - - using Storage::Info::ItemLibraryProperties; - Storage::Info::ItemLibraryEntries entries; - - auto callback = [&](TypeId typeId, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { - auto &last = entries.emplace_back( - typeId, name, iconPath, category, import, toolTip, templatePath); - if (properties.size()) - selectItemLibraryPropertiesStatement.readTo(last.properties, properties); - if (extraFilePaths.size()) - selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); - }; - - selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback); - - return entries; - } + Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override; - std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get signal names"_t, projectStorageCategory()}; + Storage::Info::ItemLibraryEntries itemLibraryEntries(ImportId importId) const; - return selectSignalDeclarationNamesForTypeStatement - .template valuesWithTransaction<Utils::SmallString, 32>(typeId); - } + Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override; - std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get function names"_t, projectStorageCategory()}; + Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override; - return selectFuncionDeclarationNamesForTypeStatement - .template valuesWithTransaction<Utils::SmallString, 32>(typeId); - } + std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override; - std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override - { - NanotraceHR::Tracer tracer{"get property name"_t, projectStorageCategory()}; + std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override; - return selectPropertyNameStatement.template optionalValueWithTransaction<Utils::SmallString>( - propertyDeclarationId); - } + std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override; - const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const override + const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const override { return commonTypeCache_; } - template<const char *moduleName, const char *typeName> + template<const char *moduleName, const char *typeName, Storage::ModuleKind moduleKind = Storage::ModuleKind::QmlLibrary> TypeId commonTypeId() const { - NanotraceHR::Tracer tracer{"get type id from common type cache"_t, projectStorageCategory()}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get type id from common type cache"_t, + projectStorageCategory(), + keyValue("module name", std::string_view{moduleName}), + keyValue("type name", std::string_view{typeName})}; + + auto typeId = commonTypeCache_.typeId<moduleName, typeName, moduleKind>(); + + tracer.end(keyValue("type id", typeId)); - return commonTypeCache_.template typeId<moduleName, typeName>(); + return typeId; } template<typename BuiltinType> TypeId builtinTypeId() const { + using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t, projectStorageCategory()}; - return commonTypeCache_.template builtinTypeId<BuiltinType>(); + auto typeId = commonTypeCache_.builtinTypeId<BuiltinType>(); + + tracer.end(keyValue("type id", typeId)); + + return typeId; } template<const char *builtinType> TypeId builtinTypeId() const { + using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t, projectStorageCategory()}; - return commonTypeCache_.template builtinTypeId<builtinType>(); - } + auto typeId = commonTypeCache_.builtinTypeId<builtinType>(); - TypeIds prototypeIds(TypeId type) const override - { - NanotraceHR::Tracer tracer{"get prototypes"_t, projectStorageCategory()}; + tracer.end(keyValue("type id", typeId)); - return selectPrototypeIdsForTypeIdInOrderStatement.template valuesWithTransaction<TypeId, 16>( - type); + return typeId; } - TypeIds prototypeAndSelfIds(TypeId type) const override - { - NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()}; + SmallTypeIds<16> prototypeIds(TypeId type) const override; - return selectPrototypeAndSelfIdsForTypeIdInOrderStatement - .template valuesWithTransaction<TypeId, 16>(type); - } + SmallTypeIds<16> prototypeAndSelfIds(TypeId typeId) const override; - TypeIds heirIds(TypeId typeId) const override - { - NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()}; - - return selectHeirTypeIdsStatement.template valuesWithTransaction<TypeId, 64>(typeId); - } + SmallTypeIds<64> heirIds(TypeId typeId) const override; template<typename... TypeIds> - bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const - { - NanotraceHR::Tracer tracer{"is based on"_t, projectStorageCategory()}; + bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const; - static_assert(((std::is_same_v<TypeId, TypeIds>) &&...), "Parameter must be a TypeId!"); + bool isBasedOn(TypeId) const; - if (((typeId == baseTypeIds) || ...)) - return true; + bool isBasedOn(TypeId typeId, TypeId id1) const override; - auto range = selectPrototypeIdsStatement.template rangeWithTransaction<TypeId>(typeId); + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override; - for ([[maybe_unused]] TypeId currentTypeId : range) { - if (((currentTypeId == baseTypeIds) || ...)) - return true; - } - - return false; - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override; - bool isBasedOn(TypeId typeId) const { return isBasedOn_(typeId); } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override; - bool isBasedOn(TypeId typeId, TypeId id1) const override { return isBasedOn_(typeId, id1); } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override; - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override - { - return isBasedOn_(typeId, id1, id2); - } - - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override - { - return isBasedOn_(typeId, id1, id2, id3); - } - - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4); - } - - bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5); - } - - bool isBasedOn( - TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6); - } + bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) + const override; bool isBasedOn(TypeId typeId, TypeId id1, @@ -546,316 +201,147 @@ public: TypeId id4, TypeId id5, TypeId id6, - TypeId id7) const override - { - return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7); - } + TypeId id7) const override; - TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const - { - NanotraceHR::Tracer tracer{"is based on"_t, projectStorageCategory()}; + TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const; - return selectTypeIdByExportedNameStatement.template valueWithTransaction<TypeId>(name); - } + TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, + Utils::SmallStringView name) const; - TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, Utils::SmallStringView name) const - { - return selectTypeIdByModuleIdsAndExportedNameStatement.template valueWithTransaction<TypeId>( - static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name); - } + TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name); - TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name) - { - return selectTypeIdBySourceIdAndNameStatement.template valueWithTransaction<TypeId>(sourceId, - name); - } + Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId); - Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId) - { - return Sqlite::withDeferredTransaction(database, [&] { - auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>( - typeId); - - type.exportedTypes = fetchExportedTypes(typeId); - type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); - type.functionDeclarations = fetchFunctionDeclarations(type.typeId); - type.signalDeclarations = fetchSignalDeclarations(type.typeId); - type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); - - return type; - }); - } - - Storage::Synchronization::Types fetchTypes() - { - return Sqlite::withDeferredTransaction(database, [&] { - auto types = selectTypesStatement.template values<Storage::Synchronization::Type, 64>(); - - for (Storage::Synchronization::Type &type : types) { - type.exportedTypes = fetchExportedTypes(type.typeId); - type.propertyDeclarations = fetchPropertyDeclarations(type.typeId); - type.functionDeclarations = fetchFunctionDeclarations(type.typeId); - type.signalDeclarations = fetchSignalDeclarations(type.typeId); - type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId); - } - - return types; - }); - } - - bool fetchIsProtype(TypeId type, TypeId prototype) - { - return bool(selectPrototypeIdStatement.template valueWithTransaction<TypeId>(type, prototype)); - } - - auto fetchPrototypes(TypeId type) - { - return selectPrototypeIdsInOrderStatement.template rangeWithTransaction<TypeId>(type); - } - - SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath) - { - NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()}; - - auto sourceContextId = readSourceContextId(sourceContextPath); - - return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath); - } - - SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath) - { - NanotraceHR::Tracer tracer{"fetch source context id"_t, projectStorageCategory()}; - - try { - return Sqlite::withDeferredTransaction(database, [&] { - return fetchSourceContextIdUnguarded(sourceContextPath); - }); - } catch (const Sqlite::ConstraintPreventsModification &) { - return fetchSourceContextId(sourceContextPath); - } - } + Storage::Synchronization::Types fetchTypes(); - Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const - { - NanotraceHR::Tracer tracer{"fetch source context path"_t, projectStorageCategory()}; - - return Sqlite::withDeferredTransaction(database, [&] { - auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement - .template optionalValue<Utils::PathString>( - sourceContextId); - - if (!optionalSourceContextPath) - throw SourceContextIdDoesNotExists(); - - return std::move(*optionalSourceContextPath); - }); - } + SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath); - auto fetchAllSourceContexts() const - { - NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()}; + SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath); - return selectAllSourceContextsStatement - .template valuesWithTransaction<Cache::SourceContext, 128>(); - } + Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const; - SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - NanotraceHR::Tracer tracer{"fetch source id"_t, projectStorageCategory()}; - - return Sqlite::withDeferredTransaction(database, [&] { - return fetchSourceIdUnguarded(sourceContextId, sourceName); - }); - } + Cache::SourceContexts fetchAllSourceContexts() const; - auto fetchSourceNameAndSourceContextId(SourceId sourceId) const - { - NanotraceHR::Tracer tracer{"fetch source name and source context id"_t, - projectStorageCategory()}; + SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement - .template valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId); + Cache::SourceNameAndSourceContextId fetchSourceNameAndSourceContextId(SourceId sourceId) const; - if (!value.sourceContextId) - throw SourceIdDoesNotExists(); + void clearSources(); - return value; - } + SourceContextId fetchSourceContextId(SourceId sourceId) const; - void clearSources() - { - Sqlite::withImmediateTransaction(database, [&] { - deleteAllSourceContextsStatement.execute(); - deleteAllSourcesStatement.execute(); - }); - } + Cache::Sources fetchAllSources() const; - SourceContextId fetchSourceContextId(SourceId sourceId) const - { - NanotraceHR::Tracer tracer{"fetch source context id"_t, projectStorageCategory()}; + SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, + Utils::SmallStringView sourceName); - auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement - .template valueWithTransaction<SourceContextId>(sourceId); + FileStatuses fetchAllFileStatuses() const; - if (!sourceContextId) - throw SourceIdDoesNotExists(); + FileStatus fetchFileStatus(SourceId sourceId) const override; - return sourceContextId; - } + std::optional<Storage::Synchronization::DirectoryInfo> fetchDirectoryInfo(SourceId sourceId) const override; - auto fetchAllSources() const - { - NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()}; + Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceId directorySourceId) const override; + Storage::Synchronization::DirectoryInfos fetchDirectoryInfos( + SourceId directorySourceId, Storage::Synchronization::FileType fileType) const override; + Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(const SourceIds &directorySourceIds) const; + SmallSourceIds<32> fetchSubdirectorySourceIds(SourceId directorySourceId) const override; - return selectAllSourcesStatement.template valuesWithTransaction<Cache::Source, 1024>(); - } + void setPropertyEditorPathId(TypeId typeId, SourceId pathId); - SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - NanotraceHR::Tracer tracer{"fetch source id unguarded"_t, projectStorageCategory()}; + SourceId propertyEditorPathId(TypeId typeId) const override; - auto sourceId = readSourceId(sourceContextId, sourceName); + Storage::Imports fetchDocumentImports() const; - if (sourceId) - return sourceId; + void resetForTestsOnly(); - return writeSourceId(sourceContextId, sourceName); - } - - auto fetchAllFileStatuses() const - { - NanotraceHR::Tracer tracer{"fetch all file statuses"_t, projectStorageCategory()}; - - return selectAllFileStatusesStatement.template rangeWithTransaction<FileStatus>(); - } - - FileStatus fetchFileStatus(SourceId sourceId) const override - { - NanotraceHR::Tracer tracer{"fetch file status"_t, projectStorageCategory()}; - - return selectFileStatusesForSourceIdStatement.template valueWithTransaction<FileStatus>( - sourceId); - } - - std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const override - { - NanotraceHR::Tracer tracer{"fetch project data"_t, projectStorageCategory()}; - - return selectProjectDataForSourceIdStatement - .template optionalValueWithTransaction<Storage::Synchronization::ProjectData>(sourceId); - } - - Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override - { - NanotraceHR::Tracer tracer{"fetch project datas by source id"_t, projectStorageCategory()}; - - return selectProjectDatasForSourceIdStatement - .template valuesWithTransaction<Storage::Synchronization::ProjectData, 1024>( - projectSourceId); - } - - Storage::Synchronization::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const - { - NanotraceHR::Tracer tracer{"fetch project datas by source ids"_t, projectStorageCategory()}; - - return selectProjectDatasForSourceIdsStatement - .template valuesWithTransaction<Storage::Synchronization::ProjectData, 64>( - toIntegers(projectSourceIds)); - } - - void setPropertyEditorPathId(TypeId typeId, SourceId pathId) +private: + struct ModuleView { - Sqlite::ImmediateSessionTransaction transaction{database}; + ModuleView() = default; - upsertPropertyEditorPathIdStatement.write(typeId, pathId); + ModuleView(Utils::SmallStringView name, Storage::ModuleKind kind) + : name{name} + , kind{kind} + {} - transaction.commit(); - } + ModuleView(const Storage::Module &module) + : name{module.name} + , kind{module.kind} + {} - SourceId propertyEditorPathId(TypeId typeId) const override - { - return selectPropertyEditorPathIdStatement.template valueWithTransaction<SourceId>(typeId); - } + Utils::SmallStringView name; + Storage::ModuleKind kind; - Storage::Imports fetchDocumentImports() const - { - NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()}; + friend bool operator<(ModuleView first, ModuleView second) + { + return std::tie(first.kind, first.name) < std::tie(second.kind, second.name); + } - return selectAllDocumentImportForSourceIdStatement - .template valuesWithTransaction<Storage::Imports>(); - } + friend bool operator==(const Storage::Module &first, ModuleView second) + { + return first.name == second.name && first.kind == second.kind; + } - void resetForTestsOnly() - { - database.clearAllTablesForTestsOnly(); - commonTypeCache_.clearForTestsOnly(); - moduleCache.clearForTestOnly(); - } + friend bool operator==(ModuleView first, const Storage::Module &second) + { + return second == first; + } + }; -private: class ModuleStorageAdapter { public: - auto fetchId(const Utils::SmallStringView name) { return storage.fetchModuleId(name); } + auto fetchId(ModuleView module) { return storage.fetchModuleId(module.name, module.kind); } - auto fetchValue(ModuleId id) { return storage.fetchModuleName(id); } + auto fetchValue(ModuleId id) { return storage.fetchModule(id); } auto fetchAll() { return storage.fetchAllModules(); } ProjectStorage &storage; }; - class Module : public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId> + friend ModuleStorageAdapter; + + static bool moduleNameLess(ModuleView first, ModuleView second) noexcept + { + return first < second; + } + + class ModuleCacheEntry : public StorageCacheEntry<Storage::Module, ModuleView, ModuleId> { - using Base = StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId>; + using Base = StorageCacheEntry<Storage::Module, ModuleView, ModuleId>; public: using Base::Base; - friend bool operator==(const Module &first, const Module &second) + ModuleCacheEntry(Utils::SmallStringView name, Storage::ModuleKind kind, ModuleId moduleId) + : Base{{name, kind}, moduleId} + {} + + friend bool operator==(const ModuleCacheEntry &first, const ModuleCacheEntry &second) { return &first == &second && first.value == second.value; } - }; - friend ModuleStorageAdapter; + friend bool operator==(const ModuleCacheEntry &first, ModuleView second) + { + return first.value.name == second.name && first.value.kind == second.kind; + } + }; - static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept - { - return first < second; - } + using ModuleCacheEntries = std::vector<ModuleCacheEntry>; - using ModuleCache = StorageCache<Utils::PathString, - Utils::SmallStringView, - ModuleId, - ModuleStorageAdapter, - NonLockingMutex, - moduleNameLess, - Module>; + using ModuleCache + = StorageCache<Storage::Module, ModuleView, ModuleId, ModuleStorageAdapter, NonLockingMutex, moduleNameLess, ModuleCacheEntry>; - ModuleId fetchModuleId(Utils::SmallStringView moduleName) - { - return Sqlite::withDeferredTransaction(database, - [&] { return fetchModuleIdUnguarded(moduleName); }); - } + ModuleId fetchModuleId(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind); - auto fetchModuleName(ModuleId id) - { - return Sqlite::withDeferredTransaction(database, [&] { return fetchModuleNameUnguarded(id); }); - } + Storage::Module fetchModule(ModuleId id); - auto fetchAllModules() const - { - return selectAllModulesStatement.template valuesWithTransaction<Module, 128>(); - } + ModuleCacheEntries fetchAllModules() const; - void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds) - { - if (deletedTypeIds.size()) { - for (ProjectStorageObserver *observer : observers) - observer->removedTypeIds(deletedTypeIds); - } - } + void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds); class AliasPropertyDeclaration { @@ -882,6 +368,25 @@ private: < std::tie(second.typeId, second.propertyDeclarationId); } + template<typename String> + friend void convertToString(String &string, + const AliasPropertyDeclaration &aliasPropertyDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary( + keyValue("type id", aliasPropertyDeclaration.typeId), + keyValue("property declaration id", aliasPropertyDeclaration.propertyDeclarationId), + keyValue("alias imported type name id", + aliasPropertyDeclaration.aliasImportedTypeNameId), + keyValue("alias property name", aliasPropertyDeclaration.aliasPropertyName), + keyValue("alias property name tail", aliasPropertyDeclaration.aliasPropertyNameTail), + keyValue("alias property declaration id", + aliasPropertyDeclaration.aliasPropertyDeclarationId)); + + convertToString(string, dict); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; @@ -910,6 +415,20 @@ private: < std::tie(second.typeId, second.propertyDeclarationId); } + template<typename String> + friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", propertyDeclaration.typeId), + keyValue("property declaration id", + propertyDeclaration.propertyDeclarationId), + keyValue("imported type name id", + propertyDeclaration.importedTypeNameId)); + + convertToString(string, dict); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; @@ -931,6 +450,22 @@ private: return first.typeId < second.typeId; } + friend bool operator==(Prototype first, Prototype second) + { + return first.typeId == second.typeId; + } + + template<typename String> + friend void convertToString(String &string, const Prototype &prototype) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", prototype.typeId), + keyValue("prototype name id", prototype.prototypeNameId)); + + convertToString(string, dict); + } + public: TypeId typeId; ImportedTypeNameId prototypeNameId; @@ -970,127 +505,67 @@ private: } }; - SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, SourceIds &sourceIdsOfTypes) - { - std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end()); + SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, + SourceIds &sourceIdsOfTypes); - SourceIds sourceIdsWithoutTypeSourceIds; - sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size()); - std::set_difference(updatedSourceIds.begin(), - updatedSourceIds.end(), - sourceIdsOfTypes.begin(), - sourceIdsOfTypes.end(), - std::back_inserter(sourceIdsWithoutTypeSourceIds)); + TypeIds fetchTypeIds(const SourceIds &sourceIds); - return sourceIdsWithoutTypeSourceIds; - } - - TypeIds fetchTypeIds(const SourceIds &sourceIds) - { - return selectTypeIdsForSourceIdsStatement.template values<TypeId, 128>(toIntegers(sourceIds)); - } - - void unique(SourceIds &sourceIds) - { - std::sort(sourceIds.begin(), sourceIds.end()); - auto newEnd = std::unique(sourceIds.begin(), sourceIds.end()); - sourceIds.erase(newEnd, sourceIds.end()); - } + void unique(SourceIds &sourceIds); - void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits) - { - updateTypeAnnotationTraitStatement.write(typeId, traits.annotation); - } + void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits); class TypeAnnotationView { public: TypeAnnotationView(TypeId typeId, + Utils::SmallStringView typeName, Utils::SmallStringView iconPath, Utils::SmallStringView itemLibraryJson, Utils::SmallStringView hintsJson) : typeId{typeId} + , typeName{typeName} , iconPath{iconPath} , itemLibraryJson{itemLibraryJson} , hintsJson{hintsJson} {} + template<typename String> + friend void convertToString(String &string, const TypeAnnotationView &typeAnnotationView) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", typeAnnotationView.typeId), + keyValue("type name", typeAnnotationView.typeName), + keyValue("icon path", typeAnnotationView.iconPath), + keyValue("item library json", typeAnnotationView.itemLibraryJson), + keyValue("hints json", typeAnnotationView.hintsJson)); + + convertToString(string, dict); + } + public: TypeId typeId; + Utils::SmallStringView typeName; Utils::SmallStringView iconPath; Utils::SmallStringView itemLibraryJson; Utils::PathString hintsJson; }; - void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations) - { - for (auto &annotation : typeAnnotations) { - annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId, - annotation.typeName); - } - } + void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations); - void synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations, - const SourceIds &updatedTypeAnnotationSourceIds) + template<typename Value> + static Sqlite::ValueView createEmptyAsNull(const Value &value) { - NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()}; - - using Storage::Synchronization::TypeAnnotation; - - updateTypeIdInTypeAnnotations(typeAnnotations); - - auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; }; + if (value.size()) + return Sqlite::ValueView::create(value); - std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) { - return first.typeId < second.typeId; - }); - - auto range = selectTypeAnnotationsForSourceIdsStatement.template range<TypeAnnotationView>( - toIntegers(updatedTypeAnnotationSourceIds)); - - auto insert = [&](const TypeAnnotation &annotation) { - if (!annotation.sourceId) - throw TypeAnnotationHasInvalidSourceId{}; - - synchronizeTypeTraits(annotation.typeId, annotation.traits); - - insertTypeAnnotationStatement.write(annotation.typeId, - annotation.sourceId, - annotation.iconPath, - annotation.itemLibraryJson, - annotation.hintsJson); - }; - - auto update = [&](const TypeAnnotationView &annotationFromDatabase, - const TypeAnnotation &annotation) { - synchronizeTypeTraits(annotation.typeId, annotation.traits); - - if (annotationFromDatabase.iconPath != annotation.iconPath - || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson - || annotationFromDatabase.hintsJson != annotation.hintsJson) { - updateTypeAnnotationStatement.write(annotation.typeId, - annotation.iconPath, - annotation.itemLibraryJson, - annotation.hintsJson); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const TypeAnnotationView &annotationFromDatabase) { - synchronizeTypeTraits(annotationFromDatabase.typeId, Storage::TypeTraits{}); - - deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId); - }; - - Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove); + return Sqlite::ValueView{}; } - void synchronizeTypeTrait(const Storage::Synchronization::Type &type) - { - updateTypeTraitStatement.write(type.typeId, type.traits.type); - } + void synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations, + const SourceIds &updatedTypeAnnotationSourceIds); + + void synchronizeTypeTrait(const Storage::Synchronization::Type &type); void synchronizeTypes(Storage::Synchronization::Types &types, TypeIds &updatedTypeIds, @@ -1100,403 +575,62 @@ private: PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - const SourceIds &updatedSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()}; - - Storage::Synchronization::ExportedTypes exportedTypes; - exportedTypes.reserve(types.size() * 3); - SourceIds sourceIdsOfTypes; - sourceIdsOfTypes.reserve(updatedSourceIds.size()); - SourceIds notUpdatedExportedSourceIds; - notUpdatedExportedSourceIds.reserve(updatedSourceIds.size()); - SourceIds exportedSourceIds; - exportedSourceIds.reserve(types.size()); - - for (auto &type : types) { - if (!type.sourceId) - throw TypeHasInvalidSourceId{}; - - TypeId typeId = declareType(type); - synchronizeTypeTrait(type); - sourceIdsOfTypes.push_back(type.sourceId); - updatedTypeIds.push_back(typeId); - if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) { - exportedSourceIds.push_back(type.sourceId); - extractExportedTypes(typeId, type, exportedTypes); - } - } - - std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) { - return first.typeId < second.typeId; - }); - - unique(exportedSourceIds); - - SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, - sourceIdsOfTypes); - exportedSourceIds.insert(exportedSourceIds.end(), - sourceIdsWithoutType.begin(), - sourceIdsWithoutType.end()); - TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds); - synchronizeExportedTypes(exportedTypeIds, - exportedTypes, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions); - - syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); - resetDefaultPropertiesIfChanged(types); - resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); - syncDeclarations(types, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - relinkablePropertyDeclarations); - syncDefaultProperties(types); - } + const SourceIds &updatedSourceIds); - void synchronizeProjectDatas(Storage::Synchronization::ProjectDatas &projectDatas, - const SourceIds &updatedProjectSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize project datas"_t, projectStorageCategory()}; - - auto compareKey = [](auto &&first, auto &&second) { - auto projectSourceIdDifference = first.projectSourceId - second.projectSourceId; - if (projectSourceIdDifference != 0) - return projectSourceIdDifference; - - return first.sourceId - second.sourceId; - }; - - std::sort(projectDatas.begin(), projectDatas.end(), [&](auto &&first, auto &&second) { - return std::tie(first.projectSourceId, first.sourceId) - < std::tie(second.projectSourceId, second.sourceId); - }); - - auto range = selectProjectDatasForSourceIdsStatement - .template range<Storage::Synchronization::ProjectData>( - toIntegers(updatedProjectSourceIds)); - - auto insert = [&](const Storage::Synchronization::ProjectData &projectData) { - if (!projectData.projectSourceId) - throw ProjectDataHasInvalidProjectSourceId{}; - if (!projectData.sourceId) - throw ProjectDataHasInvalidSourceId{}; - - insertProjectDataStatement.write(projectData.projectSourceId, - projectData.sourceId, - projectData.moduleId, - projectData.fileType); - }; - - auto update = [&](const Storage::Synchronization::ProjectData &projectDataFromDatabase, - const Storage::Synchronization::ProjectData &projectData) { - if (projectDataFromDatabase.fileType != projectData.fileType - || !compareInvalidAreTrue(projectDataFromDatabase.moduleId, projectData.moduleId)) { - updateProjectDataStatement.write(projectData.projectSourceId, - projectData.sourceId, - projectData.moduleId, - projectData.fileType); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ProjectData &projectData) { - deleteProjectDataStatement.write(projectData.projectSourceId, projectData.sourceId); - }; - - Sqlite::insertUpdateDelete(range, projectDatas, compareKey, insert, update, remove); - } + void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, + const SourceIds &updatedDirectoryInfoSourceIds); - void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()}; - - auto compareKey = [](auto &&first, auto &&second) { - return first.sourceId - second.sourceId; - }; - - std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) { - return first.sourceId < second.sourceId; - }); - - auto range = selectFileStatusesForSourceIdsStatement.template range<FileStatus>( - toIntegers(updatedSourceIds)); - - auto insert = [&](const FileStatus &fileStatus) { - if (!fileStatus.sourceId) - throw FileStatusHasInvalidSourceId{}; - insertFileStatusStatement.write(fileStatus.sourceId, - fileStatus.size, - fileStatus.lastModified); - }; - - auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) { - if (fileStatusFromDatabase.lastModified != fileStatus.lastModified - || fileStatusFromDatabase.size != fileStatus.size) { - updateFileStatusStatement.write(fileStatus.sourceId, - fileStatus.size, - fileStatus.lastModified); - return Sqlite::UpdateChange::Update; - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const FileStatus &fileStatus) { - deleteFileStatusStatement.write(fileStatus.sourceId); - }; - - Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove); - } + void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds); void synchronizeImports(Storage::Imports &imports, const SourceIds &updatedSourceIds, Storage::Imports &moduleDependencies, const SourceIds &updatedModuleDependencySourceIds, Storage::Synchronization::ModuleExportedImports &moduleExportedImports, - const ModuleIds &updatedModuleIds) - { - NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()}; - - synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds); - synchronizeDocumentImports(imports, - updatedSourceIds, - Storage::Synchronization::ImportKind::Import); - synchronizeDocumentImports(moduleDependencies, - updatedModuleDependencySourceIds, - Storage::Synchronization::ImportKind::ModuleDependency); - } + const ModuleIds &updatedModuleIds, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions); void synchromizeModuleExportedImports( Storage::Synchronization::ModuleExportedImports &moduleExportedImports, - const ModuleIds &updatedModuleIds) - { - std::sort(moduleExportedImports.begin(), - moduleExportedImports.end(), - [](auto &&first, auto &&second) { - return std::tie(first.moduleId, first.exportedModuleId) - < std::tie(second.moduleId, second.exportedModuleId); - }); - - auto range = selectModuleExportedImportsForSourceIdStatement - .template range<Storage::Synchronization::ModuleExportedImportView>( - toIntegers(updatedModuleIds)); - - auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view, - const Storage::Synchronization::ModuleExportedImport &import) -> long long { - auto moduleIdDifference = view.moduleId - import.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - return view.exportedModuleId - import.exportedModuleId; - }; - - auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) { - if (import.version.minor) { - insertModuleExportedImportWithVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion, - import.version.major.value, - import.version.minor.value); - } else if (import.version.major) { - insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion, - import.version.major.value); - } else { - insertModuleExportedImportWithoutVersionStatement.write(import.moduleId, - import.exportedModuleId, - import.isAutoVersion); - } - }; - - auto update = [](const Storage::Synchronization::ModuleExportedImportView &, - const Storage::Synchronization::ModuleExportedImport &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) { - deleteModuleExportedImportStatement.write(view.moduleExportedImportId); - }; - - Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove); - } - - ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const override - { - auto moduleId = selectModuleIdByNameStatement.template value<ModuleId>(name); + const ModuleIds &updatedModuleIds); - if (moduleId) - return moduleId; + ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name, + Storage::ModuleKind moduleKind) const override; - return insertModuleNameStatement.template value<ModuleId>(name); - } - - auto fetchModuleNameUnguarded(ModuleId id) const - { - auto moduleName = selectModuleNameStatement.template value<Utils::PathString>(id); - - if (moduleName.empty()) - throw ModuleDoesNotExists{}; - - return moduleName; - } + Storage::Module fetchModuleUnguarded(ModuleId id) const; void handleAliasPropertyDeclarationsWithPropertyType( - TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) - { - auto callback = [&](TypeId typeId_, - PropertyDeclarationId propertyDeclarationId, - ImportedTypeNameId propertyImportedTypeNameId, - PropertyDeclarationId aliasPropertyDeclarationId, - PropertyDeclarationId aliasPropertyDeclarationTailId) { - auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>( - aliasPropertyDeclarationId); - Utils::SmallString aliasPropertyNameTail; - if (aliasPropertyDeclarationTailId) - aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>( - aliasPropertyDeclarationTailId); - - relinkableAliasPropertyDeclarations - .emplace_back(TypeId{typeId_}, - PropertyDeclarationId{propertyDeclarationId}, - ImportedTypeNameId{propertyImportedTypeNameId}, - std::move(aliasPropertyName), - std::move(aliasPropertyNameTail)); - - updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); - }; - - selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback, - typeId); - } + TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations); void handlePropertyDeclarationWithPropertyType(TypeId typeId, - PropertyDeclarations &relinkablePropertyDeclarations) - { - updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations, - typeId); - } + PropertyDeclarations &relinkablePropertyDeclarations); - void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes) - { - auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) { - relinkablePrototypes.emplace_back(typeId, prototypeNameId); - }; - - updatePrototypeIdToNullStatement.readCallback(callback, prototypeId); - } - - void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions) - { - auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { - relinkableExtensions.emplace_back(typeId, extensionNameId); - }; - - updateExtensionIdToNullStatement.readCallback(callback, extensionId); - } + void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes); + void handlePrototypesWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName, + TypeId typeId, + Prototypes &relinkablePrototypes); + void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions); + void handleExtensionsWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName, + TypeId typeId, + Prototypes &relinkableExtensions); void deleteType(TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations); - handlePrototypes(typeId, relinkablePrototypes); - handleExtensions(typeId, relinkableExtensions); - deleteTypeNamesByTypeIdStatement.write(typeId); - deleteEnumerationDeclarationByTypeIdStatement.write(typeId); - deletePropertyDeclarationByTypeIdStatement.write(typeId); - deleteFunctionDeclarationByTypeIdStatement.write(typeId); - deleteSignalDeclarationByTypeIdStatement.write(typeId); - deleteTypeStatement.write(typeId); - } + Prototypes &relinkableExtensions); void relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations, - const TypeIds &deletedTypeIds) - { - NanotraceHR::Tracer tracer{"relink alias properties"_t, projectStorageCategory()}; - - std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end()); - - Utils::set_greedy_difference( - aliasPropertyDeclarations.cbegin(), - aliasPropertyDeclarations.cend(), - deletedTypeIds.begin(), - deletedTypeIds.end(), - [&](const AliasPropertyDeclaration &alias) { - auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); - - if (!typeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)}; - - auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded( - typeId, alias.aliasPropertyName); - - updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId, - propertyTypeId, - propertyTraits, - alias.aliasImportedTypeNameId, - aliasId); - }, - TypeCompare<AliasPropertyDeclaration>{}); - } + const TypeIds &deletedTypeIds); void relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration, - const TypeIds &deletedTypeIds) - { - NanotraceHR::Tracer tracer{"relink properties"_t, projectStorageCategory()}; - - std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end()); - - Utils::set_greedy_difference( - relinkablePropertyDeclaration.cbegin(), - relinkablePropertyDeclaration.cend(), - deletedTypeIds.begin(), - deletedTypeIds.end(), - [&](const PropertyDeclaration &property) { - TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)}; - - updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId, - propertyTypeId); - }, - TypeCompare<PropertyDeclaration>{}); - } + const TypeIds &deletedTypeIds); template<typename Callable> void relinkPrototypes(Prototypes &relinkablePrototypes, const TypeIds &deletedTypeIds, - Callable updateStatement) - { - NanotraceHR::Tracer tracer{"relink prototypes"_t, projectStorageCategory()}; - - std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end()); - - Utils::set_greedy_difference( - relinkablePrototypes.cbegin(), - relinkablePrototypes.cend(), - deletedTypeIds.begin(), - deletedTypeIds.end(), - [&](const Prototype &prototype) { - TypeId prototypeId = fetchTypeId(prototype.prototypeNameId); - - if (!prototypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(prototype.prototypeNameId)}; - - updateStatement(prototype.typeId, prototypeId); - checkForPrototypeChainCycle(prototype.typeId); - }, - TypeCompare<Prototype>{}); - } + Callable updateStatement); void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, const SourceIds &updatedSourceIds, @@ -1505,295 +639,66 @@ private: PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - TypeIds &deletedTypeIds) - { - NanotraceHR::Tracer tracer{"delete not updated types"_t, projectStorageCategory()}; - - auto callback = [&](TypeId typeId) { - deletedTypeIds.push_back(typeId); - deleteType(typeId, - relinkableAliasPropertyDeclarations, - relinkablePropertyDeclarations, - relinkablePrototypes, - relinkableExtensions); - }; - - selectNotUpdatedTypesInSourcesStatement.readCallback(callback, - toIntegers(updatedSourceIds), - toIntegers(updatedTypeIds)); - for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) - callback(typeIdToBeDeleted); - } + TypeIds &deletedTypeIds); void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, Prototypes &relinkableExtensions, - TypeIds &deletedTypeIds) - { - NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()}; - - std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); - - relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { - updateTypePrototypeStatement.write(typeId, prototypeId); - }); - relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) { - updateTypeExtensionStatement.write(typeId, prototypeId); - }); - relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds); - relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); - } + TypeIds &deletedTypeIds); PropertyDeclarationId fetchAliasId(TypeId aliasTypeId, Utils::SmallStringView aliasPropertyName, - Utils::SmallStringView aliasPropertyNameTail) - { - if (aliasPropertyNameTail.empty()) - return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); + Utils::SmallStringView aliasPropertyNameTail); - auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, - aliasPropertyName); + void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations); - return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId, - aliasPropertyNameTail); - } + void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations); - void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations) - { - for (const auto &aliasDeclaration : aliasDeclarations) { - auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId); - - if (!aliasTypeId) { - throw TypeNameDoesNotExists{ - fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)}; - } - - auto aliasId = fetchAliasId(aliasTypeId, - aliasDeclaration.aliasPropertyName, - aliasDeclaration.aliasPropertyNameTail); - - updatePropertyDeclarationAliasIdAndTypeNameIdStatement - .write(aliasDeclaration.propertyDeclarationId, - aliasId, - aliasDeclaration.aliasImportedTypeNameId); - } - } - - void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations) - { - for (const auto &aliasDeclaration : aliasDeclarations) { - updatetPropertiesDeclarationValuesOfAliasStatement.write( - aliasDeclaration.propertyDeclarationId); - updatePropertyAliasDeclarationRecursivelyStatement.write( - aliasDeclaration.propertyDeclarationId); - } - } - - void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations) - { - for (const auto &aliasDeclaration : aliasDeclarations) - checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId); - } + void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations); void linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations, - const AliasPropertyDeclarations &updatedAliasPropertyDeclarations) - { - NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()}; - - linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations); - linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations); - - checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations); - checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations); - - updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations); - updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); - } + const AliasPropertyDeclarations &updatedAliasPropertyDeclarations); void synchronizeExportedTypes(const TypeIds &updatedTypeIds, Storage::Synchronization::ExportedTypes &exportedTypes, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()}; - - std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { - if (first.moduleId < second.moduleId) - return true; - else if (first.moduleId > second.moduleId) - return false; - - auto nameCompare = Sqlite::compare(first.name, second.name); - - if (nameCompare < 0) - return true; - else if (nameCompare > 0) - return false; - - return first.version < second.version; - }); - - auto range = selectExportedTypesForSourceIdsStatement - .template range<Storage::Synchronization::ExportedTypeView>( - toIntegers(updatedTypeIds)); - - auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view, - const Storage::Synchronization::ExportedType &type) -> long long { - auto moduleIdDifference = view.moduleId - type.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - auto nameDifference = Sqlite::compare(view.name, type.name); - if (nameDifference != 0) - return nameDifference; - - auto versionDifference = view.version.major.value - type.version.major.value; - if (versionDifference != 0) - return versionDifference; - - return view.version.minor.value - type.version.minor.value; - }; - - auto insert = [&](const Storage::Synchronization::ExportedType &type) { - if (!type.moduleId) - throw QmlDesigner::ModuleDoesNotExists{}; - - try { - if (type.version) { - insertExportedTypeNamesWithVersionStatement.write(type.moduleId, - type.name, - type.version.major.value, - type.version.minor.value, - type.typeId); - - } else if (type.version.major) { - insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId, - type.name, - type.version.major.value, - type.typeId); - } else { - insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId, - type.name, - type.typeId); - } - } catch (const Sqlite::ConstraintPreventsModification &) { - throw QmlDesigner::ExportedTypeCannotBeInserted{type.name}; - } - }; - - auto update = [&](const Storage::Synchronization::ExportedTypeView &view, - const Storage::Synchronization::ExportedType &type) { - if (view.typeId != type.typeId) { - handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(view.typeId, - relinkableAliasPropertyDeclarations); - handlePrototypes(view.typeId, relinkablePrototypes); - handleExtensions(view.typeId, relinkableExtensions); - updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); - return Sqlite::UpdateChange::Update; - } - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) { - handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations); - handleAliasPropertyDeclarationsWithPropertyType(view.typeId, - relinkableAliasPropertyDeclarations); - handlePrototypes(view.typeId, relinkablePrototypes); - handleExtensions(view.typeId, relinkableExtensions); - deleteExportedTypeNameStatement.write(view.exportedTypeNameId); - }; - - Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove); - } + Prototypes &relinkableExtensions); void synchronizePropertyDeclarationsInsertAlias( AliasPropertyDeclarations &insertedAliasPropertyDeclarations, const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, - TypeId typeId) - { - auto callback = [&](PropertyDeclarationId propertyDeclarationId) { - insertedAliasPropertyDeclarations.emplace_back(typeId, - propertyDeclarationId, - fetchImportedTypeNameId(value.typeName, - sourceId), - value.aliasPropertyName, - value.aliasPropertyNameTail); - return Sqlite::CallbackControl::Abort; - }; - - insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name); - } + TypeId typeId); + + QVarLengthArray<PropertyDeclarationId, 128> fetchPropertyDeclarationIds(TypeId baseTypeId) const; + + PropertyDeclarationId fetchNextPropertyDeclarationId(TypeId baseTypeId, + Utils::SmallStringView propertyName) const; + + PropertyDeclarationId fetchPropertyDeclarationId(TypeId typeId, + Utils::SmallStringView propertyName) const; + + PropertyDeclarationId fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const; + + PropertyDeclarationId fetchDefaultPropertyDeclarationId(TypeId typeId) const; void synchronizePropertyDeclarationsInsertProperty( - const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId) - { - auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); - auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId)}; - - auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<PropertyDeclarationId>( - typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId); - - auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement - .template value<PropertyDeclarationId>(typeId, - value.name); - if (nextPropertyDeclarationId) { - updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId, - propertyDeclarationId); - updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement - .write(propertyDeclarationId, propertyTypeId, value.traits); - } - } + const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId); void synchronizePropertyDeclarationsUpdateAlias( AliasPropertyDeclarations &updatedAliasPropertyDeclarations, const Storage::Synchronization::PropertyDeclarationView &view, const Storage::Synchronization::PropertyDeclaration &value, - SourceId sourceId) - { - auto last = updatedAliasPropertyDeclarations.emplace_back(view.typeId, - view.id, - fetchImportedTypeNameId(value.typeName, - sourceId), - value.aliasPropertyName, - value.aliasPropertyNameTail, - view.aliasId); - } + SourceId sourceId); - auto synchronizePropertyDeclarationsUpdateProperty( + Sqlite::UpdateChange synchronizePropertyDeclarationsUpdateProperty( const Storage::Synchronization::PropertyDeclarationView &view, const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, - PropertyDeclarationIds &propertyDeclarationIds) - { - auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId); - - auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId); - - if (!propertyTypeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId)}; - - if (view.traits == value.traits && propertyTypeId == view.typeId - && propertyImportedTypeNameId == view.typeNameId) - return Sqlite::UpdateChange::No; - - updatePropertyDeclarationStatement.write(view.id, - propertyTypeId, - value.traits, - propertyImportedTypeNameId); - updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id, - propertyTypeId, - value.traits); - propertyDeclarationIds.push_back(view.id); - return Sqlite::UpdateChange::Update; - } + PropertyDeclarationIds &propertyDeclarationIds); void synchronizePropertyDeclarations( TypeId typeId, @@ -1801,270 +706,78 @@ private: SourceId sourceId, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarationIds &propertyDeclarationIds) - { - NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()}; - - std::sort(propertyDeclarations.begin(), - propertyDeclarations.end(), - [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectPropertyDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::PropertyDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) { - if (value.kind == Storage::Synchronization::PropertyKind::Alias) { - synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations, - value, - sourceId, - typeId); - } else { - synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId); - } - }; - - auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - if (value.kind == Storage::Synchronization::PropertyKind::Alias) { - synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations, - view, - value, - sourceId); - propertyDeclarationIds.push_back(view.id); - } else { - return synchronizePropertyDeclarationsUpdateProperty(view, - value, - sourceId, - propertyDeclarationIds); - } - - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) { - auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement - .template value<PropertyDeclarationId>(typeId, - view.name); - if (nextPropertyDeclarationId) { - updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement - .write(nextPropertyDeclarationId, view.id); - } - - updateDefaultPropertyIdToNullStatement.write(view.id); - deletePropertyDeclarationStatement.write(view.id); - propertyDeclarationIds.push_back(view.id); - }; - - Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); - } + PropertyDeclarationIds &propertyDeclarationIds); - void resetRemovedAliasPropertyDeclarationsToNull(Storage::Synchronization::Type &type, - PropertyDeclarationIds &propertyDeclarationIds) + class AliasPropertyDeclarationView { - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations; + public: + explicit AliasPropertyDeclarationView(Utils::SmallStringView name, + PropertyDeclarationId id, + PropertyDeclarationId aliasId) + : name{name} + , id{id} + , aliasId{aliasId} + {} - class AliasPropertyDeclarationView + template<typename String> + friend void convertToString(String &string, + const AliasPropertyDeclarationView &aliasPropertyDeclarationView) { - public: - explicit AliasPropertyDeclarationView(Utils::SmallStringView name, - PropertyDeclarationId id, - PropertyDeclarationId aliasId) - : name{name} - , id{id} - , aliasId{aliasId} - {} - - public: - Utils::SmallStringView name; - PropertyDeclarationId id; - PropertyDeclarationId aliasId; - }; - - std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement - .template range<AliasPropertyDeclarationView>(type.typeId); - - auto compareKey = [](const AliasPropertyDeclarationView &view, - const Storage::Synchronization::PropertyDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {}; - - auto update = [&](const AliasPropertyDeclarationView &, - const Storage::Synchronization::PropertyDeclaration &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const AliasPropertyDeclarationView &view) { - updatePropertyDeclarationAliasIdToNullStatement.write(view.id); - propertyDeclarationIds.push_back(view.id); - }; - - Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); - } + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", aliasPropertyDeclarationView.name), + keyValue("id", aliasPropertyDeclarationView.id), + keyValue("alias id", aliasPropertyDeclarationView.aliasId)); - void resetRemovedAliasPropertyDeclarationsToNull( - Storage::Synchronization::Types &types, - AliasPropertyDeclarations &relinkableAliasPropertyDeclarations) - { - NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t, - projectStorageCategory()}; + convertToString(string, dict); + } - PropertyDeclarationIds propertyDeclarationIds; - propertyDeclarationIds.reserve(types.size()); + public: + Utils::SmallStringView name; + PropertyDeclarationId id; + PropertyDeclarationId aliasId; + }; - for (auto &&type : types) - resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds); + void resetRemovedAliasPropertyDeclarationsToNull(Storage::Synchronization::Type &type, + PropertyDeclarationIds &propertyDeclarationIds); - removeRelinkableEntries(relinkableAliasPropertyDeclarations, - propertyDeclarationIds, - PropertyCompare<AliasPropertyDeclaration>{}); - } + void resetRemovedAliasPropertyDeclarationsToNull( + Storage::Synchronization::Types &types, + AliasPropertyDeclarations &relinkableAliasPropertyDeclarations); + + void handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId, + TypeId prototypeId, + Prototypes &relinkablePrototypes); + void handlePrototypesAndExtensionsWithSourceId(SourceId sourceId, + TypeId prototypeId, + TypeId extensionId, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions); + void handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId, + TypeId extensionId, + Prototypes &relinkableExtensions); ImportId insertDocumentImport(const Storage::Import &import, Storage::Synchronization::ImportKind importKind, ModuleId sourceModuleId, - ImportId parentImportId) - { - if (import.version.minor) { - return insertDocumentImportWithVersionStatement - .template value<ImportId>(import.sourceId, - import.moduleId, - sourceModuleId, - importKind, - import.version.major.value, - import.version.minor.value, - parentImportId); - } else if (import.version.major) { - return insertDocumentImportWithMajorVersionStatement - .template value<ImportId>(import.sourceId, - import.moduleId, - sourceModuleId, - importKind, - import.version.major.value, - parentImportId); - } else { - return insertDocumentImportWithoutVersionStatement.template value<ImportId>( - import.sourceId, import.moduleId, sourceModuleId, importKind, parentImportId); - } - } + ImportId parentImportId, + Relink forceRelink, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions); void synchronizeDocumentImports(Storage::Imports &imports, const SourceIds &updatedSourceIds, - Storage::Synchronization::ImportKind importKind) - { - std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) { - return std::tie(first.sourceId, first.moduleId, first.version) - < std::tie(second.sourceId, second.moduleId, second.version); - }); - - auto range = selectDocumentImportForSourceIdStatement - .template range<Storage::Synchronization::ImportView>(toIntegers( - updatedSourceIds), - importKind); - - auto compareKey = [](const Storage::Synchronization::ImportView &view, - const Storage::Import &import) -> long long { - auto sourceIdDifference = view.sourceId - import.sourceId; - if (sourceIdDifference != 0) - return sourceIdDifference; - - auto moduleIdDifference = view.moduleId - import.moduleId; - if (moduleIdDifference != 0) - return moduleIdDifference; - - auto versionDifference = view.version.major.value - import.version.major.value; - if (versionDifference != 0) - return versionDifference; - - return view.version.minor.value - import.version.minor.value; - }; - - auto insert = [&](const Storage::Import &import) { - auto importId = insertDocumentImport(import, importKind, import.moduleId, ImportId{}); - auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) { - Storage::Import additionImport{exportedModuleId, - Storage::Version{majorVersion, minorVersion}, - import.sourceId}; - - auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import - ? Storage::Synchronization::ImportKind::ModuleExportedImport - : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency; - - insertDocumentImport(additionImport, exportedImportKind, import.moduleId, importId); - }; - - selectModuleExportedImportsForModuleIdStatement.readCallback(callback, - import.moduleId, - import.version.major.value, - import.version.minor.value); - }; - - auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::ImportView &view) { - deleteDocumentImportStatement.write(view.importId); - deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId); - }; - - Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove); - } - - static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations ¶meters) - { - Utils::PathString json; - json.append("["); - - Utils::SmallStringView comma{""}; - - for (const auto ¶meter : parameters) { - json.append(comma); - comma = ","; - json.append(R"({"n":")"); - json.append(parameter.name); - json.append(R"(","tn":")"); - json.append(parameter.typeName); - if (parameter.traits == Storage::PropertyDeclarationTraits::None) { - json.append("\"}"); - } else { - json.append(R"(","tr":)"); - json.append(Utils::SmallString::number(to_underlying(parameter.traits))); - json.append("}"); - } - } + Storage::Synchronization::ImportKind importKind, + Relink forceRelink, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions); - json.append("]"); - - return json; - } + static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations ¶meters); TypeId fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, - Utils::SmallStringView name) const override - { - return selectTypeIdByModuleIdAndExportedNameStatement.template value<TypeId>(moduleId, name); - } + Utils::SmallStringView name) const override; - void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths) - { - for (auto &path : paths) - path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName); - } + void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths); class PropertyEditorQmlPathView { @@ -2075,6 +788,19 @@ private: , directoryId{directoryId} {} + template<typename String> + friend void convertToString(String &string, + const PropertyEditorQmlPathView &propertyEditorQmlPathView) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", propertyEditorQmlPathView.typeId), + keyValue("source id", propertyEditorQmlPathView.pathId), + keyValue("directory id", propertyEditorQmlPathView.directoryId)); + + convertToString(string, dict); + } + public: TypeId typeId; SourceId pathId; @@ -2082,279 +808,33 @@ private: }; void synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceIds updatedPropertyEditorQmlPathsSourceIds) - { - using Storage::Synchronization::PropertyEditorQmlPath; - std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) { - return first.typeId < second.typeId; - }); - - auto range = selectPropertyEditorPathsForForSourceIdsStatement - .template range<PropertyEditorQmlPathView>( - toIntegers(updatedPropertyEditorQmlPathsSourceIds)); - - auto compareKey = [](const PropertyEditorQmlPathView &view, - const PropertyEditorQmlPath &value) -> long long { - return view.typeId - value.typeId; - }; - - auto insert = [&](const PropertyEditorQmlPath &path) { - if (path.typeId) - insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId); - }; - - auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) { - if (value.pathId != view.pathId || value.directoryId != view.directoryId) { - updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId); - return Sqlite::UpdateChange::Update; - } - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const PropertyEditorQmlPathView &view) { - deletePropertyEditorPathStatement.write(view.typeId); - }; - - Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove); - } + SourceIds updatedPropertyEditorQmlPathsSourceIds); void synchronizePropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceIds updatedPropertyEditorQmlPathsSourceIds) - { - NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t, - projectStorageCategory()}; - - addTypeIdToPropertyEditorQmlPaths(paths); - synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds); - } + SourceIds updatedPropertyEditorQmlPathsSourceIds); void synchronizeFunctionDeclarations( - TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()}; - - std::sort(functionsDeclarations.begin(), - functionsDeclarations.end(), - [](auto &&first, auto &&second) { - auto compare = Sqlite::compare(first.name, second.name); - - if (compare == 0) { - Utils::PathString firstSignature{createJson(first.parameters)}; - Utils::PathString secondSignature{createJson(second.parameters)}; - - return Sqlite::compare(firstSignature, secondSignature) < 0; - } - - return compare < 0; - }); - - auto range = selectFunctionDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::FunctionDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view, - const Storage::Synchronization::FunctionDeclaration &value) { - auto nameKey = Sqlite::compare(view.name, value.name); - if (nameKey != 0) - return nameKey; - - Utils::PathString valueSignature{createJson(value.parameters)}; - - return Sqlite::compare(view.signature, valueSignature); - }; - - auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) { - Utils::PathString signature{createJson(value.parameters)}; - - insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature); - }; - - auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view, - const Storage::Synchronization::FunctionDeclaration &value) { - Utils::PathString signature{createJson(value.parameters)}; - - if (value.returnTypeName == view.returnTypeName) - return Sqlite::UpdateChange::No; - - updateFunctionDeclarationStatement.write(view.id, value.returnTypeName); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) { - deleteFunctionDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove); - } + TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations); void synchronizeSignalDeclarations(TypeId typeId, - Storage::Synchronization::SignalDeclarations &signalDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()}; - - std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) { - auto compare = Sqlite::compare(first.name, second.name); - - if (compare == 0) { - Utils::PathString firstSignature{createJson(first.parameters)}; - Utils::PathString secondSignature{createJson(second.parameters)}; - - return Sqlite::compare(firstSignature, secondSignature) < 0; - } - - return compare < 0; - }); - - auto range = selectSignalDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::SignalDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view, - const Storage::Synchronization::SignalDeclaration &value) { - auto nameKey = Sqlite::compare(view.name, value.name); - if (nameKey != 0) - return nameKey; - - Utils::PathString valueSignature{createJson(value.parameters)}; - - return Sqlite::compare(view.signature, valueSignature); - }; - - auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) { - Utils::PathString signature{createJson(value.parameters)}; - - insertSignalDeclarationStatement.write(typeId, value.name, signature); - }; - - auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view, - [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) { - return Sqlite::UpdateChange::No; - }; - - auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) { - deleteSignalDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove); - } + Storage::Synchronization::SignalDeclarations &signalDeclarations); static Utils::PathString createJson( - const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations) - { - Utils::PathString json; - json.append("{"); - - Utils::SmallStringView comma{"\""}; - - for (const auto &enumerator : enumeratorDeclarations) { - json.append(comma); - comma = ",\""; - json.append(enumerator.name); - if (enumerator.hasValue) { - json.append("\":\""); - json.append(Utils::SmallString::number(enumerator.value)); - json.append("\""); - } else { - json.append("\":null"); - } - } - - json.append("}"); - - return json; - } + const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations); void synchronizeEnumerationDeclarations( - TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize enumeation declaration"_t, projectStorageCategory()}; - - std::sort(enumerationDeclarations.begin(), - enumerationDeclarations.end(), - [](auto &&first, auto &&second) { - return Sqlite::compare(first.name, second.name) < 0; - }); - - auto range = selectEnumerationDeclarationsForTypeIdStatement - .template range<Storage::Synchronization::EnumerationDeclarationView>(typeId); - - auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view, - const Storage::Synchronization::EnumerationDeclaration &value) { - return Sqlite::compare(view.name, value.name); - }; - - auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) { - Utils::PathString signature{createJson(value.enumeratorDeclarations)}; - - insertEnumerationDeclarationStatement.write(typeId, value.name, signature); - }; - - auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view, - const Storage::Synchronization::EnumerationDeclaration &value) { - Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)}; - - if (enumeratorDeclarations == view.enumeratorDeclarations) - return Sqlite::UpdateChange::No; - - updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) { - deleteEnumerationDeclarationStatement.write(view.id); - }; - - Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove); - } + TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations); void extractExportedTypes(TypeId typeId, const Storage::Synchronization::Type &type, - Storage::Synchronization::ExportedTypes &exportedTypes) - { - for (const auto &exportedType : type.exportedTypes) - exportedTypes.emplace_back(exportedType.name, - exportedType.version, - typeId, - exportedType.moduleId); - } - - TypeId declareType(Storage::Synchronization::Type &type) - { - if (type.typeName.isEmpty()) { - type.typeId = selectTypeIdBySourceIdStatement.template value<TypeId>(type.sourceId); - - return type.typeId; - } + Storage::Synchronization::ExportedTypes &exportedTypes); - type.typeId = insertTypeStatement.template value<TypeId>(type.sourceId, type.typeName); - - if (!type.typeId) - type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(type.sourceId, - type.typeName); - - return type.typeId; - } + TypeId declareType(Storage::Synchronization::Type &type); void syncDeclarations(Storage::Synchronization::Type &type, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarationIds &propertyDeclarationIds) - { - NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()}; - - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - synchronizePropertyDeclarations(type.typeId, - type.propertyDeclarations, - type.sourceId, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - propertyDeclarationIds); - synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations); - synchronizeSignalDeclarations(type.typeId, type.signalDeclarations); - synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations); - } + PropertyDeclarationIds &propertyDeclarationIds); template<typename Relinkable, typename Ids, typename Compare> void removeRelinkableEntries(std::vector<Relinkable> &relinkables, Ids &ids, Compare compare) @@ -2381,23 +861,7 @@ private: void syncDeclarations(Storage::Synchronization::Types &types, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, AliasPropertyDeclarations &updatedAliasPropertyDeclarations, - PropertyDeclarations &relinkablePropertyDeclarations) - { - NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()}; - - PropertyDeclarationIds propertyDeclarationIds; - propertyDeclarationIds.reserve(types.size() * 10); - - for (auto &&type : types) - syncDeclarations(type, - insertedAliasPropertyDeclarations, - updatedAliasPropertyDeclarations, - propertyDeclarationIds); - - removeRelinkableEntries(relinkablePropertyDeclarations, - propertyDeclarationIds, - PropertyCompare<PropertyDeclaration>{}); - } + PropertyDeclarations &relinkablePropertyDeclarations); class TypeWithDefaultPropertyView { @@ -2407,240 +871,55 @@ private: , defaultPropertyId{defaultPropertyId} {} + template<typename String> + friend void convertToString(String &string, const TypeWithDefaultPropertyView &view) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", view.typeId), + keyValue("property id", view.defaultPropertyId)); + + convertToString(string, dict); + } + TypeId typeId; PropertyDeclarationId defaultPropertyId; }; - void syncDefaultProperties(Storage::Synchronization::Types &types) - { - NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()}; - - auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>(); - - auto compareKey = [](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - return view.typeId - value.typeId; - }; - - auto insert = [&](const Storage::Synchronization::Type &) { - - }; - - auto update = [&](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - PropertyDeclarationId valueDefaultPropertyId; - if (value.defaultPropertyName.size()) - valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded( - value.typeId, value.defaultPropertyName) - .propertyDeclarationId; + void syncDefaultProperties(Storage::Synchronization::Types &types); - if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) - return Sqlite::UpdateChange::No; + void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types); - updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId); + void checkForPrototypeChainCycle(TypeId typeId) const; - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const TypeWithDefaultPropertyView &) {}; - - Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); - } - - void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types) - { - NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()}; - - auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>(); - - auto compareKey = [](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - return view.typeId - value.typeId; - }; - - auto insert = [&](const Storage::Synchronization::Type &) { - - }; - - auto update = [&](const TypeWithDefaultPropertyView &view, - const Storage::Synchronization::Type &value) { - PropertyDeclarationId valueDefaultPropertyId; - if (value.defaultPropertyName.size()) { - auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( - value.typeId, value.defaultPropertyName); - if (optionalValueDefaultPropertyId) - valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId; - } - - if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) - return Sqlite::UpdateChange::No; - - updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{}); - - return Sqlite::UpdateChange::Update; - }; - - auto remove = [&](const TypeWithDefaultPropertyView &) {}; - - Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove); - } - - void checkForPrototypeChainCycle(TypeId typeId) const - { - auto callback = [=](TypeId currentTypeId) { - if (typeId == currentTypeId) - throw PrototypeChainCycle{}; - }; - - selectTypeIdsForPrototypeChainIdStatement.readCallback(callback, typeId); - } - - void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const - { - auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) { - if (propertyDeclarationId == currentPropertyDeclarationId) - throw AliasChainCycle{}; - }; - - selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback, - propertyDeclarationId); - } + void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const; std::pair<TypeId, ImportedTypeNameId> fetchImportedTypeNameIdAndTypeId( - const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId) - { - TypeId typeId; - ImportedTypeNameId typeNameId; - if (!std::visit([](auto &&typeName_) -> bool { return typeName_.name.isEmpty(); }, typeName)) { - typeNameId = fetchImportedTypeNameId(typeName, sourceId); - - typeId = fetchTypeId(typeNameId); - - if (!typeId) - throw TypeNameDoesNotExists{fetchImportedTypeName(typeNameId)}; - } - - return {typeId, typeNameId}; - } + const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId); - void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds) - { - if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) - return; - - auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype, - type.sourceId); - auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension, - type.sourceId); - - updatePrototypeAndExtensionStatement.write(type.typeId, - prototypeId, - prototypeTypeNameId, - extensionId, - extensionTypeNameId); - - if (prototypeId || extensionId) - checkForPrototypeChainCycle(type.typeId); - - typeIds.push_back(type.typeId); - } + void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds); void syncPrototypesAndExtensions(Storage::Synchronization::Types &types, Prototypes &relinkablePrototypes, - Prototypes &relinkableExtensions) - { - NanotraceHR::Tracer tracer{"synchronize prototypes"_t, projectStorageCategory()}; - - TypeIds typeIds; - typeIds.reserve(types.size()); + Prototypes &relinkableExtensions); - for (auto &type : types) - syncPrototypeAndExtension(type, typeIds); - - removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{}); - removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{}); - } - - ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const - { - if (import.version) { - return selectImportIdBySourceIdAndModuleIdAndVersionStatement.template value<ImportId>( - sourceId, import.moduleId, import.version.major.value, import.version.minor.value); - } - - if (import.version.major) { - return selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement - .template value<ImportId>(sourceId, import.moduleId, import.version.major.value); - } - - return selectImportIdBySourceIdAndModuleIdStatement.template value<ImportId>(sourceId, - import.moduleId); - } + ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const; ImportedTypeNameId fetchImportedTypeNameId(const Storage::Synchronization::ImportedTypeName &name, - SourceId sourceId) - { - struct Inspect - { - auto operator()(const Storage::Synchronization::ImportedType &importedType) - { - return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported, - sourceId, - importedType.name); - } - - auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType) - { - ImportId importId = storage.fetchImportId(sourceId, importedType.import); - - return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported, - importId, - importedType.name); - } - - ProjectStorage &storage; - SourceId sourceId; - }; - - return std::visit(Inspect{*this, sourceId}, name); - } + SourceId sourceId); template<typename Id> ImportedTypeNameId fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind kind, Id id, - Utils::SmallStringView typeName) - { - auto importedTypeNameId = selectImportedTypeNameIdStatement - .template value<ImportedTypeNameId>(kind, id, typeName); - - if (importedTypeNameId) - return importedTypeNameId; - - return insertImportedTypeNameIdStatement.template value<ImportedTypeNameId>(kind, id, typeName); - } - - TypeId fetchTypeId(ImportedTypeNameId typeNameId) const - { - auto kind = selectKindFromImportedTypeNamesStatement - .template value<Storage::Synchronization::TypeNameKind>(typeNameId); - - return fetchTypeId(typeNameId, kind); - } + Utils::SmallStringView typeName); - Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const - { - return selectNameFromImportedTypeNamesStatement.template value<Utils::SmallString>(typeNameId); - } + TypeId fetchTypeId(ImportedTypeNameId typeNameId) const; - TypeId fetchTypeId(ImportedTypeNameId typeNameId, Storage::Synchronization::TypeNameKind kind) const - { - if (kind == Storage::Synchronization::TypeNameKind::QualifiedExported) { - return selectTypeIdForQualifiedImportedTypeNameNamesStatement.template value<TypeId>( - typeNameId); - } + Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const; + SourceId fetchTypeSourceId(TypeId typeId) const; - return selectTypeIdForImportedTypeNameNamesStatement.template value<TypeId>(typeNameId); - } + TypeId fetchTypeId(ImportedTypeNameId typeNameId, + Storage::Synchronization::TypeNameKind kind) const; class FetchPropertyDeclarationResult { @@ -2653,1303 +932,65 @@ private: , propertyTraits{propertyTraits} {} + template<typename String> + friend void convertToString(String &string, const FetchPropertyDeclarationResult &result) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("property type id", result.propertyTypeId), + keyValue("property declaration id", result.propertyDeclarationId), + keyValue("property traits", result.propertyTraits)); + + convertToString(string, dict); + } + public: TypeId propertyTypeId; PropertyDeclarationId propertyDeclarationId; Storage::PropertyDeclarationTraits propertyTraits; }; - auto fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, - Utils::SmallStringView name) - { - return selectPropertyDeclarationByTypeIdAndNameStatement - .template optionalValue<FetchPropertyDeclarationResult>(typeId, name); - } + std::optional<FetchPropertyDeclarationResult> fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( + TypeId typeId, Utils::SmallStringView name); FetchPropertyDeclarationResult fetchPropertyDeclarationByTypeIdAndNameUngarded( - TypeId typeId, Utils::SmallStringView name) - { - auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, - name); - - if (propertyDeclaration) - return *propertyDeclaration; - - throw PropertyNameDoesNotExists{}; - } + TypeId typeId, Utils::SmallStringView name); PropertyDeclarationId fetchPropertyDeclarationIdByTypeIdAndNameUngarded(TypeId typeId, - Utils::SmallStringView name) - { - auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement - .template value<PropertyDeclarationId>(typeId, name); + Utils::SmallStringView name); - if (propertyDeclarationId) - return propertyDeclarationId; + SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath); - throw PropertyNameDoesNotExists{}; - } + SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath); - SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath) - { - return selectSourceContextIdFromSourceContextsBySourceContextPathStatement - .template value<SourceContextId>(sourceContextPath); - } + SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath) - { - insertIntoSourceContextsStatement.write(sourceContextPath); + SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName); - return SourceContextId::create(database.lastInsertedRowId()); - } + Storage::Synchronization::ExportedTypes fetchExportedTypes(TypeId typeId); - SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - insertIntoSourcesStatement.write(sourceContextId, sourceName); + Storage::Synchronization::PropertyDeclarations fetchPropertyDeclarations(TypeId typeId); - return SourceId::create(database.lastInsertedRowId()); - } - - SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName) - { - return selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement - .template value<SourceId>(sourceContextId, sourceName); - } - - auto fetchExportedTypes(TypeId typeId) - { - return selectExportedTypesByTypeIdStatement - .template values<Storage::Synchronization::ExportedType, 12>(typeId); - } - - auto fetchPropertyDeclarations(TypeId typeId) - { - return selectPropertyDeclarationsByTypeIdStatement - .template values<Storage::Synchronization::PropertyDeclaration, 24>(typeId); - } - - auto fetchFunctionDeclarations(TypeId typeId) - { - Storage::Synchronization::FunctionDeclarations functionDeclarations; - - auto callback = [&](Utils::SmallStringView name, - Utils::SmallStringView returnType, - FunctionDeclarationId functionDeclarationId) { - auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType); - functionDeclaration.parameters = selectFunctionParameterDeclarationsStatement - .template values<Storage::Synchronization::ParameterDeclaration, - 8>(functionDeclarationId); - }; - - selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); - - return functionDeclarations; - } - - auto fetchSignalDeclarations(TypeId typeId) - { - Storage::Synchronization::SignalDeclarations signalDeclarations; - - auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) { - auto &signalDeclaration = signalDeclarations.emplace_back(name); - signalDeclaration.parameters = selectSignalParameterDeclarationsStatement - .template values<Storage::Synchronization::ParameterDeclaration, - 8>(signalDeclarationId); - }; - - selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId); - - return signalDeclarations; - } - - auto fetchEnumerationDeclarations(TypeId typeId) - { - Storage::Synchronization::EnumerationDeclarations enumerationDeclarations; - - auto callback = [&](Utils::SmallStringView name, - EnumerationDeclarationId enumerationDeclarationId) { - enumerationDeclarations.emplace_back( - name, - selectEnumeratorDeclarationStatement - .template values<Storage::Synchronization::EnumeratorDeclaration, 8>( - enumerationDeclarationId)); - }; - - selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement - .readCallback(callback, typeId); - - return enumerationDeclarations; - } - - class Initializer - { - public: - Initializer(Database &database, bool isInitialized) - { - if (!isInitialized) { - auto moduleIdColumn = createModulesTable(database); - createSourceContextsTable(database); - createSourcesTable(database); - createTypesAndePropertyDeclarationsTables(database, moduleIdColumn); - createExportedTypeNamesTable(database, moduleIdColumn); - createImportedTypeNamesTable(database); - createEnumerationsTable(database); - createFunctionsTable(database); - createSignalsTable(database); - createModuleExportedImportsTable(database, moduleIdColumn); - createDocumentImportsTable(database, moduleIdColumn); - createFileStatusesTable(database); - createProjectDatasTable(database); - createPropertyEditorPathsTable(database); - createTypeAnnotionsTable(database); - } - database.setIsInitialized(true); - } - - void createSourceContextsTable(Database &database) - { - Sqlite::Table table; - table.setUseIfNotExists(true); - table.setName("sourceContexts"); - table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); - const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath"); - - table.addUniqueIndex({sourceContextPathColumn}); - - table.initialize(database); - } - - void createSourcesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("sources"); - table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - const auto &sourceContextIdColumn = table.addColumn( - "sourceContextId", - Sqlite::StrictColumnType::Integer, - {Sqlite::NotNull{}, - Sqlite::ForeignKey{"sourceContexts", - "sourceContextId", - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade}}); - const auto &sourceNameColumn = table.addColumn("sourceName", - Sqlite::StrictColumnType::Text); - table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn}); - - table.initialize(database); - } - - void createTypesAndePropertyDeclarationsTables( - Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable typesTable; - typesTable.setUseIfNotExists(true); - typesTable.setName("types"); - typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text); - typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer); - auto &prototypeIdColumn = typesTable.addForeignKeyColumn("prototypeId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer); - auto &extensionIdColumn = typesTable.addForeignKeyColumn("extensionId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer); - auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId", - Sqlite::StrictColumnType::Integer); - typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer); - typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn}); - typesTable.addIndex({defaultPropertyIdColumn}); - typesTable.addIndex({prototypeIdColumn}); - typesTable.addIndex({extensionIdColumn}); - - typesTable.initialize(database); - - { - Sqlite::StrictTable propertyDeclarationTable; - propertyDeclarationTable.setUseIfNotExists(true); - propertyDeclarationTable.setName("propertyDeclarations"); - propertyDeclarationTable.addColumn("propertyDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId"); - auto &nameColumn = propertyDeclarationTable.addColumn("name"); - propertyDeclarationTable.addForeignKeyColumn("propertyTypeId", - typesTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - propertyDeclarationTable.addColumn("propertyTraits", - Sqlite::StrictColumnType::Integer); - propertyDeclarationTable.addColumn("propertyImportedTypeNameId", - Sqlite::StrictColumnType::Integer); - auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn( - "aliasPropertyDeclarationId", - propertyDeclarationTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn( - "aliasPropertyDeclarationTailId", - propertyDeclarationTable, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Restrict); - - propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); - propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, - "aliasPropertyDeclarationId IS NOT NULL"); - propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn}, - "aliasPropertyDeclarationTailId IS NOT NULL"); - - propertyDeclarationTable.initialize(database); - } - } - - void createExportedTypeNamesTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("exportedTypeNames"); - table.addColumn("exportedTypeNameId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::NoAction); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &majorVersionColumn = table.addColumn("majorVersion", - Sqlite::StrictColumnType::Integer); - auto &minorVersionColumn = table.addColumn("minorVersion", - Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({moduleIdColumn, nameColumn}, - "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - - table.addIndex({typeIdColumn}); - - table.initialize(database); - } - - void createImportedTypeNamesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("importedTypeNames"); - table.addColumn("importedTypeNameId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &importOrSourceIdColumn = table.addColumn("importOrSourceId"); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn}); - - table.initialize(database); - } - - void createEnumerationsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("enumerationDeclarations"); - table.addColumn("enumerationDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({typeIdColumn, nameColumn}); - - table.initialize(database); - } - - void createFunctionsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("functionDeclarations"); - table.addColumn("functionDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); - table.addColumn("returnTypeName"); - - table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); - - table.initialize(database); - } - - void createSignalsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("signalDeclarations"); - table.addColumn("signalDeclarationId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn}); - - table.initialize(database); - } - - Sqlite::StrictColumn createModulesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("modules"); - auto &modelIdColumn = table.addColumn("moduleId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({nameColumn}); - - table.initialize(database); - - return std::move(modelIdColumn); - } - - void createModuleExportedImportsTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("moduleExportedImports"); - table.addColumn("moduleExportedImportId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &sourceIdColumn = table.addColumn("exportedModuleId", - Sqlite::StrictColumnType::Integer); - table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer); - table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer); - table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({sourceIdColumn, moduleIdColumn}); - - table.initialize(database); - } - - void createDocumentImportsTable(Database &database, - const Sqlite::StrictColumn &foreignModuleIdColumn) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("documentImports"); - table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - auto &moduleIdColumn = table.addForeignKeyColumn("moduleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId", - foreignModuleIdColumn, - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade, - Sqlite::Enforment::Immediate); - auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer); - auto &majorVersionColumn = table.addColumn("majorVersion", - Sqlite::StrictColumnType::Integer); - auto &minorVersionColumn = table.addColumn("minorVersion", - Sqlite::StrictColumnType::Integer); - auto &parentImportIdColumn = table.addColumn("parentImportId", - Sqlite::StrictColumnType::Integer); - - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - parentImportIdColumn}, - "majorVersion IS NULL AND minorVersion IS NULL"); - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - majorVersionColumn, - parentImportIdColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NULL"); - table.addUniqueIndex({sourceIdColumn, - moduleIdColumn, - kindColumn, - sourceModuleIdColumn, - majorVersionColumn, - minorVersionColumn, - parentImportIdColumn}, - "majorVersion IS NOT NULL AND minorVersion IS NOT NULL"); - - table.initialize(database); - } + Storage::Synchronization::FunctionDeclarations fetchFunctionDeclarations(TypeId typeId); - void createFileStatusesTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setName("fileStatuses"); - table.addColumn("sourceId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}, - Sqlite::ForeignKey{"sources", - "sourceId", - Sqlite::ForeignKeyAction::NoAction, - Sqlite::ForeignKeyAction::Cascade}}); - table.addColumn("size", Sqlite::StrictColumnType::Integer); - table.addColumn("lastModified", Sqlite::StrictColumnType::Integer); - - table.initialize(database); - } + Storage::Synchronization::SignalDeclarations fetchSignalDeclarations(TypeId typeId); - void createProjectDatasTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("projectDatas"); - auto &projectSourceIdColumn = table.addColumn("projectSourceId", - Sqlite::StrictColumnType::Integer); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - table.addColumn("moduleId", Sqlite::StrictColumnType::Integer); - table.addColumn("fileType", Sqlite::StrictColumnType::Integer); - - table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn}); - table.addUniqueIndex({sourceIdColumn}); - - table.initialize(database); - } + Storage::Synchronization::EnumerationDeclarations fetchEnumerationDeclarations(TypeId typeId); - void createPropertyEditorPathsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("propertyEditorPaths"); - table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer); - auto &directoryIdColumn = table.addColumn("directoryId", - Sqlite::StrictColumnType::Integer); - - table.addIndex({directoryIdColumn}); - - table.initialize(database); - } + class Initializer; - void createTypeAnnotionsTable(Database &database) - { - Sqlite::StrictTable table; - table.setUseIfNotExists(true); - table.setUseWithoutRowId(true); - table.setName("typeAnnotations"); - auto &typeIdColumn = table.addColumn("typeId", - Sqlite::StrictColumnType::Integer, - {Sqlite::PrimaryKey{}}); - auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer); - table.addColumn("iconPath", Sqlite::StrictColumnType::Text); - table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text); - table.addColumn("hints", Sqlite::StrictColumnType::Text); - - table.addUniqueIndex({sourceIdColumn, typeIdColumn}); - - table.initialize(database); - } - }; + struct Statements; public: Database &database; + ProjectStorageErrorNotifierInterface *errorNotifier = nullptr; // cannot be null Sqlite::ExclusiveNonThrowingDestructorTransaction<Database> exclusiveTransaction; - Initializer initializer; + std::unique_ptr<Initializer> initializer; mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}}; - Storage::Info::CommonTypeCache<ProjectStorageInterface> commonTypeCache_{*this}; + Storage::Info::CommonTypeCache<ProjectStorageType> commonTypeCache_{*this}; QVarLengthArray<ProjectStorageObserver *, 24> observers; - ReadWriteStatement<1, 2> insertTypeStatement{ - "INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database}; - WriteStatement<5> updatePrototypeAndExtensionStatement{ - "UPDATE types SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 " - "WHERE typeId=?1 AND (prototypeId IS NOT ?2 OR extensionId IS NOT ?3 AND prototypeId " - "IS NOT ?4 OR extensionNameId IS NOT ?5)", - database}; - mutable ReadStatement<1, 1> selectTypeIdByExportedNameStatement{ - "SELECT typeId FROM exportedTypeNames WHERE name=?1", database}; - mutable ReadStatement<1, 2> selectTypeIdByModuleIdAndExportedNameStatement{ - "SELECT typeId FROM exportedTypeNames " - "WHERE moduleId=?1 AND name=?2 " - "ORDER BY majorVersion DESC, minorVersion DESC " - "LIMIT 1", - database}; - mutable ReadStatement<1, 3> selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement{ - "SELECT typeId FROM exportedTypeNames " - "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3" - "ORDER BY minorVersion DESC " - "LIMIT 1", - database}; - mutable ReadStatement<1, 4> selectTypeIdByModuleIdAndExportedNameAndVersionStatement{ - "SELECT typeId FROM exportedTypeNames " - "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3 AND minorVersion<=?4" - "ORDER BY minorVersion DESC " - "LIMIT 1", - database}; - mutable ReadStatement<1, 2> selectPrototypeIdStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId) AS (" - " VALUES(?1) " - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN typeSelection " - " USING(typeId))" - "SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1", - database}; - mutable ReadStatement<1, 2> selectPropertyDeclarationIdByTypeIdAndNameStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId, level) AS (" - " VALUES(?1, 0) " - " UNION ALL " - " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN " - " typeSelection USING(typeId)) " - "SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) " - " WHERE name=?2 ORDER BY level LIMIT 1", - database}; - mutable ReadStatement<3, 2> selectPropertyDeclarationByTypeIdAndNameStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId, level) AS (" - " VALUES(?1, 0) " - " UNION ALL " - " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN " - " typeSelection USING(typeId))" - "SELECT propertyTypeId, propertyDeclarationId, propertyTraits " - " FROM propertyDeclarations JOIN typeSelection USING(typeId) " - " WHERE name=?2 ORDER BY level LIMIT 1", - database}; - mutable ReadStatement<1, 1> selectPrototypeIdsInOrderStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId, level) AS (" - " VALUES(?1, 0) " - " UNION ALL " - " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN " - " typeSelection USING(typeId) WHERE prototypeId IS NOT NULL) " - "SELECT typeId FROM typeSelection ORDER BY level DESC", - database}; - mutable ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{ - "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database}; - mutable ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{ - "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database}; - mutable ReadStatement<2> selectAllSourceContextsStatement{ - "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database}; - WriteStatement<1> insertIntoSourceContextsStatement{ - "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database}; - mutable ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{ - "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database}; - mutable ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{ - "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database}; - mutable ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{ - "SELECT sourceContextId FROM sources WHERE sourceId = ?", database}; - WriteStatement<2> insertIntoSourcesStatement{ - "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; - mutable ReadStatement<3> selectAllSourcesStatement{ - "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; - mutable ReadStatement<8, 1> selectTypeByTypeIdStatement{ - "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " - "pd.name " - "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON " - "defaultPropertyId=propertyDeclarationId " - "WHERE t.typeId=?", - database}; - mutable ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{ - "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " - "exportedTypeNames WHERE typeId=?", - database}; - mutable ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{ - "SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) " - "FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND " - "sourceId=?2", - database}; - mutable ReadStatement<8> selectTypesStatement{ - "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, " - "pd.name " - "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON " - "defaultPropertyId=propertyDeclarationId", - database}; - WriteStatement<2> updateTypeTraitStatement{"UPDATE types SET traits = ?2 WHERE typeId=?1", - database}; - WriteStatement<2> updateTypeAnnotationTraitStatement{ - "UPDATE types SET annotationTraits = ?2 WHERE typeId=?1", database}; - ReadStatement<1, 2> selectNotUpdatedTypesInSourcesStatement{ - "SELECT DISTINCT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN " - "carray(?2))", - database}; - WriteStatement<1> deleteTypeNamesByTypeIdStatement{ - "DELETE FROM exportedTypeNames WHERE typeId=?", database}; - WriteStatement<1> deleteEnumerationDeclarationByTypeIdStatement{ - "DELETE FROM enumerationDeclarations WHERE typeId=?", database}; - WriteStatement<1> deletePropertyDeclarationByTypeIdStatement{ - "DELETE FROM propertyDeclarations WHERE typeId=?", database}; - WriteStatement<1> deleteFunctionDeclarationByTypeIdStatement{ - "DELETE FROM functionDeclarations WHERE typeId=?", database}; - WriteStatement<1> deleteSignalDeclarationByTypeIdStatement{ - "DELETE FROM signalDeclarations WHERE typeId=?", database}; - WriteStatement<1> deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; - mutable ReadStatement<4, 1> selectPropertyDeclarationsByTypeIdStatement{ - "SELECT name, propertyTypeId, propertyTraits, (SELECT name FROM " - "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM " - "propertyDeclarations AS pd WHERE typeId=?", - database}; - ReadStatement<6, 1> selectPropertyDeclarationsForTypeIdStatement{ - "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, " - "propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " - "WHERE typeId=? ORDER BY name", - database}; - ReadWriteStatement<1, 5> insertPropertyDeclarationStatement{ - "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, " - "propertyImportedTypeNameId, aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5, NULL) " - "RETURNING propertyDeclarationId", - database}; - WriteStatement<4> updatePropertyDeclarationStatement{ - "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " - "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=NULL WHERE " - "propertyDeclarationId=?1", - database}; - WriteStatement<3> updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{ - "WITH RECURSIVE " - " properties(aliasPropertyDeclarationId) AS ( " - " SELECT propertyDeclarationId FROM propertyDeclarations WHERE " - " aliasPropertyDeclarationId=?1 " - " UNION ALL " - " SELECT pd.propertyDeclarationId FROM " - " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) " - "UPDATE propertyDeclarations AS pd " - "SET propertyTypeId=?2, propertyTraits=?3 " - "FROM properties AS p " - "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", - database}; - WriteStatement<1> updatePropertyAliasDeclarationRecursivelyStatement{ - "WITH RECURSIVE " - " propertyValues(propertyTypeId, propertyTraits) AS (" - " SELECT propertyTypeId, propertyTraits FROM propertyDeclarations " - " WHERE propertyDeclarationId=?1), " - " properties(aliasPropertyDeclarationId) AS ( " - " SELECT propertyDeclarationId FROM propertyDeclarations WHERE " - " aliasPropertyDeclarationId=?1 " - " UNION ALL " - " SELECT pd.propertyDeclarationId FROM " - " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) " - "UPDATE propertyDeclarations AS pd " - "SET propertyTypeId=pv.propertyTypeId, propertyTraits=pv.propertyTraits " - "FROM properties AS p, propertyValues AS pv " - "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", - database}; - WriteStatement<1> deletePropertyDeclarationStatement{ - "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; - ReadStatement<3, 1> selectPropertyDeclarationsWithAliasForTypeIdStatement{ - "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " - "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name", - database}; - WriteStatement<5> updatePropertyDeclarationWithAliasAndTypeStatement{ - "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " - "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=?5 WHERE " - "propertyDeclarationId=?1", - database}; - ReadWriteStatement<1, 2> insertAliasPropertyDeclarationStatement{ - "INSERT INTO propertyDeclarations(typeId, name) VALUES(?1, ?2) RETURNING " - "propertyDeclarationId", - database}; - mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{ - "SELECT name, returnTypeName, signature, functionDeclarationId FROM " - "functionDeclarations WHERE typeId=? ORDER BY name, signature", - database}; - mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{ - "SELECT name, returnTypeName, functionDeclarationId FROM " - "functionDeclarations WHERE typeId=? ORDER BY name", - database}; - mutable ReadStatement<3, 1> selectFunctionParameterDeclarationsStatement{ - "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " - "json_extract(json_each.value, '$.tr') FROM functionDeclarations, " - "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?", - database}; - WriteStatement<4> insertFunctionDeclarationStatement{ - "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, " - "?3, ?4)", - database}; - WriteStatement<2> updateFunctionDeclarationStatement{ - "UPDATE functionDeclarations SET returnTypeName=?2 WHERE functionDeclarationId=?1", database}; - WriteStatement<1> deleteFunctionDeclarationStatement{ - "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database}; - mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{ - "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER " - "BY name, signature", - database}; - mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{ - "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name", - database}; - mutable ReadStatement<3, 1> selectSignalParameterDeclarationsStatement{ - "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " - "json_extract(json_each.value, '$.tr') FROM signalDeclarations, " - "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?", - database}; - WriteStatement<3> insertSignalDeclarationStatement{ - "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database}; - WriteStatement<2> updateSignalDeclarationStatement{ - "UPDATE signalDeclarations SET signature=?2 WHERE signalDeclarationId=?1", database}; - WriteStatement<1> deleteSignalDeclarationStatement{ - "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database}; - mutable ReadStatement<3, 1> selectEnumerationDeclarationsForTypeIdStatement{ - "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM " - "enumerationDeclarations WHERE typeId=? ORDER BY name", - database}; - mutable ReadStatement<2, 1> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{ - "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER " - "BY name", - database}; - mutable ReadStatement<3, 1> selectEnumeratorDeclarationStatement{ - "SELECT json_each.key, json_each.value, json_each.type!='null' FROM " - "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE " - "enumerationDeclarationId=?", - database}; - WriteStatement<3> insertEnumerationDeclarationStatement{ - "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, " - "?3)", - database}; - WriteStatement<2> updateEnumerationDeclarationStatement{ - "UPDATE enumerationDeclarations SET enumeratorDeclarations=?2 WHERE " - "enumerationDeclarationId=?1", - database}; - WriteStatement<1> deleteEnumerationDeclarationStatement{ - "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database}; - mutable ReadStatement<1, 1> selectModuleIdByNameStatement{ - "SELECT moduleId FROM modules WHERE name=? LIMIT 1", database}; - mutable ReadWriteStatement<1, 1> insertModuleNameStatement{ - "INSERT INTO modules(name) VALUES(?1) RETURNING moduleId", database}; - mutable ReadStatement<1, 1> selectModuleNameStatement{ - "SELECT name FROM modules WHERE moduleId =?1", database}; - mutable ReadStatement<2> selectAllModulesStatement{"SELECT name, moduleId FROM modules", database}; - mutable ReadStatement<1, 2> selectTypeIdBySourceIdAndNameStatement{ - "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database}; - mutable ReadStatement<1, 3> selectTypeIdByModuleIdsAndExportedNameStatement{ - "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND " - "name=?3", - database}; - mutable ReadStatement<4> selectAllDocumentImportForSourceIdStatement{ - "SELECT moduleId, majorVersion, minorVersion, sourceId " - "FROM documentImports ", - database}; - mutable ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{ - "SELECT importId, sourceId, moduleId, majorVersion, minorVersion " - "FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, " - "moduleId, majorVersion, minorVersion", - database}; - ReadWriteStatement<1, 5> insertDocumentImportWithoutVersionStatement{ - "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, " - "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING importId", - database}; - ReadWriteStatement<1, 6> insertDocumentImportWithMajorVersionStatement{ - "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, " - "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6) RETURNING importId", - database}; - ReadWriteStatement<1, 7> insertDocumentImportWithVersionStatement{ - "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, " - "minorVersion, parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) RETURNING " - "importId", - database}; - WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1", - database}; - WriteStatement<2> deleteDocumentImportsWithParentImportIdStatement{ - "DELETE FROM documentImports WHERE sourceId=?1 AND parentImportId=?2", database}; - WriteStatement<1> deleteDocumentImportsWithSourceIdsStatement{ - "DELETE FROM documentImports WHERE sourceId IN carray(?1)", database}; - ReadStatement<1, 2> selectPropertyDeclarationIdPrototypeChainDownStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId, level) AS (" - " SELECT prototypeId, 0 FROM types WHERE typeId=?1 AND prototypeId IS NOT NULL" - " UNION ALL " - " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN " - " typeSelection USING(typeId))" - "SELECT propertyDeclarationId FROM typeSelection JOIN propertyDeclarations " - " USING(typeId) WHERE name=?2 ORDER BY level LIMIT 1", - database}; - WriteStatement<2> updateAliasIdPropertyDeclarationStatement{ - "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2 WHERE " - "aliasPropertyDeclarationId=?1", - database}; - WriteStatement<2> updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{ - "UPDATE propertyDeclarations SET propertyTypeId=new.propertyTypeId, " - "propertyTraits=new.propertyTraits, aliasPropertyDeclarationId=?1 FROM (SELECT " - "propertyTypeId, propertyTraits FROM propertyDeclarations WHERE propertyDeclarationId=?1) " - "AS new WHERE aliasPropertyDeclarationId=?2", - database}; - WriteStatement<1> updateAliasPropertyDeclarationToNullStatement{ - "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL, propertyTypeId=NULL, " - "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT " - "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)", - database}; - ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ - "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " - "alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId FROM " - "propertyDeclarations AS alias JOIN propertyDeclarations AS target ON " - "alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR " - "alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId WHERE " - "alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN " - "(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) " - "WHERE typeId=?1)", - database}; - ReadStatement<3, 1> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{ - "WITH RECURSIVE " - " properties(propertyDeclarationId, propertyImportedTypeNameId, typeId, " - " aliasPropertyDeclarationId) AS (" - " SELECT propertyDeclarationId, propertyImportedTypeNameId, typeId, " - " aliasPropertyDeclarationId FROM propertyDeclarations WHERE " - " aliasPropertyDeclarationId=?1" - " UNION ALL " - " SELECT pd.propertyDeclarationId, pd.propertyImportedTypeNameId, pd.typeId, " - " pd.aliasPropertyDeclarationId FROM propertyDeclarations AS pd JOIN properties AS " - " p ON pd.aliasPropertyDeclarationId=p.propertyDeclarationId)" - "SELECT propertyDeclarationId, propertyImportedTypeNameId, aliasPropertyDeclarationId " - " FROM properties", - database}; - ReadWriteStatement<3, 1> updatesPropertyDeclarationPropertyTypeToNullStatement{ - "UPDATE propertyDeclarations SET propertyTypeId=NULL WHERE propertyTypeId=?1 AND " - "aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, " - "propertyImportedTypeNameId", - database}; - mutable ReadStatement<1, 1> selectPropertyNameStatement{ - "SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; - WriteStatement<2> updatePropertyDeclarationTypeStatement{ - "UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database}; - ReadWriteStatement<2, 1> updatePrototypeIdToNullStatement{ - "UPDATE types SET prototypeId=NULL WHERE prototypeId=?1 RETURNING " - "typeId, prototypeNameId", - database}; - ReadWriteStatement<2, 1> updateExtensionIdToNullStatement{ - "UPDATE types SET extensionId=NULL WHERE extensionId=?1 RETURNING " - "typeId, extensionNameId", - database}; - WriteStatement<2> updateTypePrototypeStatement{ - "UPDATE types SET prototypeId=?2 WHERE typeId=?1", database}; - WriteStatement<2> updateTypeExtensionStatement{ - "UPDATE types SET extensionId=?2 WHERE typeId=?1", database}; - mutable ReadStatement<1, 1> selectTypeIdsForPrototypeChainIdStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " prototypes(typeId) AS (" - " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?" - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN " - " prototypes USING(typeId)) " - "SELECT typeId FROM prototypes", - database}; - WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ - "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, " - "propertyImportedTypeNameId=?3 WHERE propertyDeclarationId=?1 AND " - "(aliasPropertyDeclarationId IS NOT ?2 OR propertyImportedTypeNameId IS NOT ?3)", - database}; - WriteStatement<1> updatetPropertiesDeclarationValuesOfAliasStatement{ - "WITH RECURSIVE " - " properties(propertyDeclarationId, propertyTypeId, propertyTraits) AS ( " - " SELECT aliasPropertyDeclarationId, propertyTypeId, propertyTraits FROM " - " propertyDeclarations WHERE propertyDeclarationId=?1 " - " UNION ALL " - " SELECT pd.aliasPropertyDeclarationId, pd.propertyTypeId, pd.propertyTraits FROM " - " propertyDeclarations AS pd JOIN properties USING(propertyDeclarationId)) " - "UPDATE propertyDeclarations AS pd SET propertyTypeId=p.propertyTypeId, " - " propertyTraits=p.propertyTraits " - "FROM properties AS p " - "WHERE pd.propertyDeclarationId=?1 AND p.propertyDeclarationId IS NULL AND " - " (pd.propertyTypeId IS NOT p.propertyTypeId OR pd.propertyTraits IS NOT " - " p.propertyTraits)", - database}; - WriteStatement<1> updatePropertyDeclarationAliasIdToNullStatement{ - "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL WHERE " - "propertyDeclarationId=?1", - database}; - mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForAliasChainStatement{ - "WITH RECURSIVE " - " properties(propertyDeclarationId) AS ( " - " SELECT aliasPropertyDeclarationId FROM propertyDeclarations WHERE " - " propertyDeclarationId=?1 " - " UNION ALL " - " SELECT aliasPropertyDeclarationId FROM propertyDeclarations JOIN properties " - " USING(propertyDeclarationId)) " - "SELECT propertyDeclarationId FROM properties", - database}; - mutable ReadStatement<3> selectAllFileStatusesStatement{ - "SELECT sourceId, size, lastModified FROM fileStatuses ORDER BY sourceId", database}; - mutable ReadStatement<3, 1> selectFileStatusesForSourceIdsStatement{ - "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId IN carray(?1) ORDER " - "BY sourceId", - database}; - mutable ReadStatement<3, 1> selectFileStatusesForSourceIdStatement{ - "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId=?1 ORDER BY sourceId", - database}; - WriteStatement<3> insertFileStatusStatement{ - "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES(?1, ?2, ?3)", database}; - WriteStatement<1> deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1", - database}; - WriteStatement<3> updateFileStatusStatement{ - "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database}; - ReadStatement<1, 1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?", - database}; - mutable ReadStatement<1, 3> selectImportedTypeNameIdStatement{ - "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 " - "AND name=?3 LIMIT 1", - database}; - mutable ReadWriteStatement<1, 3> insertImportedTypeNameIdStatement{ - "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) " - "RETURNING importedTypeNameId", - database}; - mutable ReadStatement<1, 2> selectImportIdBySourceIdAndModuleIdStatement{ - "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion " - "IS NULL AND minorVersion IS NULL LIMIT 1", - database}; - mutable ReadStatement<1, 3> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ - "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " - "majorVersion=?3 AND minorVersion IS NULL LIMIT 1", - database}; - mutable ReadStatement<1, 4> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ - "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " - "majorVersion=?3 AND minorVersion=?4 LIMIT 1", - database}; - mutable ReadStatement<1, 1> selectKindFromImportedTypeNamesStatement{ - "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; - mutable ReadStatement<1, 1> selectNameFromImportedTypeNamesStatement{ - "SELECT name FROM importedTypeNames WHERE importedTypeNameId=?1", database}; - mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ - "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " - "importOrSourceId=di.importId JOIN documentImports AS di2 ON di.sourceId=di2.sourceId AND " - "di.moduleId=di2.sourceModuleId " - "JOIN exportedTypeNames AS etn ON di2.moduleId=etn.moduleId WHERE " - "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND " - "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " - "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " - "etn.minorVersion DESC NULLS FIRST LIMIT 1", - database}; - mutable ReadStatement<1, 1> selectTypeIdForImportedTypeNameNamesStatement{ - "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " - "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " - "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND " - "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS " - "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY di.kind, etn.majorVersion DESC " - "NULLS FIRST, etn.minorVersion DESC NULLS FIRST LIMIT 1", - database}; - WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database}; - WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; - mutable ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{ - "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " - "exportedTypeNameId FROM exportedTypeNames WHERE typeId in carray(?1) ORDER BY moduleId, " - "name, majorVersion, minorVersion", - database}; - WriteStatement<5> insertExportedTypeNamesWithVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4, ?5)", - database}; - WriteStatement<4> insertExportedTypeNamesWithMajorVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) " - "VALUES(?1, ?2, ?3, ?4)", - database}; - WriteStatement<3> insertExportedTypeNamesWithoutVersionStatement{ - "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database}; - WriteStatement<1> deleteExportedTypeNameStatement{ - "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database}; - WriteStatement<2> updateExportedTypeNameTypeIdStatement{ - "UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database}; - mutable ReadStatement<4, 1> selectProjectDatasForSourceIdsStatement{ - "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " - "projectSourceId IN carray(?1) ORDER BY projectSourceId, sourceId", - database}; - WriteStatement<4> insertProjectDataStatement{ - "INSERT INTO projectDatas(projectSourceId, sourceId, " - "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)", - database}; - WriteStatement<2> deleteProjectDataStatement{ - "DELETE FROM projectDatas WHERE projectSourceId=?1 AND sourceId=?2", database}; - WriteStatement<4> updateProjectDataStatement{ - "UPDATE projectDatas SET moduleId=?3, fileType=?4 WHERE projectSourceId=?1 AND sourceId=?2", - database}; - mutable ReadStatement<4, 1> selectProjectDatasForSourceIdStatement{ - "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " - "projectSourceId=?1", - database}; - mutable ReadStatement<4, 1> selectProjectDataForSourceIdStatement{ - "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " - "sourceId=?1 LIMIT 1", - database}; - mutable ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{ - "SELECT typeId FROM types WHERE sourceId IN carray(?1)", database}; - mutable ReadStatement<6, 1> selectModuleExportedImportsForSourceIdStatement{ - "SELECT moduleExportedImportId, moduleId, exportedModuleId, ifnull(majorVersion, -1), " - "ifnull(minorVersion, -1), isAutoVersion FROM moduleExportedImports WHERE moduleId IN " - "carray(?1) ORDER BY moduleId, exportedModuleId", - database}; - WriteStatement<3> insertModuleExportedImportWithoutVersionStatement{ - "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion) " - "VALUES (?1, ?2, ?3)", - database}; - WriteStatement<4> insertModuleExportedImportWithMajorVersionStatement{ - "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, " - "majorVersion) VALUES (?1, ?2, ?3, ?4)", - database}; - WriteStatement<5> insertModuleExportedImportWithVersionStatement{ - "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, " - "majorVersion, minorVersion) VALUES (?1, ?2, ?3, ?4, ?5)", - database}; - WriteStatement<1> deleteModuleExportedImportStatement{ - "DELETE FROM moduleExportedImports WHERE moduleExportedImportId=?1", database}; - mutable ReadStatement<3, 3> selectModuleExportedImportsForModuleIdStatement{ - "WITH RECURSIVE " - " imports(moduleId, majorVersion, minorVersion, moduleExportedImportId) AS ( " - " SELECT exportedModuleId, " - " iif(isAutoVersion=1, ?2, majorVersion), " - " iif(isAutoVersion=1, ?3, minorVersion), " - " moduleExportedImportId " - " FROM moduleExportedImports WHERE moduleId=?1 " - " UNION ALL " - " SELECT exportedModuleId, " - " iif(mei.isAutoVersion=1, i.majorVersion, mei.majorVersion), " - " iif(mei.isAutoVersion=1, i.minorVersion, mei.minorVersion), " - " mei.moduleExportedImportId " - " FROM moduleExportedImports AS mei JOIN imports AS i USING(moduleId)) " - "SELECT DISTINCT moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " - "FROM imports", - database}; - mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForTypeStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeChain(typeId) AS (" - " VALUES(?1)" - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " - " USING(typeId))" - "SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations " - " USING(typeId) ORDER BY propertyDeclarationId", - database}; - mutable ReadStatement<1, 1> selectLocalPropertyDeclarationIdsForTypeStatement{ - "SELECT propertyDeclarationId " - "FROM propertyDeclarations " - "WHERE typeId=? " - "ORDER BY propertyDeclarationId", - database}; - mutable ReadStatement<1, 2> selectPropertyDeclarationIdForTypeAndPropertyNameStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeChain(typeId, level) AS (" - " VALUES(?1, 0)" - " UNION ALL " - " SELECT prototypeId, typeChain.level + 1 FROM all_prototype_and_extension JOIN " - " typeChain USING(typeId))" - "SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations " - " USING(typeId) WHERE name=?2 ORDER BY level LIMIT 1", - database}; - mutable ReadStatement<1, 2> selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement{ - "SELECT propertyDeclarationId " - "FROM propertyDeclarations " - "WHERE typeId=?1 AND name=?2 LIMIT 1", - database}; - mutable ReadStatement<4, 1> selectPropertyDeclarationForPropertyDeclarationIdStatement{ - "SELECT typeId, name, propertyTraits, propertyTypeId " - "FROM propertyDeclarations " - "WHERE propertyDeclarationId=?1 LIMIT 1", - database}; - mutable ReadStatement<1, 1> selectSignalDeclarationNamesForTypeStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeChain(typeId) AS (" - " VALUES(?1)" - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " - " USING(typeId)) " - "SELECT name FROM typeChain JOIN signalDeclarations " - " USING(typeId) ORDER BY name", - database}; - mutable ReadStatement<1, 1> selectFuncionDeclarationNamesForTypeStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeChain(typeId) AS (" - " VALUES(?1)" - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " - " USING(typeId))" - "SELECT name FROM typeChain JOIN functionDeclarations " - " USING(typeId) ORDER BY name", - database}; - mutable ReadStatement<2> selectTypesWithDefaultPropertyStatement{ - "SELECT typeId, defaultPropertyId FROM types ORDER BY typeId", database}; - WriteStatement<2> updateDefaultPropertyIdStatement{ - "UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database}; - WriteStatement<1> updateDefaultPropertyIdToNullStatement{ - "UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database}; - mutable ReadStatement<4, 1> selectInfoTypeByTypeIdStatement{ - "SELECT defaultPropertyId, sourceId, traits, annotationTraits FROM types WHERE typeId=?", - database}; - mutable ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " prototypes(typeId, level) AS (" - " SELECT prototypeId, 0 FROM all_prototype_and_extension WHERE typeId=?" - " UNION ALL " - " SELECT prototypeId, p.level+1 FROM all_prototype_and_extension JOIN " - " prototypes AS p USING(typeId)) " - "SELECT typeId FROM prototypes ORDER BY level", - database}; - mutable ReadStatement<1, 1> selectPrototypeAndSelfIdsForTypeIdInOrderStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeChain(typeId, level) AS (" - " VALUES(?1, 0)" - " UNION ALL " - " SELECT prototypeId, tc.level+1 FROM all_prototype_and_extension JOIN " - " typeChain AS tc USING(typeId)) " - "SELECT typeId FROM typeChain ORDER BY level", - database}; - mutable ReadStatement<1, 1> selectPrototypeIdsStatement{ - "WITH RECURSIVE " - " all_prototype_and_extension(typeId, prototypeId) AS (" - " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" - " UNION ALL " - " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," - " typeSelection(typeId) AS (" - " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?1 " - " UNION ALL " - " SELECT prototypeId FROM all_prototype_and_extension JOIN typeSelection " - " USING(typeId))" - "SELECT typeId FROM typeSelection", - database}; - WriteStatement<2> upsertPropertyEditorPathIdStatement{ - "INSERT INTO propertyEditorPaths(typeId, pathSourceId) VALUES(?1, ?2) ON CONFLICT DO " - "UPDATE SET pathSourceId=excluded.pathSourceId WHERE pathSourceId IS NOT " - "excluded.pathSourceId", - database}; - mutable ReadStatement<1, 1> selectPropertyEditorPathIdStatement{ - "SELECT pathSourceId FROM propertyEditorPaths WHERE typeId=?", database}; - mutable ReadStatement<3, 1> selectPropertyEditorPathsForForSourceIdsStatement{ - "SELECT typeId, pathSourceId, directoryId " - "FROM propertyEditorPaths " - "WHERE directoryId IN carray(?1) " - "ORDER BY typeId", - database}; - WriteStatement<3> insertPropertyEditorPathStatement{ - "INSERT INTO propertyEditorPaths(typeId, pathSourceId, directoryId) VALUES (?1, ?2, ?3)", - database}; - WriteStatement<3> updatePropertyEditorPathsStatement{"UPDATE propertyEditorPaths " - "SET pathSourceId=?2, directoryId=?3 " - "WHERE typeId=?1", - database}; - WriteStatement<1> deletePropertyEditorPathStatement{ - "DELETE FROM propertyEditorPaths WHERE typeId=?1", database}; - mutable ReadStatement<4, 1> selectTypeAnnotationsForSourceIdsStatement{ - "SELECT typeId, iconPath, itemLibrary, hints FROM typeAnnotations WHERE " - "sourceId IN carray(?1) ORDER BY typeId", - database}; - WriteStatement<5> insertTypeAnnotationStatement{ - "INSERT INTO typeAnnotations(typeId, sourceId, iconPath, itemLibrary, hints) VALUES(?1, " - "?2, ?3, ?4, ?5)", - database}; - WriteStatement<4> updateTypeAnnotationStatement{ - "UPDATE typeAnnotations SET iconPath=?2, itemLibrary=?3, hints=?4 WHERE typeId=?1", database}; - WriteStatement<1> deleteTypeAnnotationStatement{"DELETE FROM typeAnnotations WHERE typeId=?1", - database}; - mutable ReadStatement<1, 1> selectTypeIconPathStatement{ - "SELECT iconPath FROM typeAnnotations WHERE typeId=?1", database}; - mutable ReadStatement<2, 1> selectTypeHintsStatement{ - "SELECT hints.key, hints.value " - "FROM typeAnnotations, json_each(typeAnnotations.hints) AS hints " - "WHERE typeId=?1", - database}; - mutable ReadStatement<9> selectItemLibraryEntriesStatement{ - "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', " - " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', " - " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " - "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i", - database}; - mutable ReadStatement<9, 1> selectItemLibraryEntriesByTypeIdStatement{ - "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', " - " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', " - " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " - "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i " - "WHERE typeId=?1", - database}; - mutable ReadStatement<9, 1> selectItemLibraryEntriesBySourceIdStatement{ - "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', " - " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', " - " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' " - "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i " - "WHERE typeId IN (SELECT DISTINCT typeId " - " FROM documentImports AS di JOIN exportedTypeNames USING(moduleId) " - " WHERE di.sourceId=?)", - database}; - mutable ReadStatement<3, 1> selectItemLibraryPropertiesStatement{ - "SELECT p.value->>0, p.value->>1, p.value->>2 FROM json_each(?1) AS p", database}; - mutable ReadStatement<1, 1> selectItemLibraryExtraFilePathsStatement{ - "SELECT p.value FROM json_each(?1) AS p", database}; - mutable ReadStatement<1, 1> selectTypeIdsByModuleIdStatement{ - "SELECT DISTINCT typeId FROM exportedTypeNames WHERE moduleId=?", database}; - mutable ReadStatement<1, 1> selectHeirTypeIdsStatement{ - "WITH RECURSIVE " - " typeSelection(typeId) AS (" - " SELECT typeId FROM types WHERE prototypeId=?1 OR extensionId=?1" - " UNION ALL " - " SELECT t.typeId " - " FROM types AS t JOIN typeSelection AS ts " - " WHERE prototypeId=ts.typeId OR extensionId=ts.typeId)" - "SELECT typeId FROM typeSelection", - database}; + std::unique_ptr<Statements> s; }; -extern template class ProjectStorage<Sqlite::Database>; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp new file mode 100644 index 0000000000..a4705f5eec --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "projectstorageerrornotifier.h" + +#include "sourcepathcache.h" + +namespace QmlDesigner { + +void ProjectStorageErrorNotifier::typeNameCannotBeResolved(Utils::SmallStringView typeName, + SourceId sourceId) +{ + qDebug() << "Missing type name: " << typeName + << " in file: " << m_pathCache.sourcePath(sourceId).toStringView(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h new file mode 100644 index 0000000000..2695e93019 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h @@ -0,0 +1,25 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectstorageerrornotifierinterface.h" + +#include <modelfwd.h> + +namespace QmlDesigner { + +class ProjectStorageErrorNotifier final : public ProjectStorageErrorNotifierInterface +{ +public: + ProjectStorageErrorNotifier(PathCacheType &pathCache) + : m_pathCache{pathCache} + {} + + void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) override; + +private: + PathCacheType &m_pathCache; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h new file mode 100644 index 0000000000..8136c9d599 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectstorageids.h" + +#include <utils/smallstringview.h> + +namespace QmlDesigner { + +class ProjectStorageErrorNotifierInterface +{ +public: + ProjectStorageErrorNotifierInterface() = default; + ProjectStorageErrorNotifierInterface(ProjectStorageErrorNotifierInterface &&) = default; + ProjectStorageErrorNotifierInterface &operator=(ProjectStorageErrorNotifierInterface &&) = default; + ProjectStorageErrorNotifierInterface(const ProjectStorageErrorNotifierInterface &) = delete; + ProjectStorageErrorNotifierInterface &operator=(const ProjectStorageErrorNotifierInterface &) = delete; + + virtual void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) = 0; + +protected: + ~ProjectStorageErrorNotifierInterface() = default; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp index efe9bc58f5..a86b78a785 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp @@ -3,87 +3,186 @@ #include "projectstorageexceptions.h" +#include <tracing/qmldesignertracing.h> + namespace QmlDesigner { +using namespace NanotraceHR::Literals; +using NanotraceHR::keyValue; + +namespace { +auto &category() +{ + return ProjectStorageTracing::projectStorageCategory(); +} +} // namespace + +NoSourcePathForInvalidSourceId::NoSourcePathForInvalidSourceId() +{ + category().threadEvent("NoSourcePathForInvalidSourceId"_t); +} + const char *NoSourcePathForInvalidSourceId::what() const noexcept { return "You cannot get a file path for an invalid file path id!"; } +NoSourceContextPathForInvalidSourceContextId::NoSourceContextPathForInvalidSourceContextId() +{ + category().threadEvent("NoSourceContextPathForInvalidSourceContextId"_t); +} + const char *NoSourceContextPathForInvalidSourceContextId::what() const noexcept { return "You cannot get a directory path for an invalid directory path id!"; } +SourceContextIdDoesNotExists::SourceContextIdDoesNotExists() +{ + category().threadEvent("SourceContextIdDoesNotExists"_t); +} + const char *SourceContextIdDoesNotExists::what() const noexcept { return "The source context id does not exist in the database!"; } +SourceIdDoesNotExists::SourceIdDoesNotExists() +{ + category().threadEvent("SourceIdDoesNotExists"_t); +} + const char *SourceIdDoesNotExists::what() const noexcept { return "The source id does not exist in the database!"; } +TypeHasInvalidSourceId::TypeHasInvalidSourceId() +{ + category().threadEvent("TypeHasInvalidSourceId"_t); +} + const char *TypeHasInvalidSourceId::what() const noexcept { return "The source id is invalid!"; } +ModuleDoesNotExists::ModuleDoesNotExists() +{ + category().threadEvent("ModuleDoesNotExists"_t); +} + const char *ModuleDoesNotExists::what() const noexcept { return "The module does not exist!"; } +ModuleAlreadyExists::ModuleAlreadyExists() +{ + category().threadEvent("ModuleAlreadyExists"_t); +} + const char *ModuleAlreadyExists::what() const noexcept { return "The module does already exist!"; } -TypeNameDoesNotExists::TypeNameDoesNotExists(std::string_view errorMessage) - : ProjectStorageErrorWithMessage{"TypeNameDoesNotExists"sv, errorMessage} -{} +TypeNameDoesNotExists::TypeNameDoesNotExists(std::string_view typeName, SourceId sourceId) + : ProjectStorageErrorWithMessage{ + "TypeNameDoesNotExists"sv, + Utils::SmallString::join( + {"type: ", typeName, ", source id: ", Utils::SmallString::number(sourceId.internalId())})} +{ + category().threadEvent("TypeNameDoesNotExists"_t, + keyValue("type name", typeName), + keyValue("source id", sourceId)); +} + +PropertyNameDoesNotExists::PropertyNameDoesNotExists() +{ + category().threadEvent("PropertyNameDoesNotExists"_t); +} const char *PropertyNameDoesNotExists::what() const noexcept { return "The property name does not exist!"; } +PrototypeChainCycle::PrototypeChainCycle() +{ + category().threadEvent("PrototypeChainCycle"_t); +} + const char *PrototypeChainCycle::what() const noexcept { return "There is a prototype chain cycle!"; } +AliasChainCycle::AliasChainCycle() +{ + category().threadEvent("AliasChainCycle"_t); +} + const char *AliasChainCycle::what() const noexcept { return "There is a prototype chain cycle!"; } +CannotParseQmlTypesFile::CannotParseQmlTypesFile() +{ + category().threadEvent("CannotParseQmlTypesFile"_t); +} + const char *CannotParseQmlTypesFile::what() const noexcept { return "Cannot parse qml types file!"; } +CannotParseQmlDocumentFile::CannotParseQmlDocumentFile() +{ + category().threadEvent("CannotParseQmlDocumentFile"_t); +} + const char *CannotParseQmlDocumentFile::what() const noexcept { return "Cannot parse qml types file!"; } -const char *ProjectDataHasInvalidProjectSourceId::what() const noexcept +DirectoryInfoHasInvalidProjectSourceId::DirectoryInfoHasInvalidProjectSourceId() +{ + category().threadEvent("DirectoryInfoHasInvalidProjectSourceId"_t); +} + +const char *DirectoryInfoHasInvalidProjectSourceId::what() const noexcept { return "The project source id is invalid!"; } -const char *ProjectDataHasInvalidSourceId::what() const noexcept +DirectoryInfoHasInvalidSourceId::DirectoryInfoHasInvalidSourceId() +{ + category().threadEvent("DirectoryInfoHasInvalidSourceId"_t); +} + +const char *DirectoryInfoHasInvalidSourceId::what() const noexcept { return "The source id is invalid!"; } -const char *ProjectDataHasInvalidModuleId::what() const noexcept +DirectoryInfoHasInvalidModuleId::DirectoryInfoHasInvalidModuleId() +{ + category().threadEvent("DirectoryInfoHasInvalidModuleId"_t); +} + +const char *DirectoryInfoHasInvalidModuleId::what() const noexcept { return "The module id is invalid!"; } +FileStatusHasInvalidSourceId::FileStatusHasInvalidSourceId() +{ + category().threadEvent("FileStatusHasInvalidSourceId"_t); +} + const char *FileStatusHasInvalidSourceId::what() const noexcept { return "The source id in file status is invalid!"; @@ -110,7 +209,14 @@ const char *ProjectStorageErrorWithMessage::what() const noexcept ExportedTypeCannotBeInserted::ExportedTypeCannotBeInserted(std::string_view errorMessage) : ProjectStorageErrorWithMessage{"ExportedTypeCannotBeInserted"sv, errorMessage} -{} +{ + category().threadEvent("ExportedTypeCannotBeInserted"_t, keyValue("error message", errorMessage)); +} + +TypeAnnotationHasInvalidSourceId::TypeAnnotationHasInvalidSourceId() +{ + category().threadEvent("TypeAnnotationHasInvalidSourceId"_t); +} const char *TypeAnnotationHasInvalidSourceId::what() const noexcept { diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h index 412dd4a9ff..f4f78f714b 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h @@ -5,6 +5,8 @@ #include "../include/qmldesignercorelib_global.h" +#include "projectstorageids.h" + #include <exception> namespace QmlDesigner { @@ -13,15 +15,19 @@ using namespace std::literals::string_view_literals; class QMLDESIGNERCORE_EXPORT ProjectStorageError : public std::exception { +protected: + ProjectStorageError() = default; + public: const char *what() const noexcept override; }; class ProjectStorageErrorWithMessage : public ProjectStorageError { -public: +protected: ProjectStorageErrorWithMessage(std::string_view error, std::string_view errorMessage); +public: const char *what() const noexcept override; public: @@ -31,42 +37,49 @@ public: class QMLDESIGNERCORE_EXPORT NoSourcePathForInvalidSourceId : public ProjectStorageError { public: + NoSourcePathForInvalidSourceId(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : public ProjectStorageError { public: + NoSourceContextPathForInvalidSourceContextId(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : public ProjectStorageError { public: + SourceContextIdDoesNotExists(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : public ProjectStorageError { public: + SourceIdDoesNotExists(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT TypeHasInvalidSourceId : public ProjectStorageError { public: + TypeHasInvalidSourceId(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT ModuleDoesNotExists : public ProjectStorageError { public: + ModuleDoesNotExists(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT ModuleAlreadyExists : public ProjectStorageError { public: + ModuleAlreadyExists(); const char *what() const noexcept override; }; @@ -79,66 +92,76 @@ public: class QMLDESIGNERCORE_EXPORT TypeNameDoesNotExists : public ProjectStorageErrorWithMessage { public: - TypeNameDoesNotExists(std::string_view errorMessage); + TypeNameDoesNotExists(std::string_view typeName, SourceId sourceId = SourceId{}); }; class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : public ProjectStorageError { public: + PropertyNameDoesNotExists(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : public ProjectStorageError { public: + PrototypeChainCycle(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT AliasChainCycle : public ProjectStorageError { public: + AliasChainCycle(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT CannotParseQmlTypesFile : public ProjectStorageError { public: + CannotParseQmlTypesFile(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT CannotParseQmlDocumentFile : public ProjectStorageError { public: + CannotParseQmlDocumentFile(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidProjectSourceId : public ProjectStorageError +class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidProjectSourceId : public ProjectStorageError { public: + DirectoryInfoHasInvalidProjectSourceId(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidSourceId : public ProjectStorageError +class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidSourceId : public ProjectStorageError { public: + DirectoryInfoHasInvalidSourceId(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidModuleId : public ProjectStorageError +class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidModuleId : public ProjectStorageError { public: + DirectoryInfoHasInvalidModuleId(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT FileStatusHasInvalidSourceId : public ProjectStorageError { public: + FileStatusHasInvalidSourceId(); const char *what() const noexcept override; }; class QMLDESIGNERCORE_EXPORT TypeAnnotationHasInvalidSourceId : public ProjectStorageError { public: + TypeAnnotationHasInvalidSourceId(); const char *what() const noexcept override; }; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h index b33c609509..cbb7d4265a 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h @@ -11,7 +11,6 @@ namespace QmlDesigner { class ProjectStorageInterface; class SourcePathCacheInterface; -template<typename Database> class ProjectStorage; template<typename Type> diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h index 427c0ff8d6..1d630344ae 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h @@ -7,6 +7,9 @@ #include <sqlite/sqlitevalue.h> #include <utils/smallstring.h> +#include <utils/utility.h> + +#include <QVarLengthArray> #include <array> #include <tuple> @@ -15,19 +18,57 @@ namespace QmlDesigner { -template<typename Enumeration> -constexpr std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept -{ - static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration"); - return static_cast<std::underlying_type_t<Enumeration>>(enumeration); -} +template<std::size_t size> +using SmallPathStrings = QVarLengthArray<Utils::PathString, size>; enum class FlagIs : unsigned int { False, Set, True }; +template<typename String> +void convertToString(String &string, const FlagIs &flagIs) +{ + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + + if (flagIs == FlagIs::False) + convertToString(string, false); + else if (flagIs == FlagIs::True) + convertToString(string, true); + else + convertToString(string, "is set"); +} + } // namespace QmlDesigner namespace QmlDesigner::Storage { +enum class ModuleKind { QmlLibrary, CppLibrary, PathLibrary }; + +struct Module +{ + Module() = default; + + Module(Utils::SmallStringView name, Storage::ModuleKind kind) + : name{name} + , kind{kind} + {} + + template<typename ModuleType> + Module(const ModuleType &module) + : name{module.name} + , kind{module.kind} + {} + + Utils::PathString name; + Storage::ModuleKind kind = Storage::ModuleKind::QmlLibrary; + + friend bool operator==(const Module &first, const Module &second) + { + return first.name == second.name && first.kind == second.kind; + } + + explicit operator bool() const { return name.size(); } +}; + enum class PropertyDeclarationTraits : int { None = 0, IsReadOnly = 1 << 0, @@ -46,6 +87,18 @@ constexpr bool operator&(PropertyDeclarationTraits first, PropertyDeclarationTra return static_cast<int>(first) & static_cast<int>(second); } +template<typename String> +void convertToString(String &string, const PropertyDeclarationTraits &traits) +{ + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("is read only", traits & PropertyDeclarationTraits::IsReadOnly), + keyValue("is pointer", traits & PropertyDeclarationTraits::IsPointer), + keyValue("is list", traits & PropertyDeclarationTraits::IsList)); + + convertToString(string, dict); +} + enum class TypeTraitsKind : unsigned int { None, Reference, @@ -53,6 +106,25 @@ enum class TypeTraitsKind : unsigned int { Sequence, }; +template<typename String> +void convertToString(String &string, const TypeTraitsKind &kind) +{ + switch (kind) { + case TypeTraitsKind::None: + convertToString(string, "None"); + break; + case TypeTraitsKind::Reference: + convertToString(string, "Reference"); + break; + case TypeTraitsKind::Value: + convertToString(string, "Value"); + break; + case TypeTraitsKind::Sequence: + convertToString(string, "Sequence"); + break; + } +} + struct TypeTraits { constexpr TypeTraits() @@ -100,6 +172,35 @@ struct TypeTraits return first.type == second.type && first.annotation == second.annotation; } + template<typename String> + friend void convertToString(String &string, const TypeTraits &typeTraits) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary( + keyValue("kind", typeTraits.kind), + keyValue("is enum", typeTraits.isEnum), + keyValue("is file component", typeTraits.isFileComponent), + keyValue("is project component", typeTraits.isProjectComponent), + keyValue("is in project module", typeTraits.isInProjectModule), + keyValue("uses custom parser", typeTraits.usesCustomParser), + keyValue("can be container", typeTraits.canBeContainer), + keyValue("force clip", typeTraits.forceClip), + keyValue("does layout children", typeTraits.doesLayoutChildren), + keyValue("can be dropped in form editor", typeTraits.canBeDroppedInFormEditor), + keyValue("can be dropped in navigator", typeTraits.canBeDroppedInNavigator), + keyValue("can be dropped in view 3D", typeTraits.canBeDroppedInView3D), + keyValue("is movable", typeTraits.isMovable), + keyValue("is resizable", typeTraits.isResizable), + keyValue("has form editor item", typeTraits.hasFormEditorItem), + keyValue("is stacked container", typeTraits.isStackedContainer), + keyValue("takes over rendering of children", typeTraits.takesOverRenderingOfChildren), + keyValue("visible in navigator", typeTraits.visibleInNavigator), + keyValue("visible in library", typeTraits.visibleInLibrary)); + + convertToString(string, dict); + } + union { struct { @@ -202,10 +303,22 @@ public: explicit operator bool() const { return major && minor; } + template<typename String> + friend void convertToString(String &string, const Version &version) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("major version", version.major.value), + keyValue("minor version", version.minor.value)); + + convertToString(string, dict); + } + public: VersionNumber major; VersionNumber minor; }; + } // namespace QmlDesigner::Storage namespace QmlDesigner::Storage::Info { @@ -217,6 +330,17 @@ struct TypeHint , expression{expression} {} + template<typename String> + friend void convertToString(String &string, const TypeHint &typeHint) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", typeHint.name), + keyValue("expression", typeHint.expression)); + + convertToString(string, dict); + } + Utils::SmallString name; Utils::PathString expression; }; @@ -231,6 +355,18 @@ struct ItemLibraryProperty , value{value} {} + template<typename String> + friend void convertToString(String &string, const ItemLibraryProperty &property) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", property.name), + keyValue("type", property.type), + keyValue("value", property.value)); + + convertToString(string, dict); + } + Utils::SmallString name; Utils::SmallString type; Sqlite::Value value; @@ -243,6 +379,7 @@ using ToolTipString = Utils::BasicSmallString<94>; struct ItemLibraryEntry { ItemLibraryEntry(TypeId typeId, + Utils::SmallStringView typeName, Utils::SmallStringView name, Utils::SmallStringView iconPath, Utils::SmallStringView category, @@ -250,6 +387,7 @@ struct ItemLibraryEntry Utils::SmallStringView toolTip, Utils::SmallStringView templatePath) : typeId{typeId} + , typeName{typeName} , name{name} , iconPath{iconPath} , category{category} @@ -259,6 +397,7 @@ struct ItemLibraryEntry {} ItemLibraryEntry(TypeId typeId, + Utils::SmallStringView typeName, Utils::SmallStringView name, Utils::SmallStringView iconPath, Utils::SmallStringView category, @@ -266,6 +405,7 @@ struct ItemLibraryEntry Utils::SmallStringView toolTip, ItemLibraryProperties properties) : typeId{typeId} + , typeName{typeName} , name{name} , iconPath{iconPath} , category{category} @@ -274,7 +414,27 @@ struct ItemLibraryEntry , properties{std::move(properties)} {} + template<typename String> + friend void convertToString(String &string, const ItemLibraryEntry &entry) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", entry.typeId), + keyValue("type name", entry.typeName), + keyValue("name", entry.name), + keyValue("icon path", entry.iconPath), + keyValue("category", entry.category), + keyValue("import", entry.import), + keyValue("tool tip", entry.toolTip), + keyValue("template path", entry.templatePath), + keyValue("properties", entry.properties), + keyValue("extra file paths", entry.extraFilePaths)); + + convertToString(string, dict); + } + TypeId typeId; + Utils::SmallString typeName; Utils::SmallString name; Utils::PathString iconPath; Utils::SmallString category; @@ -321,6 +481,18 @@ public: < std::tie(second.moduleId, second.name, second.version); } + template<typename String> + friend void convertToString(String &string, const ExportedTypeName &exportedTypeName) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", exportedTypeName.name), + keyValue("version", exportedTypeName.version), + keyValue("module id", exportedTypeName.moduleId)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; Storage::Version version; @@ -342,6 +514,19 @@ public: , propertyTypeId{propertyTypeId} {} + template<typename String> + friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type id", propertyDeclaration.typeId), + keyValue("name", propertyDeclaration.name), + keyValue("traits", propertyDeclaration.traits), + keyValue("property type id", propertyDeclaration.propertyTypeId)); + + convertToString(string, dict); + } + TypeId typeId; ::Utils::SmallString name; PropertyDeclarationTraits traits; @@ -351,22 +536,26 @@ public: class Type { public: - Type(PropertyDeclarationId defaultPropertyId, - SourceId sourceId, - long long typeTraits, - long long typeAnnotationTraits) - : defaultPropertyId{defaultPropertyId} - , sourceId{sourceId} + Type(SourceId sourceId, long long typeTraits, long long typeAnnotationTraits) + : sourceId{sourceId} , traits{typeTraits, typeAnnotationTraits} {} - Type(PropertyDeclarationId defaultPropertyId, SourceId sourceId, TypeTraits traits) - : defaultPropertyId{defaultPropertyId} - , sourceId{sourceId} + Type(SourceId sourceId, TypeTraits traits) + : sourceId{sourceId} , traits{traits} {} - PropertyDeclarationId defaultPropertyId; + template<typename String> + friend void convertToString(String &string, const Type &type) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("source id", type.sourceId), keyValue("traits", type.traits)); + + convertToString(string, dict); + } + SourceId sourceId; TypeTraits traits; }; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h index 266c6ee7ca..4d840d2a5c 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h @@ -31,7 +31,8 @@ public: virtual void addObserver(ProjectStorageObserver *observer) = 0; virtual void removeObserver(ProjectStorageObserver *observer) = 0; - virtual ModuleId moduleId(::Utils::SmallStringView name) const = 0; + virtual ModuleId moduleId(::Utils::SmallStringView name, Storage::ModuleKind kind) const = 0; + virtual QmlDesigner::Storage::Module module(ModuleId moduleId) const = 0; virtual std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration(PropertyDeclarationId propertyDeclarationId) const = 0; virtual TypeId typeId(ModuleId moduleId, @@ -54,7 +55,10 @@ public: virtual PropertyDeclarationId propertyDeclarationId(TypeId typeId, ::Utils::SmallStringView propertyName) const = 0; + virtual PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const = 0; virtual std::optional<Storage::Info::Type> type(TypeId typeId) const = 0; + virtual SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const = 0; + virtual SmallSourceIds<64> typeAnnotationDirectorySourceIds() const = 0; virtual Utils::PathString typeIconPath(TypeId typeId) const = 0; virtual Storage::Info::TypeHints typeHints(TypeId typeId) const = 0; virtual Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const = 0; @@ -64,9 +68,9 @@ public: virtual std::vector<::Utils::SmallString> functionDeclarationNames(TypeId typeId) const = 0; virtual std::optional<::Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const = 0; - virtual TypeIds prototypeAndSelfIds(TypeId type) const = 0; - virtual TypeIds prototypeIds(TypeId type) const = 0; - virtual TypeIds heirIds(TypeId typeId) const = 0; + virtual SmallTypeIds<16> prototypeAndSelfIds(TypeId type) const = 0; + virtual SmallTypeIds<16> prototypeIds(TypeId type) const = 0; + virtual SmallTypeIds<64> heirIds(TypeId typeId) const = 0; virtual bool isBasedOn(TypeId, TypeId) const = 0; virtual bool isBasedOn(TypeId, TypeId, TypeId) const = 0; virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId) const = 0; @@ -76,16 +80,20 @@ public: virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId) const = 0; virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; - virtual Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0; - virtual std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const = 0; + virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceId sourceId) const = 0; + virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos( + SourceId directorySourceId, Storage::Synchronization::FileType) const + = 0; + virtual std::optional<Storage::Synchronization::DirectoryInfo> fetchDirectoryInfo(SourceId sourceId) const = 0; + virtual SmallSourceIds<32> fetchSubdirectorySourceIds(SourceId directorySourceId) const = 0; virtual SourceId propertyEditorPathId(TypeId typeId) const = 0; - virtual const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const = 0; + virtual const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const = 0; - template<const char *moduleName, const char *typeName> + template<const char *moduleName, const char *typeName, Storage::ModuleKind moduleKind = Storage::ModuleKind::QmlLibrary> TypeId commonTypeId() const { - return commonTypeCache().template typeId<moduleName, typeName>(); + return commonTypeCache().template typeId<moduleName, typeName, moduleKind>(); } template<typename BuiltinType> @@ -104,7 +112,7 @@ protected: ProjectStorageInterface() = default; ~ProjectStorageInterface() = default; - virtual ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const = 0; + virtual ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name, Storage::ModuleKind moduleKind) const = 0; virtual TypeId fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, Utils::SmallStringView name) const = 0; }; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h index a9185d91e8..04f11096bd 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h @@ -12,6 +12,28 @@ namespace QmlDesigner { enum class SourceType : int { Qml, QmlUi, QmlTypes, QmlDir, Directory }; +template<typename String> +void convertToString(String &string, SourceType sourceType) +{ + switch (sourceType) { + case SourceType::Qml: + convertToString(string, "Qml"); + break; + case SourceType::QmlUi: + convertToString(string, "QmlUi"); + break; + case SourceType::QmlTypes: + convertToString(string, "QmlTypes"); + break; + case SourceType::QmlDir: + convertToString(string, "QmlDir"); + break; + case SourceType::Directory: + convertToString(string, "Directory"); + break; + } +} + class ProjectChunkId { public: @@ -46,6 +68,17 @@ public: friend bool operator<(ProjectChunkId first, ProjectPartId second) { return first.id < second; } friend bool operator<(ProjectPartId first, ProjectChunkId second) { return first < second.id; } + + template<typename String> + friend void convertToString(String &string, const ProjectChunkId &id) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("project part id", id.id), + keyValue("source type", id.sourceType)); + + convertToString(string, dict); + } }; using ProjectChunkIds = std::vector<ProjectChunkId>; @@ -67,6 +100,16 @@ public: return first.id == second.id && first.sourceIds == second.sourceIds; } + template<typename String> + friend void convertToString(String &string, const IdPaths &idPaths) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("id", idPaths.id), keyValue("source ids", idPaths.sourceIds)); + + convertToString(string, dict); + } + public: ProjectChunkId id; SourceIds sourceIds; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 18c3931249..1592628af5 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -7,8 +7,10 @@ #include "projectstorageids.h" #include "projectstorageinfotypes.h" +#include <nanotrace/nanotracehr.h> #include <sqlite/sqlitevalue.h> #include <utils/smallstring.h> +#include <utils/utility.h> #include <tuple> #include <variant> @@ -45,6 +47,17 @@ public: < std::tie(second.sourceId, second.moduleId, second.version); } + template<typename String> + friend void convertToString(String &string, const Import &import) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("module id", import.moduleId), + keyValue("source id", import.sourceId), + keyValue("version", import.version)); + convertToString(string, dict); + } + public: Storage::Version version; ModuleId moduleId; @@ -57,11 +70,53 @@ namespace Synchronization { enum class TypeNameKind { Exported = 1, QualifiedExported = 2 }; -enum class FileType : char { QmlTypes, QmlDocument }; +template<typename String> +void convertToString(String &string, const TypeNameKind &kind) +{ + switch (kind) { + case TypeNameKind::Exported: + convertToString(string, "Exported"); + break; + case TypeNameKind::QualifiedExported: + convertToString(string, "QualifiedExported"); + break; + } +} + +enum class FileType : char { QmlTypes, QmlDocument, Directory }; + +template<typename String> +void convertToString(String &string, const FileType &type) +{ + switch (type) { + case FileType::QmlTypes: + convertToString(string, "QmlTypes"); + break; + case FileType::QmlDocument: + convertToString(string, "QmlDocument"); + break; + case FileType::Directory: + convertToString(string, "Directory"); + break; + } +} enum class IsQualified : int { No, Yes }; -inline int operator-(IsQualified first, IsQualified second) +template<typename String> +void convertToString(String &string, const IsQualified &isQualified) +{ + switch (isQualified) { + case IsQualified::No: + convertToString(string, "No"); + break; + case IsQualified::Yes: + convertToString(string, "Yes"); + break; + } +} + +inline int operator-(IsQualified first, const IsQualified &second) { return static_cast<int>(first) - static_cast<int>(second); } @@ -78,6 +133,25 @@ enum class ImportKind : char { ModuleExportedModuleDependency }; +template<typename String> +void convertToString(String &string, const ImportKind &kind) +{ + switch (kind) { + case ImportKind::Import: + convertToString(string, "Import"); + break; + case ImportKind::ModuleDependency: + convertToString(string, "ModuleDependency"); + break; + case ImportKind::ModuleExportedImport: + convertToString(string, "ModuleExportedImport"); + break; + case ImportKind::ModuleExportedModuleDependency: + convertToString(string, "ModuleExportedModuleDependency"); + break; + } +} + class ImportView { public: @@ -97,6 +171,19 @@ public: && first.version == second.version; } + template<typename String> + friend void convertToString(String &string, const ImportView &import) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("import id", import.importId), + keyValue("source id", import.sourceId), + keyValue("module id", import.moduleId), + keyValue("version", import.version)); + + convertToString(string, dict); + } + public: ImportId importId; SourceId sourceId; @@ -106,9 +193,22 @@ public: enum class IsAutoVersion : char { No, Yes }; +template<typename String> +void convertToString(String &string, const IsAutoVersion &isAutoVersion) +{ + switch (isAutoVersion) { + case IsAutoVersion::No: + convertToString(string, "No"); + break; + case IsAutoVersion::Yes: + convertToString(string, "Yes"); + break; + } +} + constexpr bool operator<(IsAutoVersion first, IsAutoVersion second) { - return to_underlying(first) < to_underlying(second); + return Utils::to_underlying(first) < Utils::to_underlying(second); } class ModuleExportedImport @@ -137,6 +237,19 @@ public: < std::tie(second.moduleId, second.exportedModuleId, second.isAutoVersion, second.version); } + template<typename String> + friend void convertToString(String &string, const ModuleExportedImport &import) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("module id", import.moduleId), + keyValue("exported module id", import.exportedModuleId), + keyValue("version", import.version), + keyValue("is auto version", import.isAutoVersion)); + + convertToString(string, dict); + } + public: Storage::Version version; ModuleId moduleId; @@ -171,6 +284,20 @@ public: && first.version == second.version && first.isAutoVersion == second.isAutoVersion; } + template<typename String> + friend void convertToString(String &string, const ModuleExportedImportView &import) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("module exported import id", import.moduleExportedImportId), + keyValue("module id", import.moduleId), + keyValue("exported module id", import.exportedModuleId), + keyValue("version", import.version), + keyValue("is auto version", import.isAutoVersion)); + + convertToString(string, dict); + } + public: ModuleExportedImportId moduleExportedImportId; Storage::Version version; @@ -192,6 +319,16 @@ public: return first.name == second.name; } + template<typename String> + friend void convertToString(String &string, const ImportedType &importedType) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", importedType.name)); + + convertToString(string, dict); + } + public: TypeNameString name; }; @@ -210,6 +347,17 @@ public: return first.name == second.name && first.import == second.import; } + template<typename String> + friend void convertToString(String &string, const QualifiedImportedType &importedType) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", importedType.name), + keyValue("import", importedType.import)); + + convertToString(string, dict); + } + public: TypeNameString name; Import import; @@ -264,6 +412,19 @@ public: < std::tie(second.moduleId, second.name, second.version); } + template<typename String> + friend void convertToString(String &string, const ExportedType &exportedType) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", exportedType.name), + keyValue("module id", exportedType.moduleId), + keyValue("type id", exportedType.typeId), + keyValue("version", exportedType.version)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; Storage::Version version; @@ -295,6 +456,20 @@ public: , exportedTypeNameId{exportedTypeNameId} {} + template<typename String> + friend void convertToString(String &string, const ExportedTypeView &exportedType) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", exportedType.name), + keyValue("module id", exportedType.moduleId), + keyValue("type id", exportedType.typeId), + keyValue("version", exportedType.version), + keyValue("version", exportedType.exportedTypeNameId)); + + convertToString(string, dict); + } + public: ::Utils::SmallStringView name; Storage::Version version; @@ -305,6 +480,43 @@ public: using ImportedTypeName = std::variant<ImportedType, QualifiedImportedType>; +template<typename String> +void convertToString(String &string, const ImportedTypeName &typeName) +{ + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + + struct Dispatcher + { + static const QmlDesigner::Storage::Import &nullImport() + { + static QmlDesigner::Storage::Import import; + + return import; + } + + void operator()(const QmlDesigner::Storage::Synchronization::ImportedType &importedType) const + { + auto dict = dictonary(keyValue("name", importedType.name)); + + convertToString(string, dict); + } + + void operator()( + const QmlDesigner::Storage::Synchronization::QualifiedImportedType &qualifiedImportedType) const + { + auto dict = dictonary(keyValue("name", qualifiedImportedType.name), + keyValue("import", qualifiedImportedType.import)); + + convertToString(string, dict); + } + + String &string; + }; + + std::visit(Dispatcher{string}, typeName); +} + class EnumeratorDeclaration { public: @@ -325,6 +537,18 @@ public: && first.hasValue == second.hasValue; } + template<typename String> + friend void convertToString(String &string, const EnumeratorDeclaration &enumeratorDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", enumeratorDeclaration.name), + keyValue("value", enumeratorDeclaration.value), + keyValue("has value", enumeratorDeclaration.hasValue)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; long long value = 0; @@ -349,6 +573,18 @@ public: && first.enumeratorDeclarations == second.enumeratorDeclarations; } + template<typename String> + friend void convertToString(String &string, const EnumerationDeclaration &enumerationDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", enumerationDeclaration.name), + keyValue("enumerator declarations", + enumerationDeclaration.enumeratorDeclarations)); + + convertToString(string, dict); + } + public: TypeNameString name; EnumeratorDeclarations enumeratorDeclarations; @@ -368,6 +604,20 @@ public: , id{id} {} + template<typename String> + friend void convertToString(String &string, + const EnumerationDeclarationView &enumerationDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", enumerationDeclaration.name), + keyValue("enumerator declarations", + enumerationDeclaration.enumeratorDeclarations), + keyValue("id", enumerationDeclaration.id)); + + convertToString(string, dict); + } + public: ::Utils::SmallStringView name; ::Utils::SmallStringView enumeratorDeclarations; @@ -392,6 +642,18 @@ public: && first.traits == second.traits; } + template<typename String> + friend void convertToString(String &string, const ParameterDeclaration ¶meterDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", parameterDeclaration.name), + keyValue("type name", parameterDeclaration.typeName), + keyValue("traits", parameterDeclaration.traits)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; TypeNameString typeName; @@ -418,6 +680,17 @@ public: return first.name == second.name && first.parameters == second.parameters; } + template<typename String> + friend void convertToString(String &string, const SignalDeclaration &signalDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", signalDeclaration.name), + keyValue("parameters", signalDeclaration.parameters)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; ParameterDeclarations parameters; @@ -437,6 +710,18 @@ public: , id{id} {} + template<typename String> + friend void convertToString(String &string, const SignalDeclarationView &signalDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", signalDeclaration.name), + keyValue("signature", signalDeclaration.signature), + keyValue("id", signalDeclaration.id)); + + convertToString(string, dict); + } + public: ::Utils::SmallStringView name; ::Utils::SmallStringView signature; @@ -467,6 +752,18 @@ public: && first.parameters == second.parameters; } + template<typename String> + friend void convertToString(String &string, const FunctionDeclaration &functionDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", functionDeclaration.name), + keyValue("return type name", functionDeclaration.returnTypeName), + keyValue("parameters", functionDeclaration.parameters)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; TypeNameString returnTypeName; @@ -489,6 +786,19 @@ public: , id{id} {} + template<typename String> + friend void convertToString(String &string, const FunctionDeclarationView &functionDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", functionDeclaration.name), + keyValue("return type name", functionDeclaration.returnTypeName), + keyValue("signature", functionDeclaration.signature), + keyValue("id", functionDeclaration.id)); + + convertToString(string, dict); + } + public: ::Utils::SmallStringView name; ::Utils::SmallStringView returnTypeName; @@ -498,6 +808,19 @@ public: enum class PropertyKind { Property, Alias }; +template<typename String> +void convertToString(String &string, const PropertyKind &kind) +{ + switch (kind) { + case PropertyKind::Property: + convertToString(string, "Property"); + break; + case PropertyKind::Alias: + convertToString(string, "Alias"); + break; + } +} + class PropertyDeclaration { public: @@ -567,6 +890,24 @@ public: && first.traits == second.traits && first.kind == second.kind; } + template<typename String> + friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", propertyDeclaration.name), + keyValue("type name", propertyDeclaration.typeName), + keyValue("alias property name", propertyDeclaration.aliasPropertyName), + keyValue("alias property name tail", + propertyDeclaration.aliasPropertyNameTail), + keyValue("traits", propertyDeclaration.traits), + keyValue("type id", propertyDeclaration.typeId), + keyValue("property type id", propertyDeclaration.propertyTypeId), + keyValue("kind", propertyDeclaration.kind)); + + convertToString(string, dict); + } + public: ::Utils::SmallString name; ImportedTypeName typeName; @@ -597,6 +938,21 @@ public: , aliasId{aliasId} {} + template<typename String> + friend void convertToString(String &string, const PropertyDeclarationView &propertyDeclaration) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("name", propertyDeclaration.name), + keyValue("traits", propertyDeclaration.traits), + keyValue("type id", propertyDeclaration.typeId), + keyValue("type name id", propertyDeclaration.typeNameId), + keyValue("id", propertyDeclaration.id), + keyValue("alias id", propertyDeclaration.aliasId)); + + convertToString(string, dict); + } + public: ::Utils::SmallStringView name; PropertyDeclarationTraits traits = {}; @@ -608,6 +964,22 @@ public: enum class ChangeLevel : char { Full, Minimal, ExcludeExportedTypes }; +template<typename String> +void convertToString(String &string, const ChangeLevel &changeLevel) +{ + switch (changeLevel) { + case ChangeLevel::Full: + convertToString(string, "Full"); + break; + case ChangeLevel::Minimal: + convertToString(string, "Minimal"); + break; + case ChangeLevel::ExcludeExportedTypes: + convertToString(string, "ExcludeExportedTypes"); + break; + } +} + class Type { public: @@ -717,6 +1089,27 @@ public: && first.sourceId == second.sourceId; } + template<typename String> + friend void convertToString(String &string, const Type &type) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type name", type.typeName), + keyValue("prototype", type.prototype), + keyValue("extension", type.extension), + keyValue("exported types", type.exportedTypes), + keyValue("property declarations", type.propertyDeclarations), + keyValue("function declarations", type.functionDeclarations), + keyValue("signal declarations", type.signalDeclarations), + keyValue("enumeration declarations", type.enumerationDeclarations), + keyValue("traits", type.traits), + keyValue("source id", type.sourceId), + keyValue("change level", type.changeLevel), + keyValue("default property name", type.defaultPropertyName)); + + convertToString(string, dict); + } + public: TypeNameString typeName; ::Utils::SmallString defaultPropertyName; @@ -747,6 +1140,20 @@ public: , moduleId{moduleId} {} + template<typename String> + friend void convertToString(String &string, const PropertyEditorQmlPath &propertyEditorQmlPath) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type name", propertyEditorQmlPath.typeName), + keyValue("type id", propertyEditorQmlPath.typeId), + keyValue("path id", propertyEditorQmlPath.pathId), + keyValue("directory id", propertyEditorQmlPath.directoryId), + keyValue("module id", propertyEditorQmlPath.moduleId)); + + convertToString(string, dict); + } + public: TypeNameString typeName; TypeId typeId; @@ -757,39 +1164,55 @@ public: using PropertyEditorQmlPaths = std::vector<class PropertyEditorQmlPath>; -class ProjectData +class DirectoryInfo { public: - ProjectData(SourceId projectSourceId, SourceId sourceId, ModuleId moduleId, FileType fileType) - : projectSourceId{projectSourceId} + DirectoryInfo(SourceId directorySourceId, SourceId sourceId, ModuleId moduleId, FileType fileType) + : directorySourceId{directorySourceId} , sourceId{sourceId} , moduleId{moduleId} , fileType{fileType} {} - friend bool operator==(const ProjectData &first, const ProjectData &second) + friend bool operator==(const DirectoryInfo &first, const DirectoryInfo &second) { - return first.projectSourceId == second.projectSourceId && first.sourceId == second.sourceId + return first.directorySourceId == second.directorySourceId && first.sourceId == second.sourceId && first.moduleId.internalId() == second.moduleId.internalId() && first.fileType == second.fileType; } + template<typename String> + friend void convertToString(String &string, const DirectoryInfo &directoryInfo) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("project source id", directoryInfo.directorySourceId), + keyValue("source id", directoryInfo.sourceId), + keyValue("module id", directoryInfo.moduleId), + keyValue("file type", directoryInfo.fileType)); + + convertToString(string, dict); + } + public: - SourceId projectSourceId; + SourceId directorySourceId; SourceId sourceId; ModuleId moduleId; FileType fileType; }; -using ProjectDatas = std::vector<ProjectData>; +using DirectoryInfos = std::vector<DirectoryInfo>; class TypeAnnotation { public: - TypeAnnotation(SourceId sourceId) + TypeAnnotation(SourceId sourceId, SourceId directorySourceId) : sourceId{sourceId} + , directorySourceId{directorySourceId} {} + TypeAnnotation(SourceId sourceId, + SourceId directorySourceId, Utils::SmallStringView typeName, ModuleId moduleId, Utils::SmallStringView iconPath, @@ -803,8 +1226,26 @@ public: , sourceId{sourceId} , moduleId{moduleId} , traits{traits} + , directorySourceId{directorySourceId} {} + template<typename String> + friend void convertToString(String &string, const TypeAnnotation &typeAnnotation) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + auto dict = dictonary(keyValue("type name", typeAnnotation.typeName), + keyValue("icon path", typeAnnotation.iconPath), + keyValue("item library json", typeAnnotation.itemLibraryJson), + keyValue("hints json", typeAnnotation.hintsJson), + keyValue("type id", typeAnnotation.typeId), + keyValue("source id", typeAnnotation.sourceId), + keyValue("module id", typeAnnotation.moduleId), + keyValue("traits", typeAnnotation.traits)); + + convertToString(string, dict); + } + public: TypeNameString typeName; Utils::PathString iconPath; @@ -814,6 +1255,7 @@ public: SourceId sourceId; ModuleId moduleId; TypeTraits traits; + SourceId directorySourceId; }; using TypeAnnotations = std::vector<TypeAnnotation>; @@ -853,9 +1295,9 @@ public: , fileStatuses(std::move(fileStatuses)) {} - SynchronizationPackage(SourceIds updatedProjectSourceIds, ProjectDatas projectDatas) - : projectDatas(std::move(projectDatas)) - , updatedProjectSourceIds(std::move(updatedProjectSourceIds)) + SynchronizationPackage(SourceIds updatedDirectoryInfoSourceIds, DirectoryInfos directoryInfos) + : directoryInfos(std::move(directoryInfos)) + , updatedDirectoryInfoSourceIds(std::move(updatedDirectoryInfoSourceIds)) {} public: @@ -864,8 +1306,8 @@ public: SourceIds updatedSourceIds; SourceIds updatedFileStatusSourceIds; FileStatuses fileStatuses; - ProjectDatas projectDatas; - SourceIds updatedProjectSourceIds; + DirectoryInfos directoryInfos; + SourceIds updatedDirectoryInfoSourceIds; Imports moduleDependencies; SourceIds updatedModuleDependencySourceIds; ModuleExportedImports moduleExportedImports; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp index 62fcf310f6..a0e7bba3c5 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp @@ -11,8 +11,11 @@ #include "qmltypesparserinterface.h" #include "sourcepath.h" #include "sourcepathcache.h" +#include "typeannotationreader.h" #include <sqlitedatabase.h> +#include <tracing/qmldesignertracing.h> +#include <utils/set_algorithm.h> #include <QDirIterator> #include <QRegularExpression> @@ -21,6 +24,26 @@ #include <functional> namespace QmlDesigner { +constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory; +using NanotraceHR::keyValue; +using Tracer = ProjectStorageTracing::Category::TracerType; + +template<typename String> +void convertToString(String &string, const ProjectStorageUpdater::FileState &state) +{ + switch (state) { + case ProjectStorageUpdater::FileState::Changed: + convertToString(string, "Changed"); + break; + case ProjectStorageUpdater::FileState::NotChanged: + convertToString(string, "NotChanged"); + break; + case ProjectStorageUpdater::FileState::NotExists: + convertToString(string, "NotExists"); + break; + } +} + namespace { QStringList filterMultipleEntries(QStringList qmlTypes) @@ -79,6 +102,8 @@ ProjectStorageUpdater::Components createComponents( } for (const QmlDirParser::Component &qmlDirParserComponent : qmlDirParserComponents) { + if (qmlDirParserComponent.fileName.contains('/')) + continue; components.push_back(ProjectStorageUpdater::Component{qmlDirParserComponent.fileName, qmlDirParserComponent.typeName, moduleId, @@ -110,10 +135,15 @@ SourceIds filterNotUpdatedSourceIds(SourceIds updatedSourceIds, SourceIds notUpd return filteredUpdatedSourceIds; } -void addSourceIds(SourceIds &sourceIds, const Storage::Synchronization::ProjectDatas &projectDatas) +void addSourceIds(SourceIds &sourceIds, + const Storage::Synchronization::DirectoryInfos &directoryInfos, + TracerLiteral message, + Tracer &tracer) { - for (const auto &projectData : projectDatas) - sourceIds.push_back(projectData.sourceId); + for (const auto &directoryInfo : directoryInfos) { + tracer.tick(message, keyValue("source id", directoryInfo.sourceId)); + sourceIds.push_back(directoryInfo.sourceId); + } } Storage::Version convertVersion(LanguageUtils::ComponentVersion version) @@ -131,34 +161,84 @@ Storage::Synchronization::IsAutoVersion convertToIsAutoVersion(QmlDirParser::Imp void addDependencies(Storage::Imports &dependencies, SourceId sourceId, const QList<QmlDirParser::Import> &qmldirDependencies, - ProjectStorageInterface &projectStorage) + ProjectStorageInterface &projectStorage, + TracerLiteral message, + Tracer &tracer) { for (const QmlDirParser::Import &qmldirDependency : qmldirDependencies) { - ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module} - + "-cppnative"); - dependencies.emplace_back(moduleId, Storage::Version{}, sourceId); + ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module}, + Storage::ModuleKind::CppLibrary); + auto &import = dependencies.emplace_back(moduleId, Storage::Version{}, sourceId); + tracer.tick(message, keyValue("import", import)); } } +void addModuleExportedImport(Storage::Synchronization::ModuleExportedImports &imports, + ModuleId moduleId, + ModuleId exportedModuleId, + Storage::Version version, + Storage::Synchronization::IsAutoVersion isAutoVersion, + std::string_view moduleName, + Storage::ModuleKind moduleKind, + std::string_view exportedModuleName) +{ + NanotraceHR::Tracer tracer{"add module exported imports"_t, + category(), + keyValue("module id", moduleId), + keyValue("exported module id", exportedModuleId), + keyValue("version", version), + keyValue("is auto version", isAutoVersion), + keyValue("module name", moduleName), + keyValue("module kind", moduleKind), + keyValue("exported module name", exportedModuleName)}; + + imports.emplace_back(moduleId, exportedModuleId, version, isAutoVersion); +} + +bool isOptionalImport(QmlDirParser::Import::Flags flags) +{ + return flags & QmlDirParser::Import::Optional && !(flags & QmlDirParser::Import::OptionalDefault); +} + void addModuleExportedImports(Storage::Synchronization::ModuleExportedImports &imports, ModuleId moduleId, ModuleId cppModuleId, + std::string_view moduleName, const QList<QmlDirParser::Import> &qmldirImports, ProjectStorageInterface &projectStorage) { + NanotraceHR::Tracer tracer{"add module exported imports"_t, + category(), + keyValue("cpp module id", cppModuleId), + keyValue("module id", moduleId)}; + for (const QmlDirParser::Import &qmldirImport : qmldirImports) { - ModuleId exportedModuleId = projectStorage.moduleId(Utils::PathString{qmldirImport.module}); - imports.emplace_back(moduleId, - exportedModuleId, - convertVersion(qmldirImport.version), - convertToIsAutoVersion(qmldirImport.flags)); + if (isOptionalImport(qmldirImport.flags)) + continue; - ModuleId exportedCppModuleId = projectStorage.moduleId( - Utils::PathString{qmldirImport.module} + "-cppnative"); - imports.emplace_back(cppModuleId, - exportedCppModuleId, - Storage::Version{}, - Storage::Synchronization::IsAutoVersion::No); + Utils::PathString exportedModuleName{qmldirImport.module}; + using Storage::ModuleKind; + ModuleId exportedModuleId = projectStorage.moduleId(exportedModuleName, + ModuleKind::QmlLibrary); + addModuleExportedImport(imports, + moduleId, + exportedModuleId, + convertVersion(qmldirImport.version), + convertToIsAutoVersion(qmldirImport.flags), + moduleName, + ModuleKind::QmlLibrary, + exportedModuleName); + + ModuleId exportedCppModuleId = projectStorage.moduleId(exportedModuleName, + ModuleKind::CppLibrary); + addModuleExportedImport(imports, + cppModuleId, + exportedCppModuleId, + Storage::Version{}, + Storage::Synchronization::IsAutoVersion::No, + moduleName, + ModuleKind::CppLibrary, + exportedModuleName); } } @@ -182,8 +262,14 @@ std::vector<IdPaths> createIdPaths(ProjectStorageUpdater::WatchedSourceIdsIds wa void ProjectStorageUpdater::update(QStringList directories, QStringList qmlTypesPaths, - const QString &propertyEditorResourcesPath) + const QString &propertyEditorResourcesPath, + const QStringList &typeAnnotationPaths) { + NanotraceHR::Tracer tracer{"update"_t, + category(), + keyValue("directories", directories), + keyValue("qml types paths", qmlTypesPaths)}; + Storage::Synchronization::SynchronizationPackage package; WatchedSourceIdsIds watchedSourceIds{Utils::span{directories}.size()}; NotUpdatedSourceIds notUpdatedSourceIds{Utils::span{directories}.size()}; @@ -191,6 +277,7 @@ void ProjectStorageUpdater::update(QStringList directories, updateDirectories(directories, package, notUpdatedSourceIds, watchedSourceIds); updateQmlTypes(qmlTypesPaths, package, notUpdatedSourceIds, watchedSourceIds); updatePropertyEditorPaths(propertyEditorResourcesPath, package, notUpdatedSourceIds); + updateTypeAnnotations(typeAnnotationPaths, package, notUpdatedSourceIds); package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds), std::move(notUpdatedSourceIds.sourceIds)); @@ -198,7 +285,13 @@ void ProjectStorageUpdater::update(QStringList directories, std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedSourceIds.fileStatusSourceIds)); - m_projectStorage.synchronize(std::move(package)); + try { + m_projectStorage.synchronize(std::move(package)); + } catch (const TypeNameDoesNotExists &exception) { + qDebug() << "missing type: " << exception.what(); + } catch (...) { + qWarning() << "Project storage could not been updated!"; + } m_pathWatcher.updateIdPaths(createIdPaths(watchedSourceIds, m_projectPartId)); } @@ -211,25 +304,30 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths, if (qmlTypesPaths.empty()) return; - ModuleId moduleId = m_projectStorage.moduleId("QML-cppnative"); + NanotraceHR::Tracer tracer{"update qmltypes file"_t, category()}; + + ModuleId moduleId = m_projectStorage.moduleId("QML", Storage::ModuleKind::CppLibrary); for (const QString &qmlTypesPath : qmlTypesPaths) { SourceId sourceId = m_pathCache.sourceId(SourcePath{qmlTypesPath}); watchedSourceIdsIds.qmltypesSourceIds.push_back(sourceId); + tracer.tick("append watched qml types source id"_t, + keyValue("source id", sourceId), + keyValue("qml types path", qmlTypesPath)); - Storage::Synchronization::ProjectData projectData{sourceId, - sourceId, - moduleId, - Storage::Synchronization::FileType::QmlTypes}; + Storage::Synchronization::DirectoryInfo directoryInfo{ + sourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes}; - FileState state = parseTypeInfo(projectData, + FileState state = parseTypeInfo(directoryInfo, Utils::PathString{qmlTypesPath}, package, notUpdatedSourceIds); if (state == FileState::Changed) { - package.projectDatas.push_back(std::move(projectData)); - package.updatedProjectSourceIds.push_back(sourceId); + tracer.tick("append project data"_t, keyValue("project data", directoryInfo)); + package.directoryInfos.push_back(std::move(directoryInfo)); + tracer.tick("append updated project source ids"_t, keyValue("source id", sourceId)); + package.updatedDirectoryInfoSourceIds.push_back(sourceId); } } } @@ -246,24 +344,199 @@ ProjectStorageUpdater::FileState combineState(FileStates... fileStates) return ProjectStorageUpdater::FileState::NotExists; } + } // namespace +void ProjectStorageUpdater::updateDirectoryChanged(std::string_view directoryPath, + FileState qmldirState, + SourcePath qmldirSourcePath, + SourceId qmldirSourceId, + SourceId directorySourceId, + SourceContextId directoryId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIdsIds, + Tracer &tracer) +{ + QmlDirParser parser; + if (qmldirState != FileState::NotExists) + parser.parse(m_fileSystem.contentAsQString(QString{qmldirSourcePath})); + + if (qmldirState != FileState::NotChanged) { + tracer.tick("append updated source id"_t, keyValue("module id", qmldirSourceId)); + package.updatedSourceIds.push_back(qmldirSourceId); + } + + using Storage::ModuleKind; + Utils::PathString moduleName{parser.typeNamespace()}; + ModuleId moduleId = m_projectStorage.moduleId(moduleName, ModuleKind::QmlLibrary); + ModuleId cppModuleId = m_projectStorage.moduleId(moduleName, ModuleKind::CppLibrary); + ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath, ModuleKind::PathLibrary); + + auto imports = filterMultipleEntries(parser.imports()); + + addModuleExportedImports(package.moduleExportedImports, + moduleId, + cppModuleId, + moduleName, + imports, + m_projectStorage); + tracer.tick("append updated module id"_t, keyValue("module id", moduleId)); + package.updatedModuleIds.push_back(moduleId); + + const auto qmlDirectoryInfos = m_projectStorage.fetchDirectoryInfos(directorySourceId); + addSourceIds(package.updatedSourceIds, qmlDirectoryInfos, "append updated source id"_t, tracer); + addSourceIds(package.updatedFileStatusSourceIds, + qmlDirectoryInfos, + "append updated file status source id"_t, + tracer); + + auto qmlTypes = filterMultipleEntries(parser.typeInfos()); + + if (!qmlTypes.isEmpty()) { + parseTypeInfos(qmlTypes, + filterMultipleEntries(parser.dependencies()), + imports, + directorySourceId, + directoryPath, + cppModuleId, + package, + notUpdatedSourceIds, + watchedSourceIdsIds); + } + parseQmlComponents( + createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath), + directorySourceId, + directoryId, + package, + notUpdatedSourceIds, + watchedSourceIdsIds, + qmldirState); + tracer.tick("append updated project source id"_t, keyValue("module id", moduleId)); + package.updatedDirectoryInfoSourceIds.push_back(directorySourceId); +} + void ProjectStorageUpdater::updateDirectories(const QStringList &directories, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds) { + NanotraceHR::Tracer tracer{"update directories"_t, category()}; + for (const QString &directory : directories) - updateDirectory({directory}, package, notUpdatedSourceIds, watchedSourceIdsIds); + updateDirectory({directory}, {}, package, notUpdatedSourceIds, watchedSourceIdsIds); +} + +void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &directoryPath, + SourceId directorySourceId, + FileState directoryState, + const SourceContextIds &subdirectoriesToIgnore, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIdsIds) +{ + struct Directory + { + Directory(Utils::SmallStringView path, SourceContextId sourceContextId, SourceId sourceId) + : path{path} + , sourceContextId{sourceContextId} + , sourceId{sourceId} + {} + + bool operator<(const Directory &other) const + { + return sourceContextId < other.sourceContextId; + } + + bool operator==(const Directory &other) const + { + return sourceContextId == other.sourceContextId; + } + + Utils::PathString path; + SourceContextId sourceContextId; + SourceId sourceId; + }; + + struct Compare + { + bool operator()(const Directory &first, const Directory &second) const + { + return first.sourceContextId < second.sourceContextId; + } + + bool operator()(const Directory &first, SourceContextId second) const + { + return first.sourceContextId < second; + } + + bool operator()(SourceContextId first, const Directory &second) const + { + return first < second.sourceContextId; + } + }; + + using Directories = QVarLengthArray<Directory, 32>; + + auto subdirectorySourceIds = m_projectStorage.fetchSubdirectorySourceIds(directorySourceId); + auto subdirectories = Utils::transform<Directories>( + subdirectorySourceIds, [&](SourceId sourceId) -> Directory { + auto sourceContextId = m_pathCache.sourceContextId(sourceId); + auto subdirectoryPath = m_pathCache.sourceContextPath(sourceContextId); + return {subdirectoryPath, sourceContextId, sourceId}; + }); + + auto exisitingSubdirectoryPaths = m_fileSystem.subdirectories(directoryPath.toQString()); + Directories existingSubdirecories; + for (const QString &subdirectory : exisitingSubdirectoryPaths) { + if (subdirectory.endsWith("/designer") || subdirectory.endsWith("/QtQuick/Scene2D") + || subdirectory.endsWith("/QtQuick/Scene3D")) + continue; + Utils::PathString subdirectoryPath = subdirectory; + auto [sourceContextId, sourceId] = m_pathCache.sourceContextAndSourceId( + SourcePath{subdirectoryPath + "/."}); + subdirectories.emplace_back(subdirectoryPath, sourceContextId, sourceId); + existingSubdirecories.emplace_back(subdirectoryPath, sourceContextId, sourceId); + } + + std::sort(subdirectories.begin(), subdirectories.end()); + subdirectories.erase(std::unique(subdirectories.begin(), subdirectories.end()), + subdirectories.end()); + + std::set_difference(subdirectories.begin(), + subdirectories.end(), + subdirectoriesToIgnore.begin(), + subdirectoriesToIgnore.end(), + Utils::make_iterator([&](const Directory &subdirectory) { + updateDirectory(subdirectory.path, + subdirectoriesToIgnore, + package, + notUpdatedSourceIds, + watchedSourceIdsIds); + }), + Compare{}); + + if (directoryState == FileState::Changed) { + for (const auto &[subdirectoryPath, sourceContextId, subdirectorySourceId] : + existingSubdirecories) { + package.directoryInfos.emplace_back(directorySourceId, + subdirectorySourceId, + ModuleId{}, + Storage::Synchronization::FileType::Directory); + } + } } void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath, + const SourceContextIds &subdirectoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds) { + NanotraceHR::Tracer tracer{"update directory"_t, category(), keyValue("directory", directoryPath)}; + SourcePath qmldirSourcePath{directoryPath + "/qmldir"}; - auto [directoryId, qmlDirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath); + auto [directoryId, qmldirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath); SourcePath directorySourcePath{directoryPath + "/."}; auto directorySourceId = m_pathCache.sourceId(directorySourcePath); @@ -271,82 +544,69 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa if (directoryState != FileState::NotExists) watchedSourceIdsIds.directorySourceIds.push_back(directorySourceId); - auto qmldirState = fileState(qmlDirSourceId, package, notUpdatedSourceIds); + auto qmldirState = fileState(qmldirSourceId, package, notUpdatedSourceIds); if (qmldirState != FileState::NotExists) - watchedSourceIdsIds.qmldirSourceIds.push_back(qmlDirSourceId); + watchedSourceIdsIds.qmldirSourceIds.push_back(qmldirSourceId); switch (combineState(directoryState, qmldirState)) { case FileState::Changed: { - QmlDirParser parser; - if (qmldirState != FileState::NotExists) - parser.parse(m_fileSystem.contentAsQString(QString{qmldirSourcePath})); - - if (qmldirState != FileState::NotChanged) - package.updatedSourceIds.push_back(qmlDirSourceId); - - Utils::PathString moduleName{parser.typeNamespace()}; - ModuleId moduleId = m_projectStorage.moduleId(moduleName); - ModuleId cppModuleId = m_projectStorage.moduleId(moduleName + "-cppnative"); - ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath); - - auto imports = filterMultipleEntries(parser.imports()); - - addModuleExportedImports(package.moduleExportedImports, - moduleId, - cppModuleId, - imports, - m_projectStorage); - package.updatedModuleIds.push_back(moduleId); - - const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(directorySourceId); - addSourceIds(package.updatedSourceIds, qmlProjectDatas); - addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas); - - auto qmlTypes = filterMultipleEntries(parser.typeInfos()); - - if (!qmlTypes.isEmpty()) { - parseTypeInfos(qmlTypes, - filterMultipleEntries(parser.dependencies()), - imports, - directorySourceId, - directoryPath, - cppModuleId, - package, - notUpdatedSourceIds, - watchedSourceIdsIds); - } - parseQmlComponents( - createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath), - directorySourceId, - directoryId, - package, - notUpdatedSourceIds, - watchedSourceIdsIds, - qmldirState); - package.updatedProjectSourceIds.push_back(directorySourceId); + tracer.tick("update directory changed"_t); + updateDirectoryChanged(directoryPath, + qmldirState, + qmldirSourcePath, + qmldirSourceId, + directorySourceId, + directoryId, + package, + notUpdatedSourceIds, + watchedSourceIdsIds, + tracer); break; } case FileState::NotChanged: { - parseProjectDatas(m_projectStorage.fetchProjectDatas(directorySourceId), - package, - notUpdatedSourceIds, - watchedSourceIdsIds); + tracer.tick("update directory not changed"_t); + + parseDirectoryInfos(m_projectStorage.fetchDirectoryInfos(directorySourceId), + package, + notUpdatedSourceIds, + watchedSourceIdsIds); break; } case FileState::NotExists: { + tracer.tick("update directory don't exits"_t); + package.updatedFileStatusSourceIds.push_back(directorySourceId); - package.updatedFileStatusSourceIds.push_back(qmlDirSourceId); - package.updatedProjectSourceIds.push_back(directorySourceId); - package.updatedSourceIds.push_back(qmlDirSourceId); - auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(directorySourceId); - for (const Storage::Synchronization::ProjectData &projectData : qmlProjectDatas) { - package.updatedSourceIds.push_back(projectData.sourceId); - package.updatedFileStatusSourceIds.push_back(projectData.sourceId); + package.updatedFileStatusSourceIds.push_back(qmldirSourceId); + package.updatedDirectoryInfoSourceIds.push_back(directorySourceId); + package.updatedSourceIds.push_back(qmldirSourceId); + auto qmlDirectoryInfos = m_projectStorage.fetchDirectoryInfos(directorySourceId); + for (const Storage::Synchronization::DirectoryInfo &directoryInfo : qmlDirectoryInfos) { + tracer.tick("append updated source id"_t, keyValue("source id", directoryInfo.sourceId)); + package.updatedSourceIds.push_back(directoryInfo.sourceId); + tracer.tick("append updated file status source id"_t, + keyValue("source id", directoryInfo.sourceId)); + package.updatedFileStatusSourceIds.push_back(directoryInfo.sourceId); } break; } } + + updateSubdirectories(directoryPath, + directorySourceId, + directoryState, + subdirectoriesToIgnore, + package, + notUpdatedSourceIds, + watchedSourceIdsIds); + + tracer.end(keyValue("qmldir source path", qmldirSourcePath), + keyValue("directory source path", directorySourcePath), + keyValue("directory id", directoryId), + keyValue("qmldir source id", qmldirSourceId), + keyValue("directory source source id", directorySourceId), + keyValue("qmldir state", qmldirState), + keyValue("directory state", directoryState)); } void ProjectStorageUpdater::updatePropertyEditorPaths( @@ -354,6 +614,10 @@ void ProjectStorageUpdater::updatePropertyEditorPaths( Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) { + NanotraceHR::Tracer tracer{"update property editor paths"_t, + category(), + keyValue("property editor resources path", propertyEditorResourcesPath)}; + if (propertyEditorResourcesPath.isEmpty()) return; @@ -368,49 +632,196 @@ void ProjectStorageUpdater::updatePropertyEditorPaths( auto state = fileState(directorySourceId, package, notUpdatedSourceIds); - if (state == FileState::Changed) - updatePropertyEditorPath(pathInfo.filePath(), package, directorySourceId); + if (state == FileState::Changed) { + updatePropertyEditorPath(pathInfo.filePath(), + package, + directorySourceId, + propertyEditorResourcesPath.size() + 1); + } } } +namespace { + +template<typename SourceIds1, typename SourceIds2> +SmallSourceIds<16> mergedSourceIds(const SourceIds1 &sourceIds1, const SourceIds2 &sourceIds2) +{ + SmallSourceIds<16> mergedSourceIds; + + std::set_union(sourceIds1.begin(), + sourceIds1.end(), + sourceIds2.begin(), + sourceIds2.end(), + std::back_inserter(mergedSourceIds)); + + return mergedSourceIds; +} +} // namespace + +void ProjectStorageUpdater::updateTypeAnnotations(const QStringList &directoryPaths, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds) +{ + NanotraceHR::Tracer tracer("update type annotations"_t, category()); + + std::map<SourceId, SmallSourceIds<16>> updatedSourceIdsDictonary; + + for (SourceId directoryId : m_projectStorage.typeAnnotationDirectorySourceIds()) + updatedSourceIdsDictonary[directoryId] = {}; + + for (const auto &directoryPath : directoryPaths) + updateTypeAnnotations(directoryPath, package, notUpdatedSourceIds, updatedSourceIdsDictonary); + + updateTypeAnnotationDirectories(package, notUpdatedSourceIds, updatedSourceIdsDictonary); +} + void ProjectStorageUpdater::updateTypeAnnotations( - const QString & /*propertyEditorResourcesPath*/, - Storage::Synchronization::SynchronizationPackage & /*package*/, - NotUpdatedSourceIds & /*notUpdatedSourceIds*/) + const QString &rootDirectoryPath, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary) +{ + NanotraceHR::Tracer tracer("update type annotation directory"_t, + category(), + keyValue("path", rootDirectoryPath)); + + if (rootDirectoryPath.isEmpty()) + return; + + QDirIterator directoryIterator{rootDirectoryPath, + {"*.metainfo"}, + QDir::NoDotAndDotDot | QDir::Files, + QDirIterator::Subdirectories}; + + while (directoryIterator.hasNext()) { + auto fileInfo = directoryIterator.nextFileInfo(); + auto filePath = fileInfo.filePath(); + SourceId sourceId = m_pathCache.sourceId(SourcePath{filePath}); + + auto directoryPath = fileInfo.canonicalPath(); + + SourceId directorySourceId = m_pathCache.sourceId(SourcePath{directoryPath + "/."}); + + auto state = fileState(sourceId, package, notUpdatedSourceIds); + if (state == FileState::Changed) + updateTypeAnnotation(directoryPath, fileInfo.filePath(), sourceId, directorySourceId, package); + + if (state != FileState::NotChanged) + updatedSourceIdsDictonary[directorySourceId].push_back(sourceId); + } +} + +void ProjectStorageUpdater::updateTypeAnnotationDirectories( + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary) +{ + for (auto &[directorySourceId, updatedSourceIds] : updatedSourceIdsDictonary) { + auto directoryState = fileState(directorySourceId, package, notUpdatedSourceIds); + + if (directoryState != FileState::NotChanged) { + auto existingTypeAnnotationSourceIds = m_projectStorage.typeAnnotationSourceIds( + directorySourceId); + + std::sort(updatedSourceIds.begin(), updatedSourceIds.end()); + + auto changedSourceIds = mergedSourceIds(existingTypeAnnotationSourceIds, updatedSourceIds); + package.updatedTypeAnnotationSourceIds.insert(package.updatedTypeAnnotationSourceIds.end(), + changedSourceIds.begin(), + changedSourceIds.end()); + } else { + package.updatedTypeAnnotationSourceIds.insert(package.updatedTypeAnnotationSourceIds.end(), + updatedSourceIds.begin(), + updatedSourceIds.end()); + } + } +} + +namespace { +QString contentFromFile(const QString &path) { - // const auto typeAnnotations = dir.entryInfoList({"*.metainfo"}, QDir::Files); + QFile file{path}; + if (file.open(QIODevice::ReadOnly)) + return QString::fromUtf8(file.readAll()); + + return {}; +} +} // namespace + +void ProjectStorageUpdater::updateTypeAnnotation(const QString &directoryPath, + const QString &filePath, + SourceId sourceId, + SourceId directorySourceId, + Storage::Synchronization::SynchronizationPackage &package) +{ + NanotraceHR::Tracer tracer{"update type annotation path"_t, + category(), + keyValue("path", filePath), + keyValue("directory path", directoryPath)}; + + Storage::TypeAnnotationReader reader{m_projectStorage}; + + auto annotations = reader.parseTypeAnnotation(contentFromFile(filePath), + directoryPath, + sourceId, + directorySourceId); + auto &typeAnnotations = package.typeAnnotations; + package.typeAnnotations.insert(typeAnnotations.end(), + std::make_move_iterator(annotations.begin()), + std::make_move_iterator(annotations.end())); } void ProjectStorageUpdater::updatePropertyEditorPath( const QString &directoryPath, Storage::Synchronization::SynchronizationPackage &package, - SourceId directorySourceId) + SourceId directorySourceId, + long long pathOffset) { + NanotraceHR::Tracer tracer{"update property editor path"_t, + category(), + keyValue("directory path", directoryPath), + keyValue("directory source id", directorySourceId)}; + + tracer.tick("append updated property editor qml path source id"_t, + keyValue("source id", directorySourceId)); package.updatedPropertyEditorQmlPathSourceIds.push_back(directorySourceId); auto dir = QDir{directoryPath}; const auto fileInfos = dir.entryInfoList({"*Pane.qml", "*Specifics.qml"}, QDir::Files); for (const auto &fileInfo : fileInfos) - updatePropertyEditorFilePath(fileInfo.filePath(), package, directorySourceId); + updatePropertyEditorFilePath(fileInfo.filePath(), package, directorySourceId, pathOffset); } void ProjectStorageUpdater::updatePropertyEditorFilePath( const QString &path, Storage::Synchronization::SynchronizationPackage &package, - SourceId directorySourceId) + SourceId directorySourceId, + long long pathOffset) { - QRegularExpression regex{R"xo(.+\/(\w+)\/(\w+)(Specifics|Pane).qml)xo"}; - auto match = regex.match(path); + NanotraceHR::Tracer tracer{"update property editor file path"_t, + category(), + keyValue("directory path", path), + keyValue("directory source id", directorySourceId)}; + + QRegularExpression regex{R"xo((.+)\/(\w+)(Specifics|Pane).qml)xo"}; + auto match = regex.match(QStringView{path}.mid(pathOffset)); QString oldModuleName; ModuleId moduleId; if (match.hasMatch()) { - auto moduleName = match.capturedView(1); + auto moduleName = match.capturedView(1).toString(); + moduleName.replace('/', '.'); if (oldModuleName != moduleName) { - oldModuleName = moduleName.toString(); - moduleId = m_projectStorage.moduleId(Utils::SmallString{moduleName}); + oldModuleName = moduleName; + moduleId = m_projectStorage.moduleId(Utils::SmallString{moduleName}, + Storage::ModuleKind::QmlLibrary); } Storage::TypeNameString typeName{match.capturedView(2)}; SourceId pathId = m_pathCache.sourceId(SourcePath{path}); - package.propertyEditorQmlPaths.emplace_back(moduleId, typeName, pathId, directorySourceId); + const auto &paths = package.propertyEditorQmlPaths.emplace_back(moduleId, + typeName, + pathId, + directorySourceId); + tracer.tick("append property editor qml paths"_t, + keyValue("property editor qml paths", paths)); } } @@ -447,6 +858,10 @@ bool contains(const Container &container, Id id) void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &changedIdPaths) { + NanotraceHR::Tracer tracer{"paths with ids changed"_t, + category(), + keyValue("id paths", changedIdPaths)}; + m_changedIdPaths.insert(m_changedIdPaths.end(), changedIdPaths.begin(), changedIdPaths.end()); Storage::Synchronization::SynchronizationPackage package; @@ -486,7 +901,11 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan for (auto sourceContextId : directorySourceContextIds) { Utils::PathString directory = m_pathCache.sourceContextPath(sourceContextId); - updateDirectory(directory, package, notUpdatedSourceIds, watchedSourceIds); + updateDirectory(directory, + directorySourceContextIds, + package, + notUpdatedSourceIds, + watchedSourceIds); } for (SourceId sourceId : filterUniqueSourceIds(qmlDocumentSourceIds)) { @@ -498,9 +917,9 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan for (SourceId sourceId : filterUniqueSourceIds(std::move(qmltypesSourceIds))) { if (!contains(directorySourceContextIds, m_pathCache.sourceContextId(sourceId))) { auto qmltypesPath = m_pathCache.sourcePath(sourceId); - auto projectData = m_projectStorage.fetchProjectData(sourceId); - if (projectData) - parseTypeInfo(*projectData, qmltypesPath, package, notUpdatedSourceIds); + auto directoryInfo = m_projectStorage.fetchDirectoryInfo(sourceId); + if (directoryInfo) + parseTypeInfo(*directoryInfo, qmltypesPath, package, notUpdatedSourceIds); } } } catch (const QmlDesigner::CannotParseQmlTypesFile &) { @@ -539,72 +958,99 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIds) { + NanotraceHR::Tracer tracer{"parse type infos"_t, + category(), + keyValue("directory source id", directorySourceId), + keyValue("directory path", directoryPath), + keyValue("module id", moduleId)}; + for (const QString &typeInfo : typeInfos) { + NanotraceHR::Tracer tracer{"parse type info"_t, category(), keyValue("type info", typeInfo)}; + Utils::PathString qmltypesPath = Utils::PathString::join( {directoryPath, "/", Utils::SmallString{typeInfo}}); SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath}); + tracer.tick("append qmltypes source id"_t, keyValue("source id", sourceId)); watchedSourceIds.qmltypesSourceIds.push_back(sourceId); addDependencies(package.moduleDependencies, sourceId, joinImports(qmldirDependencies, qmldirImports), - m_projectStorage); + m_projectStorage, + "append module dependency"_t, + tracer); + + tracer.tick("append module dependenct source source id"_t, keyValue("source id", sourceId)); package.updatedModuleDependencySourceIds.push_back(sourceId); - auto projectData = package.projectDatas.emplace_back( + const auto &directoryInfo = package.directoryInfos.emplace_back( directorySourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes); + tracer.tick("append project data"_t, keyValue("source id", sourceId)); - parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds); + parseTypeInfo(directoryInfo, qmltypesPath, package, notUpdatedSourceIds); } } -void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas, - Storage::Synchronization::SynchronizationPackage &package, - NotUpdatedSourceIds ¬UpdatedSourceIds, - WatchedSourceIdsIds &watchedSourceIds) +void ProjectStorageUpdater::parseDirectoryInfos( + const Storage::Synchronization::DirectoryInfos &directoryInfos, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIds) { - for (const Storage::Synchronization::ProjectData &projectData : projectDatas) { - switch (projectData.fileType) { + NanotraceHR::Tracer tracer{"parse project datas"_t, category()}; + + for (const Storage::Synchronization::DirectoryInfo &directoryInfo : directoryInfos) { + switch (directoryInfo.fileType) { case Storage::Synchronization::FileType::QmlTypes: { - watchedSourceIds.qmltypesSourceIds.push_back(projectData.sourceId); + watchedSourceIds.qmltypesSourceIds.push_back(directoryInfo.sourceId); - auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId); - parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds); + auto qmltypesPath = m_pathCache.sourcePath(directoryInfo.sourceId); + parseTypeInfo(directoryInfo, qmltypesPath, package, notUpdatedSourceIds); break; } case Storage::Synchronization::FileType::QmlDocument: { - watchedSourceIds.qmlSourceIds.push_back(projectData.sourceId); + watchedSourceIds.qmlSourceIds.push_back(directoryInfo.sourceId); - parseQmlComponent(projectData.sourceId, package, notUpdatedSourceIds); + parseQmlComponent(directoryInfo.sourceId, package, notUpdatedSourceIds); + break; } + case Storage::Synchronization::FileType::Directory: + break; } } } -auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::ProjectData &projectData, +auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::DirectoryInfo &directoryInfo, Utils::SmallStringView qmltypesPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) -> FileState { - auto state = fileState(projectData.sourceId, package, notUpdatedSourceIds); + NanotraceHR::Tracer tracer{"parse type info"_t, + category(), + keyValue("qmltypes path", qmltypesPath)}; + + auto state = fileState(directoryInfo.sourceId, package, notUpdatedSourceIds); switch (state) { case FileState::Changed: { - package.updatedSourceIds.push_back(projectData.sourceId); + tracer.tick("append updated source ids"_t, keyValue("source id", directoryInfo.sourceId)); + package.updatedSourceIds.push_back(directoryInfo.sourceId); const auto content = m_fileSystem.contentAsQString(QString{qmltypesPath}); - m_qmlTypesParser.parse(content, package.imports, package.types, projectData); + m_qmlTypesParser.parse(content, package.imports, package.types, directoryInfo); break; } case FileState::NotChanged: { - notUpdatedSourceIds.sourceIds.push_back(projectData.sourceId); + tracer.tick("append not updated source ids"_t, keyValue("source id", directoryInfo.sourceId)); + notUpdatedSourceIds.sourceIds.push_back(directoryInfo.sourceId); break; } case FileState::NotExists: throw CannotParseQmlTypesFile{}; - break; } + tracer.end(keyValue("state", state)); + return state; } @@ -617,6 +1063,14 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil WatchedSourceIdsIds &watchedSourceIds, FileState qmldirState) { + NanotraceHR::Tracer tracer{"parse qml component"_t, + category(), + keyValue("relative file path", relativeFilePath), + keyValue("directory path", directoryPath), + keyValue("exported types", exportedTypes), + keyValue("directory source id", directorySourceId), + keyValue("qmldir state", qmldirState)}; + if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end()) return; @@ -626,16 +1080,18 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil Storage::Synchronization::Type type; auto state = fileState(sourceId, package, notUpdatedSourceIds); + tracer.tick("append watched qml source id"_t, keyValue("source id", sourceId)); watchedSourceIds.qmlSourceIds.push_back(sourceId); switch (state) { case FileState::NotChanged: if (qmldirState == FileState::NotExists) { + tracer.tick("append not updated source id"_t, keyValue("source id", sourceId)); notUpdatedSourceIds.sourceIds.emplace_back(sourceId); - package.projectDatas.emplace_back(directorySourceId, - sourceId, - ModuleId{}, - Storage::Synchronization::FileType::QmlDocument); + + const auto &directoryInfo = package.directoryInfos.emplace_back( + directorySourceId, sourceId, ModuleId{}, Storage::Synchronization::FileType::QmlDocument); + tracer.tick("append project data"_t, keyValue("project data", directoryInfo)); return; } @@ -649,11 +1105,11 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil break; } - package.projectDatas.emplace_back(directorySourceId, - sourceId, - ModuleId{}, - Storage::Synchronization::FileType::QmlDocument); + const auto &directoryInfo = package.directoryInfos.emplace_back( + directorySourceId, sourceId, ModuleId{}, Storage::Synchronization::FileType::QmlDocument); + tracer.tick("append project data"_t, keyValue("project data", directoryInfo)); + tracer.tick("append updated source id"_t, keyValue("source id", sourceId)); package.updatedSourceIds.push_back(sourceId); type.typeName = SourcePath{qmlFilePath}.name(); @@ -661,6 +1117,8 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil type.sourceId = sourceId; type.exportedTypes = std::move(exportedTypes); + tracer.end(keyValue("type", type)); + package.types.push_back(std::move(type)); } @@ -668,10 +1126,13 @@ void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) { + NanotraceHR::Tracer tracer{"parse qml component"_t, category(), keyValue("source id", sourceId)}; + auto state = fileState(sourceId, package, notUpdatedSourceIds); if (state == FileState::NotChanged) return; + tracer.tick("append updated source id"_t, keyValue("source id", sourceId)); package.updatedSourceIds.push_back(sourceId); if (state == FileState::NotExists) @@ -687,6 +1148,8 @@ void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId, type.sourceId = sourceId; type.changeLevel = Storage::Synchronization::ChangeLevel::ExcludeExportedTypes; + tracer.end(keyValue("type", type)); + package.types.push_back(std::move(type)); } @@ -733,6 +1196,12 @@ void ProjectStorageUpdater::parseQmlComponents(Components components, WatchedSourceIdsIds &watchedSourceIdsIds, FileState qmldirState) { + NanotraceHR::Tracer tracer{"parse qml components"_t, + category(), + keyValue("directory source id", directorySourceId), + keyValue("directory id", directoryId), + keyValue("qmldir state", qmldirState)}; + std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { return first.fileName < second.fileName; }); @@ -760,22 +1229,37 @@ ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState( Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) const { + NanotraceHR::Tracer tracer{"update property editor paths"_t, + category(), + keyValue("source id", sourceId)}; + auto currentFileStatus = m_fileStatusCache.find(sourceId); if (!currentFileStatus.isValid()) { + tracer.tick("append updated file status source id"_t, keyValue("source id", sourceId)); package.updatedFileStatusSourceIds.push_back(sourceId); + + tracer.end(keyValue("state", FileState::NotExists)); return FileState::NotExists; } auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId); if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) { + tracer.tick("append file status"_t, keyValue("file status", sourceId)); package.fileStatuses.push_back(currentFileStatus); + + tracer.tick("append updated file status source id"_t, keyValue("source id", sourceId)); package.updatedFileStatusSourceIds.push_back(sourceId); + + tracer.end(keyValue("state", FileState::Changed)); return FileState::Changed; } + tracer.tick("append not updated file status source id"_t, keyValue("source id", sourceId)); notUpdatedSourceIds.fileStatusSourceIds.push_back(sourceId); + + tracer.end(keyValue("state", FileState::NotChanged)); return FileState::NotChanged; } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h index 187a2219d0..baecbd6b11 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h @@ -11,10 +11,15 @@ #include "projectstoragetypes.h" #include "sourcepath.h" +#include <modelfwd.h> + +#include <tracing/qmldesignertracing.h> + #include <qmljs/parser/qmldirparser_p.h> #include <QStringList> +#include <map> #include <vector> namespace Sqlite { @@ -27,7 +32,6 @@ class ProjectStorageInterface; template<typename ProjectStorage, typename Mutex> class SourcePathCache; class FileStatusCache; -template<typename Database> class ProjectStorage; class QmlDocumentParserInterface; class QmlTypesParserInterface; @@ -35,10 +39,10 @@ class QmlTypesParserInterface; class ProjectStorageUpdater final : public ProjectStoragePathWatcherNotifierInterface { public: - using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>; + using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>; ProjectStorageUpdater(FileSystemInterface &fileSystem, - ProjectStorageInterface &projectStorage, + ProjectStorageType &projectStorage, FileStatusCache &fileStatusCache, PathCache &pathCache, QmlDocumentParserInterface &qmlDocumentParser, @@ -57,7 +61,8 @@ public: void update(QStringList directories, QStringList qmlTypesPaths, - const QString &propertyEditorResourcesPath); + const QString &propertyEditorResourcesPath, + const QStringList &typeAnnotationPaths); void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) override; void pathsChanged(const SourceIds &filePathIds) override; @@ -138,22 +143,54 @@ private: WatchedSourceIdsIds &watchedSourceIdsIds); void updateDirectory(const Utils::PathString &directory, + const SourceContextIds &subdirecoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds); + void updateSubdirectories(const Utils::PathString &directory, + SourceId directorySourceId, + FileState directoryFileState, + const SourceContextIds &subdirecoriesToIgnore, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIdsIds); + void updateDirectoryChanged(std::string_view directoryPath, + FileState qmldirState, + SourcePath qmldirSourcePath, + SourceId qmldirSourceId, + SourceId directorySourceId, + SourceContextId directoryId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIdsIds, + ProjectStorageTracing::Category::TracerType &tracer); void updatePropertyEditorPaths(const QString &propertyEditorResourcesPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds); - void updateTypeAnnotations(const QString &propertyEditorResourcesPath, + void updateTypeAnnotations(const QString &directoryPath, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary); + void updateTypeAnnotationDirectories(Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary); + void updateTypeAnnotations(const QStringList &directoryPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds); + void updateTypeAnnotation(const QString &directoryPath, + const QString &filePath, + SourceId sourceId, + SourceId directorySourceId, + Storage::Synchronization::SynchronizationPackage &package); void updatePropertyEditorPath(const QString &path, Storage::Synchronization::SynchronizationPackage &package, - SourceId directorySourceId); + SourceId directorySourceId, + long long pathOffset); void updatePropertyEditorFilePath(const QString &filePath, Storage::Synchronization::SynchronizationPackage &package, - SourceId directorySourceId); + SourceId directorySourceId, + long long pathOffset); void parseTypeInfos(const QStringList &typeInfos, const QList<QmlDirParser::Import> &qmldirDependencies, const QList<QmlDirParser::Import> &qmldirImports, @@ -163,11 +200,11 @@ private: Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds); - void parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas, - Storage::Synchronization::SynchronizationPackage &package, - NotUpdatedSourceIds ¬UpdatedSourceIds, - WatchedSourceIdsIds &watchedSourceIdsIds); - FileState parseTypeInfo(const Storage::Synchronization::ProjectData &projectData, + void parseDirectoryInfos(const Storage::Synchronization::DirectoryInfos &directoryInfos, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds, + WatchedSourceIdsIds &watchedSourceIdsIds); + FileState parseTypeInfo(const Storage::Synchronization::DirectoryInfo &directoryInfo, Utils::SmallStringView qmltypesPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds); @@ -197,7 +234,7 @@ private: private: std::vector<IdPaths> m_changedIdPaths; FileSystemInterface &m_fileSystem; - ProjectStorageInterface &m_projectStorage; + ProjectStorageType &m_projectStorage; FileStatusCache &m_fileStatusCache; PathCache &m_pathCache; QmlDocumentParserInterface &m_qmlDocumentParser; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp index f9eb8080f7..4338da62ce 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp @@ -10,6 +10,8 @@ #include <sqlitedatabase.h> +#include <tracing/qmldesignertracing.h> + #ifdef QDS_BUILD_QMLPARSER #include <private/qqmldomtop_p.h> #endif @@ -21,6 +23,10 @@ namespace QmlDesigner { #ifdef QDS_BUILD_QMLPARSER +constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory; +using NanotraceHR::keyValue; +using Tracer = ProjectStorageTracing::Category::TracerType; + namespace QmlDom = QQmlJS::Dom; namespace Synchronization = Storage::Synchronization; @@ -60,23 +66,32 @@ Storage::Import createImport(const QmlDom::Import &qmlImport, Utils::SmallStringView directoryPath, QmlDocumentParser::ProjectStorage &storage) { + using Storage::ModuleKind; using QmlUriKind = QQmlJS::Dom::QmlUri::Kind; auto &&uri = qmlImport.uri; - if (uri.kind() == QmlUriKind::RelativePath) { + switch (uri.kind()) { + case QmlUriKind::AbsolutePath: + case QmlUriKind::DirectoryUrl: { + auto moduleId = storage.moduleId(Utils::PathString{uri.toString()}, ModuleKind::PathLibrary); + return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId); + } + case QmlUriKind::RelativePath: { auto path = createNormalizedPath(directoryPath, uri.localPath()); - auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath())); + auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath()), + ModuleKind::PathLibrary); return Storage::Import(moduleId, Storage::Version{}, sourceId); } - - if (uri.kind() == QmlUriKind::ModuleUri) { - auto moduleId = storage.moduleId(Utils::PathString{uri.moduleUri()}); + case QmlUriKind::ModuleUri: { + auto moduleId = storage.moduleId(Utils::PathString{uri.moduleUri()}, ModuleKind::QmlLibrary); return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId); } + case QmlUriKind::Invalid: + return Storage::Import{}; + } - auto moduleId = storage.moduleId(Utils::PathString{uri.toString()}); - return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId); + return Storage::Import{}; } QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports, @@ -84,6 +99,11 @@ QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports, Utils::SmallStringView directoryPath, QmlDocumentParser::ProjectStorage &storage) { + NanotraceHR::Tracer tracer{"create qualified imports"_t, + category(), + keyValue("sourceId", sourceId), + keyValue("directoryPath", directoryPath)}; + QualifiedImports qualifiedImports; for (const QmlDom::Import &qmlImport : qmlImports) { @@ -92,6 +112,8 @@ QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports, createImport(qmlImport, sourceId, directoryPath, storage)); } + tracer.end(keyValue("qualified imports", qualifiedImports)); + return qualifiedImports; } @@ -109,11 +131,13 @@ void addImports(Storage::Imports &imports, } } - auto localDirectoryModuleId = storage.moduleId(directoryPath); + using Storage::ModuleKind; + + auto localDirectoryModuleId = storage.moduleId(directoryPath, ModuleKind::PathLibrary); imports.emplace_back(localDirectoryModuleId, Storage::Version{}, sourceId); ++importCount; - auto qmlModuleId = storage.moduleId("QML"); + auto qmlModuleId = storage.moduleId("QML", ModuleKind::QmlLibrary); imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId); ++importCount; @@ -280,6 +304,11 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon SourceId sourceId, Utils::SmallStringView directoryPath) { + NanotraceHR::Tracer tracer{"qml document parser parse"_t, + category(), + keyValue("sourceId", sourceId), + keyValue("directoryPath", directoryPath)}; + Storage::Synchronization::Type type; using Option = QmlDom::DomEnvironment::Option; @@ -335,7 +364,7 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon m_storage); type.prototype = createImportedTypeName(qmlObject.name(), qualifiedImports); - + type.defaultPropertyName = qmlObject.localDefaultPropertyName(); addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage); addPropertyDeclarations(type, qmlObject, qualifiedImports, file); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h index b8ab4ec4b1..1b494a2f69 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h @@ -15,7 +15,7 @@ class SourcePathCache; class QmlDocumentParser final : public QmlDocumentParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; + using ProjectStorage = QmlDesigner::ProjectStorage; using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>; #ifdef QDS_BUILD_QMLPARSER diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp index 3768535299..b3ec4f0024 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -5,8 +5,12 @@ #include "projectstorage.h" +#include <tracing/qmldesignertracing.h> + #include <sqlitedatabase.h> +#include <utils/span.h> + #ifdef QDS_BUILD_QMLPARSER #include <private/qqmldomtop_p.h> #include <private/qqmljstypedescriptionreader_p.h> @@ -21,6 +25,10 @@ namespace QmlDesigner { #ifdef QDS_BUILD_QMLPARSER +constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory; +using NanotraceHR::keyValue; +using Tracer = ProjectStorageTracing::Category::TracerType; +using Storage::ModuleKind; namespace QmlDom = QQmlJS::Dom; namespace { @@ -31,6 +39,8 @@ using Storage::TypeNameString; ComponentWithoutNamespaces createComponentNameWithoutNamespaces(const QList<QQmlJSExportedScope> &objects) { + NanotraceHR::Tracer tracer{"parse qmltypes file"_t, category()}; + ComponentWithoutNamespaces componentWithoutNamespaces; for (const auto &object : objects) { @@ -46,23 +56,24 @@ ComponentWithoutNamespaces createComponentNameWithoutNamespaces(const QList<QQml name); } + tracer.end(keyValue("components without namespace", componentWithoutNamespaces)); + return componentWithoutNamespaces; } -void appendImports(Storage::Imports &imports, - const QString &dependency, - SourceId sourceId, - QmlTypesParser::ProjectStorage &storage) +const Storage::Import &appendImports(Storage::Imports &imports, + const QString &dependency, + SourceId sourceId, + QmlTypesParser::ProjectStorage &storage) { auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) { return c.isSpace(); }); Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)}; - moduleName.append("-cppnative"); - ModuleId cppModuleId = storage.moduleId(moduleName); + ModuleId cppModuleId = storage.moduleId(moduleName, ModuleKind::CppLibrary); - imports.emplace_back(cppModuleId, Storage::Version{}, sourceId); + return imports.emplace_back(cppModuleId, Storage::Version{}, sourceId); } void addImports(Storage::Imports &imports, @@ -71,13 +82,26 @@ void addImports(Storage::Imports &imports, QmlTypesParser::ProjectStorage &storage, ModuleId cppModuleId) { - for (const QString &dependency : dependencies) - appendImports(imports, dependency, sourceId, storage); + NanotraceHR::Tracer tracer{ + "add imports"_t, + category(), + keyValue("source id", sourceId), + keyValue("module id", cppModuleId), + }; + + for (const QString &dependency : dependencies) { + const auto &import = appendImports(imports, dependency, sourceId, storage); + tracer.tick("append import"_t, keyValue("import", import), keyValue("dependency", dependency)); + } - imports.emplace_back(cppModuleId, Storage::Version{}, sourceId); + const auto &import = imports.emplace_back(cppModuleId, Storage::Version{}, sourceId); + tracer.tick("append import"_t, keyValue("import", import)); - if (ModuleId qmlCppModuleId = storage.moduleId("QML-cppnative"); cppModuleId != qmlCppModuleId) - imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId); + if (ModuleId qmlCppModuleId = storage.moduleId("QML", ModuleKind::CppLibrary); + cppModuleId != qmlCppModuleId) { + const auto &import = imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId); + tracer.tick("append import"_t, keyValue("import", import)); + } } Storage::TypeTraits createAccessTypeTraits(QQmlJSScope::AccessSemantics accessSematics) @@ -121,7 +145,8 @@ Storage::Synchronization::ExportedTypes createExports(const QList<QQmlJSScope::E for (const QQmlJSScope::Export &qmlExport : qmlExports) { TypeNameString exportedTypeName{qmlExport.type()}; - exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}), + exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}, + ModuleKind::QmlLibrary), std::move(exportedTypeName), createVersion(qmlExport.version())); } @@ -412,6 +437,11 @@ void addType(Storage::Synchronization::Types &types, QmlTypesParser::ProjectStorage &storage, const ComponentWithoutNamespaces &componentNameWithoutNamespace) { + NanotraceHR::Tracer tracer{"add type"_t, + category(), + keyValue("source id", sourceId), + keyValue("module id", cppModuleId)}; + const auto &component = *exportScope.scope; auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals( @@ -421,7 +451,7 @@ void addType(Storage::Synchronization::Types &types, auto exports = exportScope.exports; auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations); - types.emplace_back( + const auto &type = types.emplace_back( Utils::SmallStringView{typeName}, Storage::Synchronization::ImportedType{TypeNameString{component.baseTypeName()}}, Storage::Synchronization::ImportedType{TypeNameString{component.extensionTypeName()}}, @@ -431,24 +461,61 @@ void addType(Storage::Synchronization::Types &types, createProperties(component.ownProperties(), enumerationTypes, componentNameWithoutNamespace), std::move(functionsDeclarations), std::move(signalDeclarations), - createEnumeration(enumerations)); + createEnumeration(enumerations), + Storage::Synchronization::ChangeLevel::Full, + Utils::SmallString{component.ownDefaultPropertyName()}); + tracer.end(keyValue("type", type)); +} + +using namespace Qt::StringLiterals; + +constexpr auto skipLists = std::make_tuple( + std::pair{std::pair{"QtQuick.Templates"_sv, ModuleKind::CppLibrary}, std::array{"QQuickItem"_L1}}); + +Utils::span<const QLatin1StringView> getSkipList(const Storage::Module &module) +{ + static constexpr Utils::span<const QLatin1StringView> emptySkipList; + auto currentSkipList = emptySkipList; + + std::apply( + [&](const auto &entry) { + if (entry.first.first == module.name && entry.first.second == module.kind) + currentSkipList = entry.second; + }, + skipLists); + + return currentSkipList; +} + +bool skipType(const QQmlJSExportedScope &object, Utils::span<const QLatin1StringView> skipList) +{ + return std::any_of(skipList.begin(), skipList.end(), [&](const QLatin1StringView skip) { + return object.scope->internalName() == skip; + }); } void addTypes(Storage::Synchronization::Types &types, - const Storage::Synchronization::ProjectData &projectData, + const Storage::Synchronization::DirectoryInfo &directoryInfo, const QList<QQmlJSExportedScope> &objects, QmlTypesParser::ProjectStorage &storage, const ComponentWithoutNamespaces &componentNameWithoutNamespaces) { + NanotraceHR::Tracer tracer{"add types"_t, category()}; types.reserve(Utils::usize(objects) + types.size()); - for (const auto &object : objects) + const auto skipList = getSkipList(storage.module(directoryInfo.moduleId)); + + for (const auto &object : objects) { + if (skipType(object, skipList)) + continue; + addType(types, - projectData.sourceId, - projectData.moduleId, + directoryInfo.sourceId, + directoryInfo.moduleId, object, storage, componentNameWithoutNamespaces); + } } } // namespace @@ -456,8 +523,10 @@ void addTypes(Storage::Synchronization::Types &types, void QmlTypesParser::parse(const QString &sourceContent, Storage::Imports &imports, Storage::Synchronization::Types &types, - const Storage::Synchronization::ProjectData &projectData) + const Storage::Synchronization::DirectoryInfo &directoryInfo) { + NanotraceHR::Tracer tracer{"qmltypes parser parse"_t, category()}; + QQmlJSTypeDescriptionReader reader({}, sourceContent); QList<QQmlJSExportedScope> components; QStringList dependencies; @@ -467,8 +536,8 @@ void QmlTypesParser::parse(const QString &sourceContent, auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components); - addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId); - addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces); + addImports(imports, directoryInfo.sourceId, dependencies, m_storage, directoryInfo.moduleId); + addTypes(types, directoryInfo, components, m_storage, componentNameWithoutNamespaces); } #else @@ -476,7 +545,7 @@ void QmlTypesParser::parse(const QString &sourceContent, void QmlTypesParser::parse([[maybe_unused]] const QString &sourceContent, [[maybe_unused]] Storage::Imports &imports, [[maybe_unused]] Storage::Synchronization::Types &types, - [[maybe_unused]] const Storage::Synchronization::ProjectData &projectData) + [[maybe_unused]] const Storage::Synchronization::DirectoryInfo &directoryInfo) {} #endif diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h index 7c41925f30..c73a429f91 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h @@ -4,6 +4,7 @@ #pragma once #include "nonlockingmutex.h" +#include "projectstoragefwd.h" #include "qmltypesparserinterface.h" namespace Sqlite { @@ -12,17 +13,13 @@ class Database; namespace QmlDesigner { -template<typename Database> -class ProjectStorage; - template<typename ProjectStorage, typename Mutex> class SourcePathCache; class QmlTypesParser final : public QmlTypesParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>; - + using ProjectStorage = QmlDesigner::ProjectStorage; #ifdef QDS_BUILD_QMLPARSER QmlTypesParser(ProjectStorage &storage) : m_storage{storage} @@ -34,7 +31,7 @@ public: void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Synchronization::Types &types, - const Storage::Synchronization::ProjectData &projectData) override; + const Storage::Synchronization::DirectoryInfo &directoryInfo) override; private: #ifdef QDS_BUILD_QMLPARSER diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h index cdc7cd54d7..c0880cf5c6 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h @@ -15,7 +15,7 @@ public: virtual void parse(const QString &sourceContent, Storage::Imports &imports, Storage::Synchronization::Types &types, - const Storage::Synchronization::ProjectData &projectData) + const Storage::Synchronization::DirectoryInfo &directoryInfo) = 0; protected: diff --git a/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h b/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h index 837e58d48a..fa550a4d52 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h @@ -7,6 +7,8 @@ #include <utils/smallstring.h> +#include <QVarLengthArray> + namespace QmlDesigner { class SourcePath : public Utils::PathString @@ -117,10 +119,17 @@ public: std::ptrdiff_t slashIndex() const { return m_slashIndex; } + template<typename String> + friend void convertToString(String &string, const SourcePath &path) + { + convertToString(string, path.toStringView()); + } + private: std::ptrdiff_t m_slashIndex = -1; }; using SourcePaths = std::vector<SourcePath>; - +template<std::size_t size> +using SmallSourcePaths = QVarLengthArray<SourcePath, size>; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h index 5feaf30d00..1ef8ba7f21 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h @@ -125,4 +125,6 @@ public: SourceContextId sourceContextId; }; +using SourceNameAndSourceContextIds = std::vector<SourceNameAndSourceContextId>; + } // namespace QmlDesigner::Cache diff --git a/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h b/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h index 85c6147d2c..32ecb1c3f7 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h @@ -313,7 +313,7 @@ private: return entries.end(); } - auto value = *found; + const auto &value = *found; if (value == view) { return found; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp index b829e9db36..71eba94966 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp @@ -27,11 +27,11 @@ constexpr auto propertyElementName = "Property"_L1; constexpr auto extraFileElementName = "ExtraFile"_L1; } // namespace -Synchronization::TypeAnnotations TypeAnnotationReader::parseTypeAnnotation(const QString &content, - const QString &directoryPath, - SourceId sourceId) +Synchronization::TypeAnnotations TypeAnnotationReader::parseTypeAnnotation( + const QString &content, const QString &directoryPath, SourceId sourceId, SourceId directorySourceId) { m_sourceId = sourceId; + m_directorySourceId = directorySourceId; m_directoryPath = directoryPath; m_parserState = ParsingDocument; if (!SimpleAbstractStreamReader::readFromSource(content)) { @@ -178,8 +178,15 @@ TypeAnnotationReader::ParserSate TypeAnnotationReader::readDocument(const QStrin TypeAnnotationReader::ParserSate TypeAnnotationReader::readMetaInfoRootElement(const QString &name) { if (name == typeElementName) { - m_typeAnnotations.emplace_back(m_sourceId); + auto &annotation = m_typeAnnotations.emplace_back(m_sourceId, m_directorySourceId); + annotation.traits.canBeDroppedInFormEditor = FlagIs::True; + annotation.traits.canBeDroppedInNavigator = FlagIs::True; + annotation.traits.isMovable = FlagIs::True; + annotation.traits.isResizable = FlagIs::True; + annotation.traits.hasFormEditorItem = FlagIs::True; + annotation.traits.visibleInLibrary = FlagIs::True; m_itemLibraryEntries = json::array(); + return ParsingType; } else { addErrorInvalidType(name); @@ -258,7 +265,8 @@ void TypeAnnotationReader::readTypeProperty(QStringView name, const QVariant &va auto [moduleName, typeName] = decomposeTypePath(fullTypeName); m_typeAnnotations.back().typeName = typeName; - m_typeAnnotations.back().moduleId = m_projectStorage.moduleId(moduleName); + m_typeAnnotations.back().moduleId = m_projectStorage.moduleId(moduleName, + ModuleKind::QmlLibrary); } else if (name == "icon"_L1) { m_typeAnnotations.back().iconPath = absoluteFilePathForDocument(value.toString()); @@ -277,7 +285,7 @@ void TypeAnnotationReader::readItemLibraryEntryProperty(QStringView name, const } else if (name == "category"_L1) { m_itemLibraryEntries.back()["category"] = value; } else if (name == "libraryIcon"_L1) { - m_itemLibraryEntries.back()["iconPath"] = value; + m_itemLibraryEntries.back()["iconPath"] = absoluteFilePathForDocument(variant.toString()); } else if (name == "version"_L1) { // setVersion(value.toString()); } else if (name == "requiredImport"_L1) { @@ -304,7 +312,7 @@ QString deEscape(const QString &value) QVariant deEscapeVariant(const QVariant &value) { - if (value.typeId() == QVariant::String) + if (value.typeId() == QMetaType::QString) return deEscape(value.toString()); return value; } @@ -427,8 +435,8 @@ void TypeAnnotationReader::setVersion(const QString &versionNumber) int minor = 0; if (!versionNumber.isEmpty()) { - int val; - bool ok; + int val = -1; + bool ok = false; if (versionNumber.contains('.'_L1)) { val = versionNumber.split('.'_L1).constFirst().toInt(&ok); major = ok ? val : major; @@ -459,9 +467,9 @@ using json = nlohmann::json; out = json::array({}); out.push_back(property.name); out.push_back(property.type); - if (property.value.type() == QVariant::String) + if (property.value.typeId() == QMetaType::QString) out.push_back(Utils::PathString{property.value.toString()}); - else if (property.value.type() == QVariant::Int || property.value.type() == QVariant::LongLong) + else if (property.value.typeId() == QMetaType::Int || property.value.typeId() == QMetaType::LongLong) out.push_back(property.value.toLongLong()); else out.push_back(property.value.toDouble()); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h index 9332d5bed9..a320493ee2 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h @@ -49,7 +49,8 @@ public: Synchronization::TypeAnnotations parseTypeAnnotation(const QString &content, const QString &directoryPath, - SourceId sourceId); + SourceId sourceId, + SourceId directorySourceId); QStringList errors(); @@ -124,6 +125,7 @@ private: json m_itemLibraryEntries; Property m_currentProperty; SourceId m_sourceId; + SourceId m_directorySourceId; }; } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp index d49c6156a6..cbe7b0ec38 100644 --- a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp +++ b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp @@ -3,40 +3,48 @@ #include "qmldesignertracing.h" +#include <sqlitebasestatement.h> + namespace QmlDesigner { + +using namespace NanotraceHR::Literals; + namespace Tracing { namespace { using TraceFile = NanotraceHR::TraceFile<tracingStatus()>; -TraceFile &traceFile() +auto &traceFile() { - static TraceFile traceFile{"qml_designer.json"}; - return traceFile; + if constexpr (std::is_same_v<Sqlite::TraceFile, TraceFile>) { + return Sqlite::traceFile(); + } else { + static TraceFile traceFile{"tracing.json"}; + return traceFile; + } } } // namespace EventQueue &eventQueue() { - thread_local NanotraceHR::EventQueueData<NanotraceHR::StringViewTraceEvent, 10000, tracingStatus()> - stringViewEventQueueData(traceFile()); + thread_local NanotraceHR::EventQueue<NanotraceHR::StringViewTraceEvent, tracingStatus()> + stringViewEventQueue(traceFile()); - return stringViewEventQueueData; + return stringViewEventQueue; } EventQueueWithStringArguments &eventQueueWithStringArguments() { - thread_local NanotraceHR:: - EventQueueData<NanotraceHR::StringViewWithStringArgumentsTraceEvent, 1000, tracingStatus()> - stringViewWithStringArgumentsEventQueueData(traceFile()); + thread_local NanotraceHR::EventQueue<NanotraceHR::StringViewWithStringArgumentsTraceEvent, tracingStatus()> + stringViewWithStringArgumentsEventQueue(traceFile()); - return stringViewWithStringArgumentsEventQueueData; + return stringViewWithStringArgumentsEventQueue; } StringEventQueue &stringEventQueue() { - thread_local NanotraceHR::EventQueueData<NanotraceHR::StringTraceEvent, 1000, tracingStatus()> eventQueue( + thread_local NanotraceHR::EventQueue<NanotraceHR::StringTraceEvent, tracingStatus()> eventQueue( traceFile()); return eventQueue; @@ -46,7 +54,6 @@ StringEventQueue &stringEventQueue() namespace ModelTracing { namespace { -using namespace NanotraceHR::Literals; thread_local Category category_{"model"_t, Tracing::stringEventQueue(), category}; @@ -58,4 +65,36 @@ Category &category() } } // namespace ModelTracing + +namespace ProjectStorageTracing { + +Category &projectStorageCategory() +{ + thread_local Category category{"project storage"_t, + Tracing::eventQueueWithStringArguments(), + projectStorageCategory}; + + return category; +} + +Category &projectStorageUpdaterCategory() +{ + thread_local Category category{"project storage updater"_t, + Tracing::eventQueueWithStringArguments(), + projectStorageCategory}; + + return category; +} + +} // namespace ProjectStorageTracing + +namespace MetaInfoTracing { +Category &category() +{ + thread_local Category category_{"meta info"_t, Tracing::eventQueueWithStringArguments(), category}; + + return category_; +} +} // namespace MetaInfoTracing + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h index 31058260d6..899ceb6cd2 100644 --- a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h +++ b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h @@ -44,4 +44,38 @@ using AsynchronousToken = Category::AsynchronousTokenType; [[gnu::pure]] QMLDESIGNERCORE_EXPORT Category &category(); } // namespace ModelTracing + +namespace ProjectStorageTracing { +constexpr NanotraceHR::Tracing projectStorageTracingStatus() +{ +#ifdef ENABLE_PROJECT_STORAGE_TRACING + return NanotraceHR::Tracing::IsEnabled; +#else + return NanotraceHR::Tracing::IsDisabled; +#endif +} + +using Category = NanotraceHR::StringViewWithStringArgumentsCategory<projectStorageTracingStatus()>; + +[[gnu::pure]] Category &projectStorageCategory(); + +[[gnu::pure]] Category &projectStorageUpdaterCategory(); + +} // namespace ProjectStorageTracing + +namespace MetaInfoTracing { +constexpr NanotraceHR::Tracing tracingStatus() +{ +#ifdef ENABLE_METAINFO_TRACING + return NanotraceHR::Tracing::IsEnabled; +#else + return NanotraceHR::Tracing::IsDisabled; +#endif +} + +using Category = NanotraceHR::StringViewWithStringArgumentsCategory<tracingStatus()>; + +[[gnu::pure]] Category &category(); + +} // namespace MetaInfoTracing } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/uniquename.cpp b/src/plugins/qmldesigner/designercore/uniquename.cpp new file mode 100644 index 0000000000..d7506164db --- /dev/null +++ b/src/plugins/qmldesigner/designercore/uniquename.cpp @@ -0,0 +1,165 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "uniquename.h" + +#include <utils/span.h> + +#include <QFileInfo> +#include <QRegularExpression> + +namespace QmlDesigner::UniqueName { + +using namespace Qt::Literals; + +constexpr QLatin1StringView keywords[] { + "anchors"_L1, "as"_L1, "baseState"_L1, + "border"_L1, "bottom"_L1, "break"_L1, + "case"_L1, "catch"_L1, "clip"_L1, + "color"_L1, "continue"_L1, "data"_L1, + "debugger"_L1, "default"_L1, "delete"_L1, + "do"_L1, "else"_L1, "enabled"_L1, + "finally"_L1, "flow"_L1, "focus"_L1, + "font"_L1, "for"_L1, "function"_L1, + "height"_L1, "if"_L1, "import"_L1, + "in"_L1, "instanceof"_L1, "item"_L1, + "layer"_L1, "left"_L1, "margin"_L1, + "new"_L1, "opacity"_L1, "padding"_L1, + "parent"_L1, "print"_L1, "rect"_L1, + "return"_L1, "right"_L1, "scale"_L1, + "shaderInfo"_L1, "source"_L1, "sprite"_L1, + "spriteSequence"_L1, "state"_L1, "switch"_L1, + "text"_L1, "this"_L1, "throw"_L1, + "top"_L1, "try"_L1, "typeof"_L1, + "var"_L1, "visible"_L1, "void"_L1, + "while"_L1, "with"_L1, "x"_L1, + "y"_L1 +}; + +namespace { + +QString toCamelCase(const QString &input) +{ + QString result = input.at(0).toLower(); + bool capitalizeNext = false; + + for (const QChar &c : Utils::span{input}.subspan(1)) { + bool isValidChar = c.isLetterOrNumber() || c == '_'; + if (isValidChar) + result += capitalizeNext ? c.toUpper() : c; + + capitalizeNext = !isValidChar; + } + + return result; +} + +} // namespace + +/** + * @brief Generates a unique name based on the provided name. + * + * This method iteratively generates a name by appending suffixes until a unique name is found. + * The uniqueness of the generated name is determined by the provided predicate function. + * + * @param name The original name to be made unique. + * @param predicate A function that checks if a name exists. Returns true if the name exists, + * false if name is unique. + * @return A unique name derived from the provided name. + */ +QString generate(const QString &name, std::function<bool(const QString &)> predicate) +{ + if (!predicate(name)) + return name; + + // match prefix and number (including zero padding) parts + static QRegularExpression rgx("(\\D*?)(\\d+)$"); + QRegularExpressionMatch match = rgx.match(name); + + QString prefix; + int number = 0; + int padding = 0; + + if (match.hasMatch()) { + // Split the name into prefix and number + prefix = match.captured(1); + QString numberStr = match.captured(2); + number = numberStr.toInt(); + padding = numberStr.size(); + } else { + prefix = name; + } + + QString nameTemplate = "%1%2"; + QString newName; + do { + newName = nameTemplate.arg(prefix).arg(++number, padding, 10, QChar('0')); + } while (predicate(newName)); + + return newName; +} + +/** + * @brief Generates a unique path based on the provided path. If the path belongs to a file, the + * filename or if it's a directory, the directory name will be adjusted to ensure uniqueness. + * + * This method appends a numerical suffix (or increment it if it exists) to the filename or + * directory name if necessary to make it unique. + * + * @param path The original path to be made unique. + * @return A unique path derived from the provided path. + */ +QString generatePath(const QString &path) +{ + // Remove the trailing slash if it exists (otherwise QFileInfo::path() returns empty) + QString adjustedPath = path; + if (adjustedPath.endsWith('/')) + adjustedPath.chop(1); + + QFileInfo fileInfo = QFileInfo(adjustedPath); + QString baseName = fileInfo.baseName(); + QString suffix = fileInfo.completeSuffix(); + if (!suffix.isEmpty()) + suffix.prepend('.'); + + QString parentDir = fileInfo.path(); + QString pathTemplate = parentDir + "/%1" + suffix; + + QString uniqueBaseName = UniqueName::generate(baseName, [&] (const QString &currName) { + return QFileInfo::exists(pathTemplate.arg(currName)); + }); + + return pathTemplate.arg(uniqueBaseName); +} + +/** + * @brief Generates a unique ID based on the provided id + * + * This works similar to get() with additional restrictions: + * - Removes non-Latin1 characters + * - Removes spaces + * - Ensures the first letter is lowercase + * - Converts spaces to camel case + * - Prepends an underscore if id starts with a number or is a reserved word + * + * @param id The original id to be made unique. + * @return A unique Id (when predicate() returns false) + */ +QString generateId(const QString &id, std::function<bool(const QString &)> predicate) +{ + // remove non word (non A-Z, a-z, 0-9) or space characters + QString newId = id.trimmed(); + + newId = toCamelCase(newId); + + // prepend _ if starts with a digit or invalid id (such as reserved words) + if (newId.at(0).isDigit() || std::binary_search(std::begin(keywords), std::end(keywords), newId)) + newId.prepend('_'); + + if (!predicate) + return newId; + + return UniqueName::generate(newId, predicate); +} + +} // namespace QmlDesigner::UniqueName diff --git a/src/plugins/qmldesigner/designercore/uniquename.h b/src/plugins/qmldesigner/designercore/uniquename.h new file mode 100644 index 0000000000..85927c4514 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/uniquename.h @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include <qmldesignercorelib_exports.h> + +#include <QString> + +namespace QmlDesigner::UniqueName { + +QString generate(const QString &name, std::function<bool(const QString &)> predicate); +QString generatePath(const QString &path); +QMLDESIGNERCORE_EXPORT QString generateId(const QString &id, + std::function<bool(const QString &)> predicate = {}); + +} // namespace QmlDesigner::UniqueName |