diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 1adfd70245b..058bee2f053 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -469,6 +469,7 @@ private: , column(column) {} + explicit operator bool() const { return statement.fetchIntValue(column); } operator int() const { return statement.fetchIntValue(column); } operator long() const { return statement.fetchLongValue(column); } operator long long() const { return statement.fetchLongLongValue(column); } diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 6afdedf6f6f..752ad8fe842 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -245,11 +245,17 @@ public: .template valuesWithTransaction(16, type); } - PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, - Utils::SmallStringView name) + template + bool isBasedOn(TypeId typeId, TypeIds... baseTypeIds) const { - return selectPropertyDeclarationIdByTypeIdAndNameStatement - .template valueWithTransaction(typeId, name); + auto range = selectPrototypeAndSelfIdsStatement.template rangeWithTransaction(typeId); + + for (TypeId currentTypeId : range) { + if (((currentTypeId == baseTypeIds) || ...)) + return true; + } + + return false; } TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const @@ -2635,7 +2641,6 @@ public: "ORDER BY minorVersion DESC " "LIMIT 1", database}; - mutable ReadStatement<1, 2> selectPrototypeIdStatement{ "WITH RECURSIVE " " all_prototype_and_extension(typeId, prototypeId) AS (" @@ -3259,6 +3264,19 @@ public: " typeChain AS tc USING(typeId)) " "SELECT typeId FROM typeChain ORDER BY level", database}; + mutable ReadStatement<1, 1> selectPrototypeAndSelfIdsStatement{ + "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", + database}; }; extern template class ProjectStorage; } // namespace QmlDesigner diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index f7734ed00af..345f4994554 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -6771,8 +6771,7 @@ TEST_F(ProjectStorage, GetPrototypeIdsWithExtension) auto prototypeIds = storage.prototypeIds(typeId); ASSERT_THAT(prototypeIds, - ElementsAre(fetchTypeId(sourceId1, "QObject2"), - fetchTypeId(sourceId1, "QObject"))); + ElementsAre(fetchTypeId(sourceId1, "QObject2"), fetchTypeId(sourceId1, "QObject"))); } TEST_F(ProjectStorage, GetPrototypeAndSelfIds) @@ -6815,4 +6814,91 @@ TEST_F(ProjectStorage, GetPrototypeAndSelfIdsWithExtension) fetchTypeId(sourceId1, "QObject"))); } +TEST_F(ProjectStorage, IsBaseOfForDirectPrototype) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject2"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject"); + auto baseTypeId2 = fetchTypeId(sourceId1, "QObject3"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId, baseTypeId2, TypeId{}); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(ProjectStorage, IsBaseOfForIndirectPrototype) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(ProjectStorage, IsBaseOfForDirectExtension) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject2"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(ProjectStorage, IsBaseOfForIndirectExtension) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(ProjectStorage, IsBaseOfForSelf) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject2"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject2"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId); + + ASSERT_TRUE(isBasedOn); +} + +TEST_F(ProjectStorage, IsNotBaseOf) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject"); + auto baseTypeId = fetchTypeId(sourceId1, "QObject2"); + auto baseTypeId2 = fetchTypeId(sourceId1, "QObject3"); + + bool isBasedOn = storage.isBasedOn(typeId, baseTypeId, baseTypeId2, TypeId{}); + + ASSERT_FALSE(isBasedOn); +} + +TEST_F(ProjectStorage, IsNotBaseOfIfNoBaseTypeIsGiven) +{ + auto package{createPackageWithProperties()}; + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject"); + + bool isBasedOn = storage.isBasedOn(typeId); + + ASSERT_FALSE(isBasedOn); +} + } // namespace