diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp index 1a46a30c1f2..37dc5189379 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp @@ -18,6 +18,7 @@ enum class SpecialIdState { Unresolved = -1 }; constexpr TypeId unresolvedTypeId = TypeId::createSpecialState(SpecialIdState::Unresolved); +namespace { class UnresolvedTypeId : public TypeId { public: @@ -33,6 +34,25 @@ public: } }; +auto createSingletonTypeTraitMask() +{ + Storage::TypeTraits traits; + traits.type = 0; + traits.isSingleton = true; + + return traits.type; +} + +auto createSingletonTraitsExpression() +{ + Utils::SmallString traitsExpression = "traits & "; + traitsExpression.append(Utils::SmallString::number(createSingletonTypeTraitMask())); + + return traitsExpression; +} + +} // namespace + struct ProjectStorage::Statements { Statements(Sqlite::Database &database) @@ -874,6 +894,14 @@ struct ProjectStorage::Statements " propertyImportedTypeNameId IS NULL " "LIMIT 1", database}; + mutable Sqlite::ReadStatement<1, 1> selectSingletonTypeIdsBySourceIdStatement{ + "SELECT DISTINCT typeId " + "FROM types " + " JOIN exportedTypeNames USING (typeId) " + " JOIN documentImports AS di USING(moduleId) " + "WHERE di.sourceId=?1 AND " + + createSingletonTraitsExpression(), + database}; }; class ProjectStorage::Initializer @@ -909,7 +937,7 @@ public: 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 &traitsColumn = typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer); auto &prototypeIdColumn = typesTable.addColumn("prototypeId", Sqlite::StrictColumnType::Integer); auto &prototypeNameIdColumn = typesTable.addColumn("prototypeNameId", @@ -927,6 +955,9 @@ public: typesTable.addIndex({extensionIdColumn, sourceIdColumn}); typesTable.addIndex({prototypeNameIdColumn}); typesTable.addIndex({extensionNameIdColumn}); + Utils::SmallString traitsExpression = "traits & "; + traitsExpression.append(Utils::SmallString::number(createSingletonTypeTraitMask())); + typesTable.addIndex({traitsColumn}, traitsExpression); typesTable.initialize(database); @@ -1453,8 +1484,23 @@ QVarLengthArray ProjectStorage::typeIds(ModuleId moduleId) const projectStorageCategory(), keyValue("module id", moduleId)}; - auto typeIds = s->selectTypeIdsByModuleIdStatement - .valuesWithTransaction>(moduleId); + auto typeIds = s->selectTypeIdsByModuleIdStatement.valuesWithTransaction>( + moduleId); + + tracer.end(keyValue("type ids", typeIds)); + + return typeIds; +} + +SmallTypeIds<256> ProjectStorage::singletonTypeIds(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get singleton type ids by source id", + projectStorageCategory(), + keyValue("source id", sourceId)}; + + auto typeIds = s->selectSingletonTypeIdsBySourceIdStatement.valuesWithTransaction>( + sourceId); tracer.end(keyValue("type ids", typeIds)); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h index b98ffcfece2..b3723bfa01d 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h @@ -70,7 +70,9 @@ public: TypeId typeId(ImportedTypeNameId typeNameId) const override; - QVarLengthArray typeIds(ModuleId moduleId) const override; + SmallTypeIds<256> typeIds(ModuleId moduleId) const override; + + SmallTypeIds<256> singletonTypeIds(SourceId sourceId) const override; Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h index 4d840d2a5c5..69674ffc8bf 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h @@ -40,7 +40,8 @@ public: Storage::Version version) const = 0; virtual TypeId typeId(ImportedTypeNameId typeNameId) const = 0; - virtual QVarLengthArray typeIds(ModuleId moduleId) const = 0; + virtual SmallTypeIds<256> typeIds(ModuleId moduleId) const = 0; + virtual SmallTypeIds<256> singletonTypeIds(SourceId sourceId) const = 0; virtual Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const = 0; virtual Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, SourceId sourceId) const diff --git a/tests/unit/tests/mocks/projectstoragemock.h b/tests/unit/tests/mocks/projectstoragemock.h index 9e06db5aef5..6131924db16 100644 --- a/tests/unit/tests/mocks/projectstoragemock.h +++ b/tests/unit/tests/mocks/projectstoragemock.h @@ -153,10 +153,14 @@ public: ::Utils::SmallStringView exportedTypeName, QmlDesigner::Storage::Version version), (const, override)); - MOCK_METHOD((QVarLengthArray), + MOCK_METHOD((QmlDesigner::SmallTypeIds<256>), typeIds, (QmlDesigner::ModuleId moduleId), (const, override)); + MOCK_METHOD((QmlDesigner::SmallTypeIds<256>), + singletonTypeIds, + (QmlDesigner::SourceId sourceId), + (const, override)); MOCK_METHOD(QmlDesigner::Storage::Info::ExportedTypeNames, exportedTypeNames, (QmlDesigner::TypeId), diff --git a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp index 521381aa840..45b7e146756 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp @@ -8835,4 +8835,52 @@ TEST_F(ProjectStorage, changed_export_is_notifing_changed_exported_types) storage.synchronize(std::move(package)); } + +TEST_F(ProjectStorage, get_unqiue_singleton_type_ids) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.back().traits.isSingleton = true; + Storage::Imports imports; + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); + storage.synchronizeDocumentImports(imports, sourceId5); + storage.synchronize(package); + + auto singletonTypeIds = storage.singletonTypeIds(sourceId5); + + ASSERT_THAT(singletonTypeIds, ElementsAre(fetchTypeId(sourceId2, "QObject"))); +} + +TEST_F(ProjectStorage, get_only_singleton_type_ids_for_document_imports) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.back().traits.isSingleton = true; + package.types.front().traits.isSingleton = true; + Storage::Imports imports; + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); + storage.synchronizeDocumentImports(imports, sourceId5); + storage.synchronize(package); + + auto singletonTypeIds = storage.singletonTypeIds(sourceId5); + + ASSERT_THAT(singletonTypeIds, ElementsAre(fetchTypeId(sourceId1, "QQuickItem"))); +} + +TEST_F(ProjectStorage, get_only_singleton_type_ids_exported_types) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.back().traits.isSingleton = true; + package.types.back().exportedTypes.clear(); + package.types.front().traits.isSingleton = true; + Storage::Imports imports; + imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5); + imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5); + storage.synchronizeDocumentImports(imports, sourceId5); + storage.synchronize(package); + + auto singletonTypeIds = storage.singletonTypeIds(sourceId5); + + ASSERT_THAT(singletonTypeIds, ElementsAre(fetchTypeId(sourceId1, "QQuickItem"))); +} + } // namespace