diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 65bb06cfd81..18f3f491a06 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -75,6 +75,7 @@ public: AliasPropertyDeclarations relinkableAliasPropertyDeclarations; PropertyDeclarations relinkablePropertyDeclarations; Prototypes relinkablePrototypes; + Prototypes relinkableExtensions; TypeIds deletedTypeIds; TypeIds updatedTypeIds; @@ -98,6 +99,7 @@ public: relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, relinkablePrototypes, + relinkableExtensions, package.updatedSourceIds); deleteNotUpdatedTypes(updatedTypeIds, @@ -106,11 +108,13 @@ public: relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, relinkablePrototypes, + relinkableExtensions, deletedTypeIds); relink(relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, relinkablePrototypes, + relinkableExtensions, deletedTypeIds); linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations); @@ -229,6 +233,8 @@ public: return commonTypeCache.template builtinTypeId(); } + auto prototypes(TypeId type) const {} + PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId, Utils::SmallStringView name) { @@ -640,6 +646,7 @@ private: AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, const SourceIds &updatedSourceIds) { Storage::Synchronization::ExportedTypes exportedTypes; @@ -680,9 +687,10 @@ private: exportedTypes, relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, - relinkablePrototypes); + relinkablePrototypes, + relinkableExtensions); - syncPrototypes(types, relinkablePrototypes); + syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions); resetDefaultPropertiesIfChanged(types); resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations); syncDeclarations(types, @@ -930,14 +938,27 @@ private: updatePrototypeIdToNullStatement.readCallback(callback, prototypeId); } + void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions) + { + auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) { + relinkableExtensions.emplace_back(typeId, extensionNameId); + + return Sqlite::CallbackControl::Continue; + }; + + updateExtensionIdToNullStatement.readCallback(callback, extensionId); + } + void deleteType(TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, - Prototypes &relinkablePrototypes) + 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); @@ -995,8 +1016,10 @@ private: }, TypeCompare{}); } - - void relinkPrototypes(Prototypes &relinkablePrototypes, const TypeIds &deletedTypeIds) + template + void relinkPrototypes(Prototypes &relinkablePrototypes, + const TypeIds &deletedTypeIds, + Callable updateStatement) { std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end()); @@ -1011,7 +1034,7 @@ private: if (!prototypeId) throw TypeNameDoesNotExists{}; - updateTypePrototypeStatement.write(prototype.typeId, prototypeId); + updateStatement(prototype.typeId, prototypeId); checkForPrototypeChainCycle(prototype.typeId); }, TypeCompare{}); @@ -1023,6 +1046,7 @@ private: AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, TypeIds &deletedTypeIds) { auto callback = [&](TypeId typeId) { @@ -1030,7 +1054,8 @@ private: deleteType(typeId, relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, - relinkablePrototypes); + relinkablePrototypes, + relinkableExtensions); return Sqlite::CallbackControl::Continue; }; @@ -1044,11 +1069,17 @@ private: void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions, TypeIds &deletedTypeIds) { std::sort(deletedTypeIds.begin(), deletedTypeIds.end()); - relinkPrototypes(relinkablePrototypes, deletedTypeIds); + 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); } @@ -1119,7 +1150,8 @@ private: Storage::Synchronization::ExportedTypes &exportedTypes, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, - Prototypes &relinkablePrototypes) + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) { std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { if (first.moduleId < second.moduleId) @@ -1192,6 +1224,7 @@ private: handleAliasPropertyDeclarationsWithPropertyType(view.typeId, relinkableAliasPropertyDeclarations); handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId); return Sqlite::UpdateChange::Update; } @@ -1203,6 +1236,7 @@ private: handleAliasPropertyDeclarationsWithPropertyType(view.typeId, relinkableAliasPropertyDeclarations); handlePrototypes(view.typeId, relinkablePrototypes); + handleExtensions(view.typeId, relinkableExtensions); deleteExportedTypeNameStatement.write(view.exportedTypeNameId); }; @@ -1926,39 +1960,57 @@ private: propertyDeclarationId); } - void syncPrototype(Storage::Synchronization::Type &type, TypeIds &typeIds) + std::pair 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{}; + } + + return {typeId, typeNameId}; + } + + void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds) { if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal) return; - if (std::visit([](auto &&typeName) -> bool { return typeName.name.isEmpty(); }, - type.prototype)) { - updatePrototypeStatement.write(type.typeId, Sqlite::NullValue{}, Sqlite::NullValue{}); - } else { - ImportedTypeNameId prototypeTypeNameId = fetchImportedTypeNameId(type.prototype, - type.sourceId); + auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype, + type.sourceId); + auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension, + type.sourceId); - TypeId prototypeId = fetchTypeId(prototypeTypeNameId); + updatePrototypeAndExtensionStatement.write(type.typeId, + prototypeId, + prototypeTypeNameId, + extensionId, + extensionTypeNameId); - if (!prototypeId) - throw TypeNameDoesNotExists{}; - - updatePrototypeStatement.write(type.typeId, prototypeId, prototypeTypeNameId); + if (prototypeId || extensionId) checkForPrototypeChainCycle(type.typeId); - } typeIds.push_back(type.typeId); } - void syncPrototypes(Storage::Synchronization::Types &types, Prototypes &relinkablePrototypes) + void syncPrototypesAndExtensions(Storage::Synchronization::Types &types, + Prototypes &relinkablePrototypes, + Prototypes &relinkableExtensions) { TypeIds typeIds; typeIds.reserve(types.size()); for (auto &type : types) - syncPrototype(type, typeIds); + syncPrototypeAndExtension(type, typeIds); removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare{}); + removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare{}); } ImportId fetchImportId(SourceId sourceId, const Storage::Synchronization::Import &import) const @@ -2257,6 +2309,11 @@ private: Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::Restrict); typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer); + typesTable.addForeignKeyColumn("extensionId", + typesTable, + Sqlite::ForeignKeyAction::NoAction, + Sqlite::ForeignKeyAction::Restrict); + typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer); auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId", Sqlite::StrictColumnType::Integer); @@ -2543,9 +2600,10 @@ public: "UPDATE SET traits=excluded.traits WHERE traits IS NOT " "excluded.traits RETURNING typeId", database}; - WriteStatement<3> updatePrototypeStatement{ - "UPDATE types SET prototypeId=?2, prototypeNameId=?3 WHERE typeId=?1 AND (prototypeId IS " - "NOT ?2 OR prototypeNameId IS NOT ?3)", + 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}; @@ -2570,41 +2628,57 @@ public: 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 types JOIN typeSelection USING(typeId) WHERE prototypeId " - " IS NOT NULL)" + " 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 types JOIN typeSelection " - " USING(typeId) WHERE prototypeId IS NOT NULL) " + " 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 types JOIN typeSelection " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " 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> 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, level) AS (" " VALUES(?1, 0) " " UNION ALL " - " SELECT prototypeId, typeSelection.level+1 FROM types JOIN typeSelection " - " USING(typeId) WHERE prototypeId IS NOT NULL) " + " 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{ @@ -2625,8 +2699,8 @@ public: "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; mutable ReadStatement<3> selectAllSourcesStatement{ "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; - mutable ReadStatement<6, 1> selectTypeByTypeIdStatement{ - "SELECT sourceId, t.name, t.typeId, prototypeId, traits, pd.name " + mutable ReadStatement<7, 1> selectTypeByTypeIdStatement{ + "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, pd.name " "FROM types AS t LEFT JOIN propertyDeclarations AS pd " " ON defaultPropertyId=propertyDeclarationId WHERE t.typeId=?", database}; @@ -2634,8 +2708,8 @@ public: "SELECT moduleId, name, majorVersion, minorVersion FROM " "exportedTypeNames WHERE typeId=?", database}; - mutable ReadStatement<6> selectTypesStatement{ - "SELECT sourceId, t.name, t.typeId, prototypeId, traits, pd.name " + mutable ReadStatement<7> selectTypesStatement{ + "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, pd.name " "FROM types AS t LEFT JOIN propertyDeclarations AS pd " " ON defaultPropertyId=propertyDeclarationId", database}; @@ -2816,11 +2890,15 @@ public: "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 types JOIN typeSelection " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " 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}; @@ -2876,16 +2954,26 @@ public: "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 " - " prototypes(typeId) AS (" - " SELECT prototypeId FROM types WHERE typeId=? AND prototypeId IS NOT NULL" + " all_prototype_and_extension(typeId, prototypeId) AS (" + " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL" " UNION ALL " - " SELECT prototypeId FROM types JOIN prototypes USING(typeId) WHERE prototypeId " - " IS NOT NULL)" - "SELECT typeId FROM prototypes", + " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL)," + " prototype_and_extension(typeId) AS (" + " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?" + " UNION ALL " + " SELECT prototypeId FROM all_prototype_and_extension JOIN prototype_and_extension " + " USING(typeId)) " + "SELECT typeId FROM prototype_and_extension", database}; WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, " @@ -3057,11 +3145,15 @@ public: 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 types JOIN typeChain " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " + " USING(typeId))" "SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations " " USING(typeId) ORDER BY propertyDeclarationId", database}; @@ -3073,11 +3165,15 @@ public: 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 types JOIN typeChain " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " 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}; @@ -3093,21 +3189,29 @@ public: 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 types JOIN typeChain " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " 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 types JOIN typeChain " - " USING(typeId) WHERE prototypeId IS NOT NULL)" + " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain " + " USING(typeId))" "SELECT name FROM typeChain JOIN functionDeclarations " " USING(typeId) ORDER BY name", database}; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h index 18066cfafd3..f6cc85c5066 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h @@ -689,6 +689,7 @@ public: explicit Type() = default; explicit Type(Utils::SmallStringView typeName, ImportedTypeName prototype, + ImportedTypeName extension, TypeTraits traits, SourceId sourceId, ExportedTypes exportedTypes = {}, @@ -701,6 +702,7 @@ public: : typeName{typeName} , defaultPropertyName{defaultPropertyName} , prototype{std::move(prototype)} + , extension{std::move(extension)} , exportedTypes{std::move(exportedTypes)} , propertyDeclarations{std::move(propertyDeclarations)} , functionDeclarations{std::move(functionDeclarations)} @@ -711,11 +713,16 @@ public: , changeLevel{changeLevel} {} - explicit Type(Utils::SmallStringView typeName, TypeId prototypeId, TypeTraits traits, SourceId sourceId) + explicit Type(Utils::SmallStringView typeName, + TypeId prototypeId, + TypeId extensionId, + TypeTraits traits, + SourceId sourceId) : typeName{typeName} , traits{traits} , sourceId{sourceId} , prototypeId{prototypeId} + , extensionId{extensionId} {} explicit Type(Utils::SmallStringView typeName, @@ -732,10 +739,12 @@ public: explicit Type(Utils::SmallStringView typeName, Utils::SmallStringView prototype, + Utils::SmallStringView extension, TypeTraits traits, SourceId sourceId) : typeName{typeName} , prototype{ImportedType{prototype}} + , extension{ImportedType{extension}} , traits{traits} , sourceId{sourceId} @@ -745,6 +754,7 @@ public: Utils::SmallStringView typeName, TypeId typeId, TypeId prototypeId, + TypeId extensionId, TypeTraits traits, Utils::SmallStringView defaultPropertyName) : typeName{typeName} @@ -753,13 +763,15 @@ public: , sourceId{sourceId} , typeId{typeId} , prototypeId{prototypeId} + , extensionId{extensionId} {} friend bool operator==(const Type &first, const Type &second) noexcept { return first.typeName == second.typeName && first.defaultPropertyName == second.defaultPropertyName - && first.prototype == second.prototype && first.exportedTypes == second.exportedTypes + && first.prototype == second.prototype && first.extension == second.extension + && first.exportedTypes == second.exportedTypes && first.propertyDeclarations == second.propertyDeclarations && first.functionDeclarations == second.functionDeclarations && first.signalDeclarations == second.signalDeclarations @@ -770,6 +782,7 @@ public: TypeNameString typeName; Utils::SmallString defaultPropertyName; ImportedTypeName prototype; + ImportedTypeName extension; ExportedTypes exportedTypes; PropertyDeclarations propertyDeclarations; FunctionDeclarations functionDeclarations; @@ -779,6 +792,7 @@ public: SourceId sourceId; TypeId typeId; TypeId prototypeId; + TypeId extensionId; ChangeLevel changeLevel = ChangeLevel::Full; }; diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index c57ce05ddfe..06043d6c525 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -91,7 +91,8 @@ MATCHER_P4(IsStorageType, prototypeId, traits, std::string(negation ? "isn't " : "is ") - + PrintToString(Storage::Synchronization::Type{typeName, prototypeId, traits, sourceId})) + + PrintToString( + Storage::Synchronization::Type{typeName, prototypeId, TypeId{}, traits, sourceId})) { const Storage::Synchronization::Type &type = arg; @@ -99,6 +100,23 @@ MATCHER_P4(IsStorageType, && compareInvalidAreTrue(prototypeId, type.prototypeId); } +MATCHER_P5(IsStorageType, + sourceId, + typeName, + prototypeId, + extensionId, + traits, + std::string(negation ? "isn't " : "is ") + + PrintToString(Storage::Synchronization::Type{ + typeName, prototypeId, extensionId, traits, sourceId})) +{ + const Storage::Synchronization::Type &type = arg; + + return type.sourceId == sourceId && type.typeName == typeName && type.traits == traits + && compareInvalidAreTrue(prototypeId, type.prototypeId) + && compareInvalidAreTrue(extensionId, type.extensionId); +} + MATCHER_P(IsExportedType, name, std::string(negation ? "isn't " : "is ") @@ -320,6 +338,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QQuickItem", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"}, @@ -363,6 +382,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -395,6 +415,7 @@ protected: package.types.push_back( Storage::Synchronization::Type{"double", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Value, sourceId1, @@ -402,6 +423,7 @@ protected: "double"}}}); package.types.push_back( Storage::Synchronization::Type{"var", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Value, sourceId1, @@ -457,6 +479,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QAliasItem", Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{qtQuickModuleId, "AliasItem"}, @@ -476,6 +499,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId4, {Storage::Synchronization::ExportedType{pathToModuleId, "Object2"}, @@ -530,6 +554,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QQuickItem", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"}, @@ -546,6 +571,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -606,6 +632,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QAliasItem", Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{qtQuickModuleId, "AliasItem"}, @@ -620,6 +647,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId4, {Storage::Synchronization::ExportedType{pathToModuleId, "Object2"}, @@ -635,6 +663,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QChildren", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId5, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -673,6 +702,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QChildren2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId6, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -725,6 +755,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QAliasItem2", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId5, {Storage::Synchronization::ExportedType{qtQuickModuleId, "AliasItem2"}, @@ -755,6 +786,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -768,6 +800,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -780,6 +813,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject3", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -792,6 +826,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject4", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -821,6 +856,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -839,6 +875,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -858,6 +895,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject3", Storage::Synchronization::ImportedType{"Object2"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -891,6 +929,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QQuickItem", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -905,6 +944,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -920,6 +960,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "QQuickItem3d", Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{qtQuick3DModuleId, @@ -930,6 +971,7 @@ protected: package.types.push_back(Storage::Synchronization::Type{ "MyItem", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId4, {Storage::Synchronization::ExportedType{myModuleModuleId, @@ -1258,10 +1300,10 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypes) "QQuickItem")))))); } -TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) +TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExtensionChain) { auto package{createSimpleSynchronizationPackage()}; - package.types[0].prototype = Storage::Synchronization::ImportedType{"Object"}; + swap(package.types.front().extension, package.types.front().prototype); storage.synchronize(std::move(package)); @@ -1274,6 +1316,58 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) IsExportedType(qmlNativeModuleId, "QObject")))), AllOf(IsStorageType(sourceId1, "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, + "QQuickItem")))))); +} + +TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedPrototypeName) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].prototype = Storage::Synchronization::ImportedType{"Object"}; + + storage.synchronize(std::move(package)); + + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeId{}, TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeId{}, + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); +} + +TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithExportedExtensionName) +{ + auto package{createSimpleSynchronizationPackage()}; + swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::ImportedType{"Object"}; + + storage.synchronize(std::move(package)); + + ASSERT_THAT(storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, fetchTypeId(sourceId2, "QObject"), TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, @@ -1290,12 +1384,21 @@ TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongPrototypeName) ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesThrowsWithWrongExtensionName) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"}; + + ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, SynchronizeTypesAddsNewTypesWithMissingModule) { auto package{createSimpleSynchronizationPackage()}; package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{ModuleId::create(22), "Object2"}, @@ -1394,6 +1497,7 @@ TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) package.types.push_back(Storage::Synchronization::Type{ "QQuickObject", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Object"}, @@ -1405,7 +1509,7 @@ TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) ASSERT_THAT( storage.fetchTypes(), UnorderedElementsAre( - AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeTraits::Reference), + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeId{}, TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), IsExportedType(qmlModuleId, "Obj"), @@ -1413,6 +1517,7 @@ TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) AllOf(IsStorageType(sourceId1, "QQuickObject", fetchTypeId(sourceId2, "QObject"), + TypeId{}, TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), @@ -1420,6 +1525,51 @@ TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoPrototypeChain) AllOf(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId1, "QQuickObject"), + TypeId{}, + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); +} + +TEST_F(ProjectStorage, SynchronizeTypesInsertTypeIntoExtensionChain) +{ + auto package{createSimpleSynchronizationPackage()}; + swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + package.types[0].extension = Storage::Synchronization::ImportedType{"QQuickObject"}; + package.types.push_back(Storage::Synchronization::Type{ + "QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{"QObject"}, + TypeTraits::Reference, + sourceId1, + {Storage::Synchronization::ExportedType{qtQuickModuleId, "Object"}, + Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); + + storage.synchronize( + SynchronizationPackage{importsSourceId1, {package.types[0], package.types[2]}, {sourceId1}}); + + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeId{}, TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickObject", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), + IsExportedType(qtQuickNativeModuleId, "QQuickObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId1, "QQuickObject"), TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), @@ -1437,6 +1587,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) package.types.push_back(Storage::Synchronization::Type{ "QQuickObject", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Object"}, @@ -1447,7 +1598,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) ASSERT_THAT( storage.fetchTypes(), UnorderedElementsAre( - AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeTraits::Reference), + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeId{}, TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), IsExportedType(qmlModuleId, "Obj"), @@ -1455,6 +1606,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) AllOf(IsStorageType(sourceId1, "QQuickObject", fetchTypeId(sourceId2, "QObject"), + TypeId{}, TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), @@ -1462,6 +1614,53 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype) AllOf(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId1, "QQuickObject"), + TypeId{}, + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); +} + +TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedExtension) +{ + auto package{createSimpleSynchronizationPackage()}; + swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qtQuickModuleId, + Storage::Synchronization::Version{}, + sourceId1}}; + package.types.push_back(Storage::Synchronization::Type{ + "QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{"QObject"}, + TypeTraits::Reference, + sourceId1, + {Storage::Synchronization::ExportedType{qtQuickModuleId, "Object"}, + Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickObject"}}}); + + storage.synchronize(package); + + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeId{}, TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickObject", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), + TypeTraits::Reference), + Field(&Storage::Synchronization::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Object"), + IsExportedType(qtQuickNativeModuleId, "QQuickObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId1, "QQuickObject"), TypeTraits::Reference), Field(&Storage::Synchronization::Type::exportedTypes, UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), @@ -1474,6 +1673,22 @@ TEST_F(ProjectStorage, SynchronizeTypesThrowsForMissingPrototype) package.types = {Storage::Synchronization::Type{ "QQuickItem", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId1, + {Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"}, + Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}}; + + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); +} + +TEST_F(ProjectStorage, SynchronizeTypesThrowsForMissingExtension) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types = {Storage::Synchronization::Type{ + "QQuickItem", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{"QObject"}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"}, @@ -1488,6 +1703,7 @@ TEST_F(ProjectStorage, SynchronizeTypesThrowsForInvalidModule) package.types = { Storage::Synchronization::Type{"QQuickItem", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{ModuleId{}, "Item"}}}}; @@ -1501,6 +1717,7 @@ TEST_F(ProjectStorage, TypeWithInvalidSourceIdThrows) package.types = { Storage::Synchronization::Type{"QQuickItem", Storage::Synchronization::ImportedType{""}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, SourceId{}, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -1586,6 +1803,18 @@ TEST_F(ProjectStorage, BreakingPrototypeChainByDeletingBaseComponentThrows) QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, BreakingExtensionChainByDeletingBaseComponentThrows) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + + ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId1, + {package.types[0]}, + {sourceId1, sourceId2}}), + QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarations) { auto package{createSimpleSynchronizationPackage()}; @@ -1626,6 +1855,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType) package.types.push_back( Storage::Synchronization::Type{"QQuickObject", Storage::Synchronization::ImportedType{"QObject"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -3096,6 +3326,7 @@ TEST_F(ProjectStorage, package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId5, {Storage::Synchronization::ExportedType{qtQuickModuleId, "Object2"}, @@ -3255,6 +3486,24 @@ TEST_F(ProjectStorage, ChangePrototypeTypeName) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject3"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, ChangeExtensionTypeName) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + package.types[1].typeName = "QObject3"; + + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject3"), TypeTraits::Reference))); } @@ -3270,6 +3519,24 @@ TEST_F(ProjectStorage, ChangePrototypeTypeModuleId) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, ChangeExtensionTypeModuleId) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + package.types[1].exportedTypes[2].moduleId = qtQuickModuleId; + + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), TypeTraits::Reference))); } @@ -3287,6 +3554,21 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleIdThrows) QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, ChangeQualifiedExtensionTypeModuleIdThrows) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), + QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId) { auto package{createSimpleSynchronizationPackage()}; @@ -3309,6 +3591,34 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, ChangeQualifiedExtensionTypeModuleId) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qtQuickModuleId, + Storage::Synchronization::Version{}, + sourceId1}}; + + storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId2, + {package.types[0], package.types[1]}, + {sourceId1, sourceId2}}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), TypeTraits::Reference))); } @@ -3331,6 +3641,31 @@ TEST_F(ProjectStorage, ChangePrototypeTypeNameAndModuleId) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject3"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, ChangeExtensionTypeNameAndModuleId) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::ImportedType{"Object"}; + package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{ + "Object"}; + storage.synchronize(package); + package.types[1].exportedTypes[0].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[1].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[2].moduleId = qtQuickModuleId; + package.types[1].exportedTypes[2].name = "QObject3"; + package.types[1].typeName = "QObject3"; + + storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject3"), TypeTraits::Reference))); } @@ -3348,6 +3683,21 @@ TEST_F(ProjectStorage, ChangePrototypeTypeNameThrowsForWrongNativePrototupeTypeN QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, ChangeExtensionTypeNameThrowsForWrongNativeExtensionTypeName) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{ + "Object"}; + storage.synchronize(package); + package.types[1].exportedTypes[2].name = "QObject3"; + package.types[1].typeName = "QObject3"; + + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), + QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, ThrowForPrototypeChainCycles) { auto package{createSimpleSynchronizationPackage()}; @@ -3355,6 +3705,32 @@ TEST_F(ProjectStorage, ThrowForPrototypeChainCycles) package.types.push_back(Storage::Synchronization::Type{ "QObject2", Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{pathToModuleId, "Object2"}, + Storage::Synchronization::ExportedType{pathToModuleId, "Obj2"}}}); + package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3); + + ASSERT_THROW(storage.synchronize(SynchronizationPackage{package.imports, + package.types, + {sourceId1, sourceId2, sourceId3}, + package.moduleDependencies, + package.updatedModuleDependencySourceIds}), + QmlDesigner::PrototypeChainCycle); +} + +TEST_F(ProjectStorage, ThrowForExtensionChainCycles) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[1].extension = Storage::Synchronization::ImportedType{"Object2"}; + package.types.push_back(Storage::Synchronization::Type{ + "QObject2", + Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{pathToModuleId, "Object2"}, @@ -3379,6 +3755,15 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSame) ASSERT_THROW(storage.synchronize(package), QmlDesigner::PrototypeChainCycle); } +TEST_F(ProjectStorage, ThrowForTypeIdAndExtensionIdAreTheSame) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[1].prototype = Storage::Synchronization::ImportedType{"Object"}; + + ASSERT_THROW(storage.synchronize(package), QmlDesigner::PrototypeChainCycle); +} + TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSameForRelinking) { auto package{createSimpleSynchronizationPackage()}; @@ -3392,6 +3777,20 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSameForRelinking) QmlDesigner::PrototypeChainCycle); } +TEST_F(ProjectStorage, ThrowForTypeIdAndExtenssionIdAreTheSameForRelinking) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + package.types[1].extension = Storage::Synchronization::ImportedType{"Item"}; + package.types[1].typeName = "QObject2"; + importsSourceId2.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2); + + ASSERT_THROW(storage.synchronize( + SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}), + QmlDesigner::PrototypeChainCycle); +} + TEST_F(ProjectStorage, RecursiveAliases) { auto package{createSynchronizationPackageWithRecursiveAliases()}; @@ -3553,6 +3952,7 @@ TEST_F(ProjectStorage, QualifiedPrototype) Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3567,6 +3967,35 @@ TEST_F(ProjectStorage, QualifiedPrototype) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, QualifiedExtension) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}}; + package.types.push_back( + Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{qtQuickModuleId, + "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.updatedSourceIds.push_back(sourceId3); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), TypeTraits::Reference))); } @@ -3582,6 +4011,19 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperDownTheModuleChainThrows) ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, QualifiedExtensionUpperDownTheModuleChainThrows) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qtQuickModuleId, + Storage::Synchronization::Version{}, + sourceId1}}; + + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) { auto package{createSimpleSynchronizationPackage()}; @@ -3592,6 +4034,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) sourceId1}}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3606,6 +4049,37 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId3, "QQuickObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, QualifiedExtensionUpperInTheModuleChain) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qtQuickModuleId, + Storage::Synchronization::Version{}, + sourceId1}}; + package.types.push_back( + Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{qtQuickModuleId, + "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.updatedSourceIds.push_back(sourceId3); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId3, "QQuickObject"), TypeTraits::Reference))); } @@ -3617,6 +4091,28 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows) Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{4}, sourceId1}}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{qtQuickModuleId, + "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.updatedSourceIds.push_back(sourceId3); + + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); +} + +TEST_F(ProjectStorage, QualifiedExtensionWithWrongVersionThrows) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{4}, sourceId1}}; + package.types.push_back( + Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3636,6 +4132,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion) package.imports[0]}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3650,6 +4147,35 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId2, "QObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, QualifiedExtensionWithVersion) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.imports[0].version = Storage::Synchronization::Version{2}; + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{"Object", + package.imports[0]}; + package.types.push_back( + Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{qtQuickModuleId, + "Object"}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.updatedSourceIds.push_back(sourceId3); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId2, "QObject"), TypeTraits::Reference))); } @@ -3663,6 +4189,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) package.types.push_back(Storage::Synchronization::Type{ "QQuickObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -3677,6 +4204,37 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain) Contains(IsStorageType(sourceId1, "QQuickItem", fetchTypeId(sourceId3, "QQuickObject"), + TypeId{}, + TypeTraits::Reference))); +} + +TEST_F(ProjectStorage, QualifiedExtensionWithVersionInTheProtoTypeChain) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.imports[1].version = Storage::Synchronization::Version{2}; + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{"Object", + package.imports[1]}; + package.types[0].exportedTypes[0].version = Storage::Synchronization::Version{2}; + package.types.push_back(Storage::Synchronization::Type{ + "QQuickObject", + Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, + TypeTraits::Reference, + sourceId3, + {Storage::Synchronization::ExportedType{qtQuickModuleId, + "Object", + Storage::Synchronization::Version{2}}}}); + package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3); + package.updatedSourceIds.push_back(sourceId3); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(IsStorageType(sourceId1, + "QQuickItem", + TypeId{}, + fetchTypeId(sourceId3, "QQuickObject"), TypeTraits::Reference))); } @@ -3692,6 +4250,19 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionDownTheProtoTypeChainThrows) ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); } +TEST_F(ProjectStorage, QualifiedExtensionWithVersionDownTheProtoTypeChainThrows) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types[0].extension = Storage::Synchronization::QualifiedImportedType{ + "Object", + Storage::Synchronization::Import{qtQuickModuleId, + Storage::Synchronization::Version{2}, + sourceId1}}; + + ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists); +} + TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) { auto package{createSimpleSynchronizationPackage()}; @@ -3700,6 +4271,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName) Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3740,6 +4312,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain) sourceId1}}; package.types.push_back( Storage::Synchronization::Type{"QQuickObject", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId3, @@ -3919,6 +4492,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -3945,6 +4519,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Object", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -3965,6 +4540,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -3991,6 +4567,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTyp Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4012,6 +4589,7 @@ TEST_F(ProjectStorage, Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Object"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4036,6 +4614,7 @@ TEST_F(ProjectStorage, Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Object", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4053,6 +4632,7 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4076,6 +4656,7 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4093,6 +4674,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4119,6 +4701,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4139,6 +4722,7 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForImportedTypeThrows) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4162,6 +4746,7 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4179,6 +4764,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4205,6 +4791,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4225,6 +4812,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4247,6 +4835,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImp Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4267,6 +4856,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedTy Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"Obj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4293,6 +4883,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedI Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"Obj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4313,6 +4904,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType) Storage::Synchronization::Type type{ "Item", Storage::Synchronization::ImportedType{"BuiltInObj"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4335,6 +4927,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedT Storage::Synchronization::Type type{ "Item", Storage::Synchronization::QualifiedImportedType{"BuiltInObj", import}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId2, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4353,6 +4946,7 @@ TEST_F(ProjectStorage, EnsureThatPropertiesForRemovedTypesAreNotAnymoreRelinked) Storage::Synchronization::Type type{ "QObject", Storage::Synchronization::ImportedType{""}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qmlModuleId, @@ -4376,6 +4970,15 @@ TEST_F(ProjectStorage, EnsureThatPrototypesForRemovedTypesAreNotAnymoreRelinked) ASSERT_NO_THROW(storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}})); } +TEST_F(ProjectStorage, EnsureThatExtensionsForRemovedTypesAreNotAnymoreRelinked) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + storage.synchronize(package); + + ASSERT_NO_THROW(storage.synchronize(SynchronizationPackage{{sourceId1, sourceId2}})); +} + TEST_F(ProjectStorage, MinimalUpdates) { auto package{createSimpleSynchronizationPackage()}; @@ -4383,6 +4986,7 @@ TEST_F(ProjectStorage, MinimalUpdates) Storage::Synchronization::Type quickType{ "QQuickItem", {}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId1, {Storage::Synchronization::ExportedType{qtQuickModuleId, @@ -4798,6 +5402,7 @@ TEST_F(ProjectStorage, ModuleExportedImportPreventCollisionIfModuleIsIndirectlyR package.types.push_back(Storage::Synchronization::Type{ "QQuickItem4d", Storage::Synchronization::ImportedType{"Item"}, + Storage::Synchronization::ImportedType{}, TypeTraits::Reference, sourceId5, {Storage::Synchronization::ExportedType{qtQuick4DModuleId, @@ -5487,7 +6092,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForWrongMajorVersion) ASSERT_FALSE(typeId); } -TEST_F(ProjectStorage, GetPropertyDeclarationIds) +TEST_F(ProjectStorage, GetPropertyDeclarationIdsOverPrototypeChain) { auto package{createPackageWithProperties()}; storage.synchronize(package); @@ -5504,6 +6109,24 @@ TEST_F(ProjectStorage, GetPropertyDeclarationIds) HasName("children3"))); } +TEST_F(ProjectStorage, GetPropertyDeclarationIdsOverExtensionChain) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto propertyIds = storage.propertyDeclarationIds(typeId); + + ASSERT_THAT(propertyIds, + UnorderedElementsAre(HasName("data"), + HasName("children"), + HasName("data2"), + HasName("children2"), + HasName("data3"), + HasName("children3"))); +} + TEST_F(ProjectStorage, GetPropertyDeclarationIdsAreReturnedSorted) { auto package{createPackageWithProperties()}; @@ -5563,7 +6186,7 @@ TEST_F(ProjectStorage, GetLocalPropertyDeclarationIdsAreReturnedSorted) ASSERT_THAT(propertyIds, IsSorted()); } -TEST_F(ProjectStorage, GetPropertyDeclarationId) +TEST_F(ProjectStorage, GetPropertyDeclarationIdOverPrototypeChain) { auto package{createPackageWithProperties()}; storage.synchronize(package); @@ -5574,6 +6197,18 @@ TEST_F(ProjectStorage, GetPropertyDeclarationId) ASSERT_THAT(propertyId, HasName("data")); } +TEST_F(ProjectStorage, GetPropertyDeclarationIdOverExtensionChain) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject3"); + + auto propertyId = storage.propertyDeclarationId(typeId, "data"); + + ASSERT_THAT(propertyId, HasName("data")); +} + TEST_F(ProjectStorage, GetLatestPropertyDeclarationId) { auto package{createPackageWithProperties()}; @@ -5729,6 +6364,18 @@ TEST_F(ProjectStorage, GetOnlySignalDeclarationNamesFromUpIntoThePrototypeChain) ASSERT_THAT(signalNames, ElementsAre("itemsChanged", "valuesChanged")); } +TEST_F(ProjectStorage, GetOnlySignalDeclarationNamesFromUpIntoTheExtensionChain) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject2"); + + auto signalNames = storage.signalDeclarationNames(typeId); + + ASSERT_THAT(signalNames, ElementsAre("itemsChanged", "valuesChanged")); +} + TEST_F(ProjectStorage, GetFunctionDeclarationNames) { auto package{createPackageWithProperties()}; @@ -5773,6 +6420,18 @@ TEST_F(ProjectStorage, GetOnlyFunctionDeclarationNamesFromUpIntoThePrototypeChai ASSERT_THAT(functionNames, ElementsAre("items", "values")); } +TEST_F(ProjectStorage, GetOnlyFunctionDeclarationNamesFromUpIntoTheExtensionChain) +{ + auto package{createPackageWithProperties()}; + std::swap(package.types[1].extension, package.types[1].prototype); + storage.synchronize(package); + auto typeId = fetchTypeId(sourceId1, "QObject2"); + + auto functionNames = storage.functionDeclarationNames(typeId); + + ASSERT_THAT(functionNames, ElementsAre("items", "values")); +} + TEST_F(ProjectStorage, SynchronizeDefaultProperty) { auto package{createSimpleSynchronizationPackage()}; @@ -5891,6 +6550,24 @@ TEST_F(ProjectStorage, SynchronizeDefaultPropertyToThePrototypeProperty) Eq("children"))))); } +TEST_F(ProjectStorage, SynchronizeDefaultPropertyToTheExtensionProperty) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types.front().defaultPropertyName = "children"; + removeProperty(package, "QQuickItem", "children"); + auto &type = findType(package, "QObject"); + type.propertyDeclarations.push_back(Storage::Synchronization::PropertyDeclaration{ + "children", Storage::Synchronization::ImportedType{"Object"}, {}}); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf(Field(&Storage::Synchronization::Type::typeName, Eq("QQuickItem")), + Field(&Storage::Synchronization::Type::defaultPropertyName, + Eq("children"))))); +} + TEST_F(ProjectStorage, SynchronizeMoveTheDefaultPropertyToThePrototypeProperty) { auto package{createSimpleSynchronizationPackage()}; @@ -5909,6 +6586,25 @@ TEST_F(ProjectStorage, SynchronizeMoveTheDefaultPropertyToThePrototypeProperty) Eq("children"))))); } +TEST_F(ProjectStorage, SynchronizeMoveTheDefaultPropertyToTheExtensionProperty) +{ + auto package{createSimpleSynchronizationPackage()}; + std::swap(package.types.front().extension, package.types.front().prototype); + package.types.front().defaultPropertyName = "children"; + storage.synchronize(package); + removeProperty(package, "QQuickItem", "children"); + auto &type = findType(package, "QObject"); + type.propertyDeclarations.push_back(Storage::Synchronization::PropertyDeclaration{ + "children", Storage::Synchronization::ImportedType{"Object"}, {}}); + + storage.synchronize(package); + + ASSERT_THAT(storage.fetchTypes(), + Contains(AllOf(Field(&Storage::Synchronization::Type::typeName, Eq("QQuickItem")), + Field(&Storage::Synchronization::Type::defaultPropertyName, + Eq("children"))))); +} + TEST_F(ProjectStorage, GetType) { auto package{createSimpleSynchronizationPackage()}; diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp index e18b1d17cac..7757f8e273a 100644 --- a/tests/unit/unittest/projectstorageupdater-test.cpp +++ b/tests/unit/unittest/projectstorageupdater-test.cpp @@ -256,11 +256,13 @@ protected: Storage::Synchronization::Type objectType{ "QObject", Storage::Synchronization::ImportedType{}, + Storage::Synchronization::ImportedType{}, Storage::TypeTraits::Reference, qmltypesPathSourceId, {Storage::Synchronization::ExportedType{exampleModuleId, "Object"}, Storage::Synchronization::ExportedType{exampleModuleId, "Obj"}}}; Storage::Synchronization::Type itemType{"QItem", + Storage::Synchronization::ImportedType{}, Storage::Synchronization::ImportedType{}, Storage::TypeTraits::Reference, qmltypes2PathSourceId,