diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 2f3dd74d31c..f877afeb6fc 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -73,6 +73,9 @@ public: for (auto &&type : types) syncType(type); + for (auto &&type : types) + synchronizeAliasPropertyDeclarations(type); + deleteNotUpdatedTypes(updatedTypeIds, sourceIds); transaction.commit(); @@ -119,7 +122,7 @@ public: PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, Utils::SmallStringView name) { - return selectPropertyDeclarationByTypeIdAndNameStatement + return selectPropertyDeclarationIdByTypeIdAndNameStatement .template valueWithTransaction(&typeId, name); } @@ -485,7 +488,7 @@ private: auto insert = [&](const Storage::PropertyDeclaration &value) { auto propertyTypeId = fetchTypeIdByNameUngarded(value.typeName, importIds); - insertPropertyDeclarationStatement.write(&typeId, + upsertPropertyDeclarationStatement.write(&typeId, value.name, &propertyTypeId, static_cast(value.traits)); @@ -510,6 +513,56 @@ private: Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove); } + void synchronizeAliasPropertyDeclarations(Storage::Type &type) + { + auto &aliasDeclarations = type.aliasDeclarations; + TypeId typeId = type.typeId; + ImportIds &importIds = type.importIds; + + std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) { + return Sqlite::compare(first.name, second.name) < 0; + }); + + auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement + .template range(&typeId); + + auto compareKey = [](const Storage::AliasPropertyDeclarationView &view, + const Storage::AliasPropertyDeclaration &value) { + return Sqlite::compare(view.name, value.name); + }; + + auto insert = [&](const Storage::AliasPropertyDeclaration &value) { + auto [aliasTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeNameAndName( + value.aliasTypeName, value.aliasPropertyName, importIds); + + insertPropertyDeclarationWithAliasStatement.write(&typeId, + value.name, + &aliasTypeId, + propertyTraits, + &aliasId); + }; + + auto update = [&](const Storage::AliasPropertyDeclarationView &view, + const Storage::AliasPropertyDeclaration &value) { + auto [aliasTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeNameAndName( + value.aliasTypeName, value.aliasPropertyName, importIds); + + if (view.aliasId == aliasId) + return; + + updatePropertyDeclarationWithAliasStatement.write(&view.id, + &aliasTypeId, + propertyTraits, + &aliasId); + }; + + auto remove = [&](const Storage::AliasPropertyDeclarationView &view) { + deletePropertyDeclarationStatement.write(&view.id); + }; + + Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove); + } + Utils::PathString createJson(const Storage::ParameterDeclarations ¶meters) { Utils::PathString json; @@ -524,7 +577,7 @@ private: json.append(parameter.name); json.append("\",\"tn\":\""); json.append(parameter.typeName); - if (parameter.traits == Storage::DeclarationTraits::Non) { + if (parameter.traits == Storage::PropertyDeclarationTraits::Non) { json.append("\"}"); } else { json.append("\",\"tr\":"); @@ -748,6 +801,22 @@ private: throw TypeNameDoesNotExists{}; } + using PropertyDeclarationViewTuple = std::tuple; + + PropertyDeclarationViewTuple fetchPropertyDeclarationByTypeNameAndName( + const Storage::TypeName &typeName, Utils::SmallStringView name, ImportIds &importIds) + { + TypeId typeId = fetchTypeIdByNameUngarded(typeName, importIds); + + auto propertyDeclaration = selectPropertyDeclarationByTypeIdAndNameStatement + .template value(&typeId, name); + + if (auto id = std::get(propertyDeclaration); id) + return propertyDeclaration; + + throw PropertyNameDoesNotExists{}; + } + SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath) { return selectSourceContextIdFromSourceContextsBySourceContextPathStatement @@ -933,6 +1002,7 @@ private: Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::Restrict); propertyDeclarationTable.addColumn("propertyTraits"); + propertyDeclarationTable.addColumn("aliasPropertyDeclarationId"); propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); @@ -1056,13 +1126,7 @@ public: " SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) " "SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1", database}; - ReadWriteStatement<1> upsertPropertyDeclarationStatement{ - "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits) " - "VALUES(?1, ?2, ?3, nullif(?4, 0)) ON CONFLICT DO UPDATE SET typeId=excluded.typeId, " - "name=excluded.name, propertyTypeId=excluded.propertyTypeId, " - "propertyTraits=excluded.propertyTraits RETURNING propertyDeclarationId", - database}; - mutable ReadStatement<1> selectPropertyDeclarationByTypeIdAndNameStatement{ + mutable ReadStatement<1> selectPropertyDeclarationIdByTypeIdAndNameStatement{ "WITH RECURSIVE " " typeSelection(typeId) AS (" " VALUES(?1) " @@ -1071,6 +1135,16 @@ public: "SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) " " WHERE name=?2 LIMIT 1", database}; + mutable ReadStatement<3> selectPropertyDeclarationByTypeIdAndNameStatement{ + "WITH RECURSIVE " + " typeSelection(typeId) AS (" + " VALUES(?1) " + " UNION ALL " + " SELECT prototypeId FROM types JOIN typeSelection USING(typeId)) " + "SELECT typeId, propertyDeclarationId, propertyTraits FROM propertyDeclarations JOIN " + "typeSelection USING(typeId) " + " WHERE name=?2 LIMIT 1", + database}; WriteStatement upsertExportedTypesStatement{"INSERT INTO exportedTypes(importId, name, typeId) " "VALUES(?1, ?2, ?3) ON CONFLICT DO NOTHING", database}; @@ -1133,11 +1207,13 @@ public: database}; ReadStatement<4> selectPropertyDeclarationsForTypeIdStatement{ "SELECT name, propertyTraits, propertyTypeId, propertyDeclarationId FROM " - "propertyDeclarations WHERE typeId=? ORDER BY name", + "propertyDeclarations WHERE typeId=? AND aliasPropertyDeclarationId IS NULL ORDER BY " + "name", database}; - WriteStatement insertPropertyDeclarationStatement{ + WriteStatement upsertPropertyDeclarationStatement{ "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits) " - "VALUES(?1, ?2, ?3, ?4) ", + "VALUES(?1, ?2, ?3, ?4) ON CONFLICT DO UPDATE SET propertyTypeId=excluded.propertyTypeId, " + "propertyTraits=excluded.propertyTraits, aliasPropertyDeclarationId=NULL", database}; WriteStatement updatePropertyDeclarationStatement{ "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3 WHERE " @@ -1145,6 +1221,18 @@ public: database}; WriteStatement deletePropertyDeclarationStatement{ "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; + ReadStatement<3> selectPropertyDeclarationsWithAliasForTypeIdStatement{ + "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " + "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name", + database}; + WriteStatement insertPropertyDeclarationWithAliasStatement{ + "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, " + "aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5) ", + database}; + WriteStatement updatePropertyDeclarationWithAliasStatement{ + "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " + "aliasPropertyDeclarationId=?4 WHERE propertyDeclarationId=?1", + database}; mutable ReadStatement<4> selectFunctionDeclarationsForTypeIdStatement{ "SELECT name, returnTypeName, signature, functionDeclarationId FROM " "functionDeclarations WHERE typeId=? ORDER BY name", diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h index c47da14e735..aedfcca712f 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h @@ -83,4 +83,10 @@ public: const char *what() const noexcept override { return "The type name does not exist!"; } }; +class PropertyNameDoesNotExists : std::exception +{ +public: + const char *what() const noexcept override { return "The property name does not exist!"; } +}; + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 84af7d62f76..444d25f6bd8 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -36,19 +36,20 @@ namespace QmlDesigner::Storage { enum class TypeAccessSemantics : int { Invalid, Reference, Value, Sequence, IsEnum = 1 << 8 }; -enum class DeclarationTraits : unsigned int { +enum class PropertyDeclarationTraits : unsigned int { Non = 0, IsReadOnly = 1 << 0, IsPointer = 1 << 1, IsList = 1 << 2 }; -constexpr DeclarationTraits operator|(DeclarationTraits first, DeclarationTraits second) +constexpr PropertyDeclarationTraits operator|(PropertyDeclarationTraits first, + PropertyDeclarationTraits second) { - return static_cast(static_cast(first) | static_cast(second)); + return static_cast(static_cast(first) | static_cast(second)); } -constexpr bool operator&(DeclarationTraits first, DeclarationTraits second) +constexpr bool operator&(PropertyDeclarationTraits first, PropertyDeclarationTraits second) { return static_cast(first) & static_cast(second); } @@ -219,7 +220,7 @@ public: explicit ParameterDeclaration() = default; explicit ParameterDeclaration(Utils::SmallStringView name, Utils::SmallStringView typeName, - DeclarationTraits traits = {}) + PropertyDeclarationTraits traits = {}) : name{name} , typeName{typeName} , traits{traits} @@ -228,7 +229,7 @@ public: explicit ParameterDeclaration(Utils::SmallStringView name, Utils::SmallStringView typeName, int traits) : name{name} , typeName{typeName} - , traits{static_cast(traits)} + , traits{static_cast(traits)} {} friend bool operator==(const ParameterDeclaration &first, const ParameterDeclaration &second) @@ -240,7 +241,7 @@ public: public: Utils::SmallString name; Utils::SmallString typeName; - DeclarationTraits traits = {}; + PropertyDeclarationTraits traits = {}; }; using ParameterDeclarations = std::vector; @@ -345,7 +346,9 @@ class PropertyDeclaration { public: explicit PropertyDeclaration() = default; - explicit PropertyDeclaration(Utils::SmallStringView name, TypeName typeName, DeclarationTraits traits) + explicit PropertyDeclaration(Utils::SmallStringView name, + TypeName typeName, + PropertyDeclarationTraits traits) : name{name} , typeName{std::move(typeName)} , traits{traits} @@ -354,13 +357,13 @@ public: explicit PropertyDeclaration(Utils::SmallStringView name, Utils::SmallStringView typeName, int traits) : name{name} , typeName{NativeType{typeName}} - , traits{static_cast(traits)} + , traits{static_cast(traits)} {} public: Utils::SmallString name; TypeName typeName; - DeclarationTraits traits = {}; + PropertyDeclarationTraits traits = {}; TypeId typeId; }; @@ -374,7 +377,7 @@ public: long long typeId, long long id) : name{name} - , traits{static_cast(traits)} + , traits{static_cast(traits)} , typeId{typeId} , id{id} @@ -382,11 +385,45 @@ public: public: Utils::SmallStringView name; - DeclarationTraits traits = {}; + PropertyDeclarationTraits traits = {}; TypeId typeId; PropertyDeclarationId id; }; +class AliasPropertyDeclaration +{ +public: + explicit AliasPropertyDeclaration(Utils::SmallStringView name, + TypeName aliasTypeName, + Utils::SmallStringView aliasPropertyName) + : name{name} + , aliasTypeName{std::move(aliasTypeName)} + , aliasPropertyName{aliasPropertyName} + {} + +public: + Utils::SmallString name; + TypeName aliasTypeName; + Utils::SmallString aliasPropertyName; +}; + +using AliasDeclarations = std::vector; + +class AliasPropertyDeclarationView +{ +public: + explicit AliasPropertyDeclarationView(Utils::SmallStringView name, long long id, long long aliasId) + : name{name} + , id{id} + , aliasId{aliasId} + {} + +public: + Utils::SmallString name; + PropertyDeclarationId id; + PropertyDeclarationId aliasId; +}; + class Type { public: @@ -402,6 +439,7 @@ public: FunctionDeclarations functionDeclarations = {}, SignalDeclarations signalDeclarations = {}, EnumerationDeclarations enumerationDeclarations = {}, + AliasDeclarations aliasDeclarations = {}, TypeId typeId = TypeId{}) : typeName{typeName} , prototype{std::move(prototype)} @@ -411,6 +449,7 @@ public: , functionDeclarations{std::move(functionDeclarations)} , signalDeclarations{std::move(signalDeclarations)} , enumerationDeclarations{std::move(enumerationDeclarations)} + , aliasDeclarations{std::move(aliasDeclarations)} , accessSemantics{accessSemantics} , sourceId{sourceId} , typeId{typeId} @@ -454,6 +493,7 @@ public: FunctionDeclarations functionDeclarations; SignalDeclarations signalDeclarations; EnumerationDeclarations enumerationDeclarations; + AliasDeclarations aliasDeclarations; TypeAccessSemantics accessSemantics = TypeAccessSemantics::Invalid; SourceId sourceId; TypeId typeId; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index b1feeabe6b5..4aeeb0798de 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -1053,22 +1053,22 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD << "\", " << propertyDeclaration.traits << ", " << propertyDeclaration.typeId << ")"; } -std::ostream &operator<<(std::ostream &out, DeclarationTraits traits) +std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits) { const char *padding = ""; out << "("; - if (traits & DeclarationTraits::IsReadOnly) { + if (traits & PropertyDeclarationTraits::IsReadOnly) { out << "readonly"; padding = ", "; } - if (traits & DeclarationTraits::IsPointer) { + if (traits & PropertyDeclarationTraits::IsPointer) { out << padding << "pointer"; padding = ", "; } - if (traits & DeclarationTraits::IsList) + if (traits & PropertyDeclarationTraits::IsList) out << padding << "list"; return out << ")"; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index b1f899bfe2d..ee12f01a559 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -243,7 +243,7 @@ using TypeName = Utils::variant; class Version; class VersionNumber; enum class TypeAccessSemantics : int; -enum class DeclarationTraits : unsigned int; +enum class PropertyDeclarationTraits : unsigned int; class PropertyDeclaration; class FunctionDeclaration; class ParameterDeclaration; @@ -261,7 +261,7 @@ std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType); std::ostream &operator<<(std::ostream &out, const NativeType &nativeType); std::ostream &operator<<(std::ostream &out, const ExplicitExportedType &exportedType); std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyDeclaration); -std::ostream &operator<<(std::ostream &out, DeclarationTraits traits); +std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits); std::ostream &operator<<(std::ostream &out, const FunctionDeclaration &functionDeclaration); std::ostream &operator<<(std::ostream &out, const ParameterDeclaration ¶meter); std::ostream &operator<<(std::ostream &out, const SignalDeclaration &signalDeclaration); diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index 45f9902f448..c250b4c81ac 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -195,8 +195,6 @@ protected: ProjectStorageMock storage{databaseMock, true}; ReadWriteStatement<1> &upsertTypeStatement = storage.upsertTypeStatement; ReadStatement<1> &selectTypeIdByExportedNameStatement = storage.selectTypeIdByExportedNameStatement; - ReadWriteStatement<1> &upsertPropertyDeclarationStatement = storage.upsertPropertyDeclarationStatement; - ReadStatement<1> &selectPropertyDeclarationByTypeIdAndNameStatement = storage.selectPropertyDeclarationByTypeIdAndNameStatement; WriteStatement &upsertExportedTypesStatement = storage.upsertExportedTypesStatement; ReadStatement<1> &selectSourceContextIdFromSourceContextsBySourceContextPathStatement = storage.selectSourceContextIdFromSourceContextsBySourceContextPathStatement; @@ -423,7 +421,7 @@ TEST_F(ProjectStorage, FetchTypeByTypeIdCalls) TEST_F(ProjectStorage, FetchTypesCalls) { InSequence s; - Storage::Type type{ImportId{}, {}, {}, {}, SourceId{}, {}, {}, {}, {}, {}, {}, TypeId{55}}; + Storage::Type type{ImportId{}, {}, {}, {}, SourceId{}, {}, {}, {}, {}, {}, {}, {}, TypeId{55}}; Storage::Types types{type}; EXPECT_CALL(databaseMock, deferredBegin()); @@ -481,24 +479,28 @@ protected: {Storage::ExportedType{"Item"}}, {Storage::PropertyDeclaration{"data", Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsList}, + Storage::PropertyDeclarationTraits::IsList}, Storage::PropertyDeclaration{"children", Storage::ExportedType{"Item"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly}}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly}}, {Storage::FunctionDeclaration{"execute", "", {Storage::ParameterDeclaration{"arg", ""}}}, Storage::FunctionDeclaration{ "values", "Vector3D", {Storage::ParameterDeclaration{"arg1", "int"}, - Storage::ParameterDeclaration{"arg2", "QObject", Storage::DeclarationTraits::IsPointer}, + Storage::ParameterDeclaration{"arg2", + "QObject", + Storage::PropertyDeclarationTraits::IsPointer}, Storage::ParameterDeclaration{"arg3", "string"}}}}, {Storage::SignalDeclaration{"execute", {Storage::ParameterDeclaration{"arg", ""}}}, - Storage::SignalDeclaration{"values", - {Storage::ParameterDeclaration{"arg1", "int"}, - Storage::ParameterDeclaration{ - "arg2", "QObject", Storage::DeclarationTraits::IsPointer}, - Storage::ParameterDeclaration{"arg3", "string"}}}}, + Storage::SignalDeclaration{ + "values", + {Storage::ParameterDeclaration{"arg1", "int"}, + Storage::ParameterDeclaration{"arg2", + "QObject", + Storage::PropertyDeclarationTraits::IsPointer}, + Storage::ParameterDeclaration{"arg3", "string"}}}}, {Storage::EnumerationDeclaration{"Enum", {Storage::EnumeratorDeclaration{"Foo"}, Storage::EnumeratorDeclaration{"Bar", 32}}}, @@ -514,6 +516,34 @@ protected: {Storage::ExportedType{"Object"}, Storage::ExportedType{"Obj"}}}}; } + auto createTypesWithAliases() + { + auto types = createTypes(); + + types[1].propertyDeclarations.push_back( + Storage::PropertyDeclaration{"objects", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList}); + + types.push_back(Storage::Type{importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1, + importIds, + {Storage::ExportedType{"AliasItem"}}}); + types.back().propertyDeclarations.push_back( + Storage::PropertyDeclaration{"data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList}); + types.back().aliasDeclarations.push_back( + Storage::AliasPropertyDeclaration{"items", Storage::NativeType{"QQuickItem"}, "children"}); + types.back().aliasDeclarations.push_back( + Storage::AliasPropertyDeclaration{"objects", Storage::NativeType{"QQuickItem"}, "objects"}); + + return types; + } + auto createImports() { importSourceId1 = sourcePathCache.sourceId(importPath1); @@ -1089,21 +1119,22 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddPropertyDeclarations) storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsList), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration( + "children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, @@ -1141,21 +1172,22 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddPropertyDeclarationExplicitTyp storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QQuickObject"}, - Storage::DeclarationTraits::IsList), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QQuickObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration( + "children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesPropertyDeclarationType) @@ -1167,74 +1199,77 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesPropertyDeclarationType) storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration( + "children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesDeclarationTraits) { Storage::Types types{createTypes()}; storage.synchronizeTypes(types, {}); - types[0].propertyDeclarations[0].traits = Storage::DeclarationTraits::IsPointer; + types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsPointer), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsPointer), + IsPropertyDeclaration( + "children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesDeclarationTraitsAndType) { Storage::Types types{createTypes()}; storage.synchronizeTypes(types, {}); - types[0].propertyDeclarations[0].traits = Storage::DeclarationTraits::IsPointer; + types[0].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsPointer; types[0].propertyDeclarations[0].typeName = Storage::NativeType{"QQuickItem"}; storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsPointer), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsPointer), + IsPropertyDeclaration( + "children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesAPropertyDeclaration) @@ -1252,10 +1287,10 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemovesAPropertyDeclaration) TypeAccessSemantics::Reference, sourceId1), Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsList)))))); + UnorderedElementsAre(IsPropertyDeclaration( + "data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsAPropertyDeclaration) @@ -1265,29 +1300,30 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddsAPropertyDeclaration) types[0].propertyDeclarations.push_back( Storage::PropertyDeclaration{"object", Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsPointer}); + Storage::PropertyDeclarationTraits::IsPointer}); storage.synchronizeTypes(types, {}); - ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("object", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsPointer), - IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsList), - IsPropertyDeclaration("children", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + ASSERT_THAT( + storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("object", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsPointer), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration("children", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, SynchronizeTypesRenameAPropertyDeclaration) @@ -1299,21 +1335,22 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesRenameAPropertyDeclaration) storage.synchronizeTypes(types, {}); ASSERT_THAT(storage.fetchTypes(), - Contains(AllOf( - IsStorageType(importId2, - "QQuickItem", - Storage::NativeType{"QObject"}, - TypeAccessSemantics::Reference, - sourceId1), - Field(&Storage::Type::propertyDeclarations, - UnorderedElementsAre( - IsPropertyDeclaration("data", - Storage::NativeType{"QObject"}, - Storage::DeclarationTraits::IsList), - IsPropertyDeclaration("objects", - Storage::NativeType{"QQuickItem"}, - Storage::DeclarationTraits::IsList - | Storage::DeclarationTraits::IsReadOnly)))))); + Contains( + AllOf(IsStorageType(importId2, + "QQuickItem", + Storage::NativeType{"QObject"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration( + "objects", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly)))))); } TEST_F(ProjectStorageSlowTest, UsingNonExistingNativePropertyTypeThrows) @@ -1502,7 +1539,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesFunctionDeclarationChangeP { Storage::Types types{createTypes()}; storage.synchronizeTypes(types, {}); - types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage::DeclarationTraits::IsList; + types[0].functionDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; storage.synchronizeTypes(types, {}); @@ -1672,7 +1709,7 @@ TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangesSignalDeclarationChangePar { Storage::Types types{createTypes()}; storage.synchronizeTypes(types, {}); - types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::DeclarationTraits::IsList; + types[0].signalDeclarations[1].parameters[0].traits = QmlDesigner::Storage::PropertyDeclarationTraits::IsList; storage.synchronizeTypes(types, {}); @@ -2290,4 +2327,242 @@ TEST_F(ProjectStorageSlowTest, FetchImportDepencencyIdsForRootDepencency) ASSERT_THAT(importIds, ElementsAre(importId1)); } +TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarations) +{ + Storage::Types types{createTypesWithAliases()}; + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsAgain) +{ + Storage::Types types{createTypesWithAliases()}; + storage.synchronizeTypes(types, {}); + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesRemoveAliasDeclarations) +{ + Storage::Types types{createTypesWithAliases()}; + storage.synchronizeTypes(types, {}); + types[2].aliasDeclarations.pop_back(); + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWrongTypeName) +{ + Storage::Types types{createTypesWithAliases()}; + types[2].aliasDeclarations[0].aliasTypeName = Storage::NativeType{"QQuickItemWrong"}; + + ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::TypeNameDoesNotExists); +} +TEST_F(ProjectStorageSlowTest, SynchronizeTypesAddAliasDeclarationsThrowsForWrongPropertyName) +{ + Storage::Types types{createTypesWithAliases()}; + types[2].aliasDeclarations[0].aliasPropertyName = "childrenWrong"; + + ASSERT_THROW(storage.synchronizeTypes(types, {}), QmlDesigner::PropertyNameDoesNotExists); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsTypeName) +{ + Storage::Types types{createTypesWithAliases()}; + types.push_back(Storage::Type{importId1, + "QObject2", + Storage::NativeType{}, + TypeAccessSemantics::Reference, + sourceId2, + importIds, + {Storage::ExportedType{"Object2"}, Storage::ExportedType{"Obj2"}}}); + types[3].propertyDeclarations.push_back( + Storage::PropertyDeclaration{"objects", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList}); + storage.synchronizeTypes(types, {}); + types[2].aliasDeclarations[1].aliasTypeName = Storage::ExportedType{"Obj2"}; + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QObject2"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsPropertyName) +{ + Storage::Types types{createTypesWithAliases()}; + storage.synchronizeTypes(types, {}); + types[2].aliasDeclarations[1].aliasPropertyName = "children"; + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT( + storage.fetchTypes(), + Contains( + AllOf(IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangeAliasDeclarationsToPropertyDeclaration) +{ + Storage::Types types{createTypesWithAliases()}; + storage.synchronizeTypes(types, {}); + types[2].aliasDeclarations.pop_back(); + types[2].propertyDeclarations.push_back( + Storage::PropertyDeclaration{"objects", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly}); + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT( + storage.fetchTypes(), + Contains( + AllOf(IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + +TEST_F(ProjectStorageSlowTest, SynchronizeTypesChangePropertyDeclarationsToAliasDeclaration) +{ + Storage::Types types{createTypesWithAliases()}; + auto typesChanged = types; + typesChanged[2].aliasDeclarations.pop_back(); + typesChanged[2].propertyDeclarations.push_back( + Storage::PropertyDeclaration{"objects", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly}); + storage.synchronizeTypes(typesChanged, {}); + + storage.synchronizeTypes(types, {}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf( + IsStorageType(importId2, + "QAliasItem", + Storage::NativeType{"QQuickItem"}, + TypeAccessSemantics::Reference, + sourceId1), + Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("items", + Storage::NativeType{"QQuickItem"}, + Storage::PropertyDeclarationTraits::IsList + | Storage::PropertyDeclarationTraits::IsReadOnly), + IsPropertyDeclaration("objects", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList), + IsPropertyDeclaration("data", + Storage::NativeType{"QObject"}, + Storage::PropertyDeclarationTraits::IsList)))))); +} + } // namespace