aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2022-05-24 18:07:17 +0200
committerMarco Bubke <marco.bubke@qt.io>2022-06-09 13:39:50 +0000
commit9194300ebe76eaf0864919c40f7086e7a760e88e (patch)
tree824c113cf1345668b7a107982ecd23ca05eba309
parenta9f9fac76d8e79f9074d8f1897dcb534474b555f (diff)
QmlDesigner: Support alias on value types in project storage
There can be an alias on value types like font.size. For that case there is an alias stem and an alias tail. This patch is introducing support for it but still not implementing all of the dependency management. Task-number: QDS-7116 Change-Id: I83d570c5b954cc0378f25ce91609d809bb41a963 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h66
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h21
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp4
-rw-r--r--tests/unit/unittest/projectstorage-test.cpp576
-rw-r--r--tests/unit/unittest/qmltypesparser-test.cpp16
5 files changed, 667 insertions, 16 deletions
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
index 210e22004b..f0e307cbcc 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
@@ -399,11 +399,13 @@ private:
PropertyDeclarationId propertyDeclarationId,
ImportedTypeNameId aliasImportedTypeNameId,
Utils::SmallString aliasPropertyName,
+ Utils::SmallString aliasPropertyNameTail,
PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{})
: typeId{typeId}
, propertyDeclarationId{propertyDeclarationId}
, aliasImportedTypeNameId{aliasImportedTypeNameId}
, aliasPropertyName{std::move(aliasPropertyName)}
+ , aliasPropertyNameTail{std::move(aliasPropertyNameTail)}
, aliasPropertyDeclarationId{aliasPropertyDeclarationId}
{}
@@ -419,6 +421,7 @@ private:
PropertyDeclarationId propertyDeclarationId;
ImportedTypeNameId aliasImportedTypeNameId;
Utils::SmallString aliasPropertyName;
+ Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationId aliasPropertyDeclarationId;
};
@@ -783,15 +786,21 @@ private:
auto callback = [&](long long typeId,
long long propertyDeclarationId,
long long propertyImportedTypeNameId,
- long long aliasPropertyDeclarationId) {
+ long long aliasPropertyDeclarationId,
+ long long aliasPropertyDeclarationTailId) {
auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>(
aliasPropertyDeclarationId);
+ Utils::SmallString aliasPropertyNameTail;
+ if (aliasPropertyDeclarationTailId != -1)
+ aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>(
+ aliasPropertyDeclarationTailId);
relinkableAliasPropertyDeclarations
.emplace_back(TypeId{typeId},
PropertyDeclarationId{propertyDeclarationId},
ImportedTypeNameId{propertyImportedTypeNameId},
- std::move(aliasPropertyName));
+ std::move(aliasPropertyName),
+ std::move(aliasPropertyNameTail));
updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
@@ -966,6 +975,20 @@ private:
relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds);
}
+ PropertyDeclarationId fetchAliasId(TypeId aliasTypeId,
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail)
+ {
+ if (aliasPropertyNameTail.empty())
+ return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName);
+
+ auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId,
+ aliasPropertyName);
+
+ return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId,
+ aliasPropertyNameTail);
+ }
+
void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
{
for (const auto &aliasDeclaration : aliasDeclarations) {
@@ -974,8 +997,9 @@ private:
if (!aliasTypeId)
throw TypeNameDoesNotExists{};
- auto aliasId = fetchPropertyDeclarationIdByTypeIdAndNameUngarded(
- aliasTypeId, aliasDeclaration.aliasPropertyName);
+ auto aliasId = fetchAliasId(aliasTypeId,
+ aliasDeclaration.aliasPropertyName,
+ aliasDeclaration.aliasPropertyNameTail);
updatePropertyDeclarationAliasIdAndTypeNameIdStatement
.write(&aliasDeclaration.propertyDeclarationId,
@@ -1020,8 +1044,19 @@ private:
Prototypes &relinkablePrototypes)
{
std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
- return std::tie(first.moduleId, first.name, first.version)
- < std::tie(second.moduleId, second.name, second.version);
+ if (first.moduleId < second.moduleId)
+ return true;
+ else if (first.moduleId > second.moduleId)
+ return false;
+
+ auto nameCompare = Sqlite::compare(first.name, second.name);
+
+ if (nameCompare < 0)
+ return true;
+ else if (nameCompare > 0)
+ return false;
+
+ return first.version < second.version;
});
auto range = selectExportedTypesForSourceIdsStatement.template range<Storage::ExportedTypeView>(
@@ -1105,7 +1140,8 @@ private:
PropertyDeclarationId{propertyDeclarationId},
fetchImportedTypeNameId(value.typeName,
sourceId),
- std::move(value.aliasPropertyName));
+ value.aliasPropertyName,
+ value.aliasPropertyNameTail);
return Sqlite::CallbackControl::Abort;
};
@@ -1147,6 +1183,7 @@ private:
fetchImportedTypeNameId(value.typeName,
sourceId),
value.aliasPropertyName,
+ value.aliasPropertyNameTail,
view.aliasId);
}
@@ -2065,10 +2102,17 @@ private:
propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict);
+ auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
+ "aliasPropertyDeclarationTailId",
+ propertyDeclarationTable,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Restrict);
propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
"aliasPropertyDeclarationId IS NOT NULL");
+ propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
+ "aliasPropertyDeclarationTailId IS NOT NULL");
propertyDeclarationTable.initialize(database);
}
@@ -2571,10 +2615,12 @@ public:
"propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
"NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
database};
- ReadStatement<4, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
+ ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
"SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
- "target.propertyDeclarationId FROM propertyDeclarations AS alias JOIN propertyDeclarations "
- "AS target ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId WHERE "
+ "alias.aliasPropertyDeclarationId, ifnull(alias.aliasPropertyDeclarationTailId, -1) FROM "
+ "propertyDeclarations AS alias JOIN propertyDeclarations AS target ON "
+ "alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
+ "alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId WHERE "
"alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN "
"(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
"WHERE typeId=?1)",
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
index f025babdb0..dd36e15921 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
@@ -640,10 +640,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName typeName,
PropertyDeclarationTraits traits,
- Utils::SmallStringView aliasPropertyName)
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, typeName{std::move(typeName)}
, aliasPropertyName{aliasPropertyName}
+ , aliasPropertyNameTail{aliasPropertyNameTail}
+
, traits{traits}
, kind{PropertyKind::Property}
{}
@@ -651,9 +654,11 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name,
TypeId propertyTypeId,
PropertyDeclarationTraits traits,
- Utils::SmallStringView aliasPropertyName)
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, aliasPropertyName{aliasPropertyName}
+ , aliasPropertyNameTail{aliasPropertyNameTail}
, traits{traits}
, propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property}
@@ -662,9 +667,12 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name,
long long propertyTypeId,
int traits,
- Utils::SmallStringView aliasPropertyName)
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, aliasPropertyName{aliasPropertyName}
+ , aliasPropertyNameTail{aliasPropertyNameTail}
+
, traits{static_cast<PropertyDeclarationTraits>(traits)}
, propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property}
@@ -672,10 +680,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName aliasTypeName,
- Utils::SmallStringView aliasPropertyName)
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, typeName{std::move(aliasTypeName)}
, aliasPropertyName{aliasPropertyName}
+ , aliasPropertyNameTail{aliasPropertyNameTail}
+
, kind{PropertyKind::Alias}
{}
@@ -683,6 +694,7 @@ public:
{
return first.name == second.name && first.typeName == second.typeName
&& first.aliasPropertyName == second.aliasPropertyName
+ && first.aliasPropertyNameTail == second.aliasPropertyNameTail
&& first.traits == second.traits && first.kind == second.kind;
}
@@ -690,6 +702,7 @@ public:
Utils::SmallString name;
ImportedTypeName typeName;
Utils::SmallString aliasPropertyName;
+ Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationTraits traits = {};
TypeId propertyTypeId;
TypeId typeId;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 24690730ae..bc187ac62f 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -1188,8 +1188,8 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD
using Utils::operator<<;
return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName
<< ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", "
- << propertyDeclaration.typeId << ", \"" << propertyDeclaration.aliasPropertyName
- << "\")";
+ << propertyDeclaration.propertyTypeId << ", \""
+ << propertyDeclaration.aliasPropertyName << "\")";
}
std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits)
diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp
index ebc60ff22e..e0ad752f74 100644
--- a/tests/unit/unittest/projectstorage-test.cpp
+++ b/tests/unit/unittest/projectstorage-test.cpp
@@ -334,6 +334,160 @@ protected:
return package;
}
+ auto createSynchronizationPackageWithIndirectAliases()
+ {
+ SynchronizationPackage package;
+
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
+
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
+ package.moduleDependencies.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1);
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2);
+
+ package.updatedModuleDependencySourceIds.push_back(sourceId1);
+ package.updatedModuleDependencySourceIds.push_back(sourceId2);
+
+ importsSourceId1.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ importsSourceId1.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
+ moduleDependenciesSourceId1.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
+ moduleDependenciesSourceId1.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId1);
+
+ importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
+ moduleDependenciesSourceId2.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId2);
+
+ package.types.push_back(Storage::Type{
+ "QQuickItem",
+ Storage::ImportedType{"QObject"},
+ TypeAccessSemantics::Reference,
+ sourceId1,
+ {Storage::ExportedType{qtQuickModuleId, "Item"},
+ Storage::ExportedType{qtQuickNativeModuleId, "QQuickItem"}},
+ {Storage::PropertyDeclaration{"children",
+ Storage::ImportedType{"QChildren"},
+ Storage::PropertyDeclarationTraits::IsReadOnly},
+ Storage::PropertyDeclaration{"kids",
+ Storage::ImportedType{"QChildren2"},
+ Storage::PropertyDeclarationTraits::IsReadOnly}}});
+
+ package.types.push_back(
+ Storage::Type{"QObject",
+ Storage::ImportedType{},
+ TypeAccessSemantics::Reference,
+ sourceId2,
+ {Storage::ExportedType{qmlModuleId, "Object", Storage::Version{2}},
+ Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2}},
+ Storage::ExportedType{qmlNativeModuleId, "QObject"}}});
+
+ package.updatedSourceIds = {sourceId1, sourceId2};
+
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3);
+ package.moduleDependencies.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3);
+ package.updatedModuleDependencySourceIds.push_back(sourceId3);
+
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4);
+ package.moduleDependencies.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId4);
+ package.updatedModuleDependencySourceIds.push_back(sourceId4);
+
+ importsSourceId3.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ importsSourceId3.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
+ moduleDependenciesSourceId3.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3);
+ moduleDependenciesSourceId3.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3);
+
+ importsSourceId4.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
+ moduleDependenciesSourceId4.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4);
+ moduleDependenciesSourceId4.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId4);
+
+ package.types[1].propertyDeclarations.push_back(
+ Storage::PropertyDeclaration{"objects",
+ Storage::ImportedType{"QObject"},
+ Storage::PropertyDeclarationTraits::IsList});
+ package.types.push_back(
+ Storage::Type{"QAliasItem",
+ Storage::ImportedType{"Item"},
+ TypeAccessSemantics::Reference,
+ sourceId3,
+ {Storage::ExportedType{qtQuickModuleId, "AliasItem"},
+ Storage::ExportedType{qtQuickNativeModuleId, "QAliasItem"}}});
+ package.types.back().propertyDeclarations.push_back(
+ Storage::PropertyDeclaration{"items", Storage::ImportedType{"Item"}, "children", "items"});
+ package.types.back().propertyDeclarations.push_back(Storage::PropertyDeclaration{
+ "objects", Storage::ImportedType{"Item"}, "children", "objects"});
+
+ package.types.push_back(Storage::Type{"QObject2",
+ Storage::ImportedType{},
+ TypeAccessSemantics::Reference,
+ sourceId4,
+ {Storage::ExportedType{pathToModuleId, "Object2"},
+ Storage::ExportedType{pathToModuleId, "Obj2"}}});
+ package.types[3].propertyDeclarations.push_back(
+ Storage::PropertyDeclaration{"children",
+ Storage::ImportedType{"QChildren2"},
+ Storage::PropertyDeclarationTraits::IsReadOnly});
+
+ package.updatedSourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId4);
+
+ package.types.push_back(Storage::Type{
+ "QChildren",
+ Storage::ImportedType{},
+ TypeAccessSemantics::Reference,
+ sourceId5,
+ {Storage::ExportedType{qtQuickModuleId, "Children", Storage::Version{2}},
+ Storage::ExportedType{qtQuickNativeModuleId, "QChildren"}},
+ {Storage::PropertyDeclaration{"items",
+ Storage::ImportedType{"QQuickItem"},
+ Storage::PropertyDeclarationTraits::IsList},
+ Storage::PropertyDeclaration{"objects",
+ Storage::ImportedType{"QObject"},
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly}}});
+
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5);
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId5);
+ package.moduleDependencies.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId5);
+ importsSourceId5.emplace_back(qmlModuleId, Storage::Version{}, sourceId5);
+ importsSourceId5.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5);
+ moduleDependenciesSourceId5.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId5);
+ moduleDependenciesSourceId5.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId5);
+ package.updatedModuleDependencySourceIds.push_back(sourceId5);
+ package.updatedSourceIds.push_back(sourceId5);
+
+ package.types.push_back(Storage::Type{
+ "QChildren2",
+ Storage::ImportedType{},
+ TypeAccessSemantics::Reference,
+ sourceId6,
+ {Storage::ExportedType{qtQuickModuleId, "Children2", Storage::Version{2}},
+ Storage::ExportedType{qtQuickNativeModuleId, "QChildren2"}},
+ {Storage::PropertyDeclaration{"items",
+ Storage::ImportedType{"QQuickItem"},
+ Storage::PropertyDeclarationTraits::IsList},
+ Storage::PropertyDeclaration{"objects",
+ Storage::ImportedType{"Object2"},
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly}}});
+
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId6);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId6);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId6);
+ package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId6);
+ package.moduleDependencies.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId6);
+ package.updatedModuleDependencySourceIds.push_back(sourceId6);
+ package.updatedSourceIds.push_back(sourceId6);
+
+ return package;
+ }
+
auto createSynchronizationPackageWithAliases2()
{
auto package{createSynchronizationPackageWithAliases()};
@@ -485,11 +639,13 @@ protected:
QmlDesigner::SourcePathView path3{"/path3/to"};
QmlDesigner::SourcePathView path4{"/path4/to"};
QmlDesigner::SourcePathView path5{"/path5/to"};
+ QmlDesigner::SourcePathView path6{"/path6/to"};
SourceId sourceId1{sourcePathCache.sourceId(path1)};
SourceId sourceId2{sourcePathCache.sourceId(path2)};
SourceId sourceId3{sourcePathCache.sourceId(path3)};
SourceId sourceId4{sourcePathCache.sourceId(path4)};
SourceId sourceId5{sourcePathCache.sourceId(path5)};
+ SourceId sourceId6{sourcePathCache.sourceId(path6)};
SourceId qmlProjectSourceId{sourcePathCache.sourceId("/path1/qmldir")};
SourceId qtQuickProjectSourceId{sourcePathCache.sourceId("/path2/qmldir")};
ModuleId qmlModuleId{storage.moduleId("Qml")};
@@ -503,10 +659,12 @@ protected:
Storage::Imports importsSourceId2;
Storage::Imports importsSourceId3;
Storage::Imports importsSourceId4;
+ Storage::Imports importsSourceId5;
Storage::Imports moduleDependenciesSourceId1;
Storage::Imports moduleDependenciesSourceId2;
Storage::Imports moduleDependenciesSourceId3;
Storage::Imports moduleDependenciesSourceId4;
+ Storage::Imports moduleDependenciesSourceId5;
};
TEST_F(ProjectStorage, FetchSourceContextIdReturnsAlwaysTheSameIdForTheSamePath)
@@ -4309,4 +4467,422 @@ TEST_F(ProjectStorage, ModuleExportedImportWithQualifiedImportedType)
UnorderedElementsAre(IsExportedType(myModuleModuleId, "MyItem"))))));
}
+TEST_F(ProjectStorage, SynchronizeTypesAddIndirectAliasDeclarations)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+
+ storage.synchronize(package);
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId2, "QObject"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesAddIndirectAliasDeclarationsAgain)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+
+ storage.synchronize(package);
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId2, "QObject"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesRemoveIndirectAliasDeclaration)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations.pop_back();
+
+ storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(IsPropertyDeclaration(
+ "items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesAddIndirectAliasDeclarationsThrowsForWrongTypeName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"QQuickItemWrong"};
+
+ ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId3,
+ {package.types[2]},
+ {sourceId3},
+ moduleDependenciesSourceId3,
+ {sourceId3}}),
+ QmlDesigner::TypeNameDoesNotExists);
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesAddIndirectAliasDeclarationsThrowsForWrongPropertyName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong";
+
+ ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId3,
+ {package.types[2]},
+ {sourceId3},
+ moduleDependenciesSourceId3,
+ {sourceId3}}),
+ QmlDesigner::PropertyNameDoesNotExists);
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesAddIndirectAliasDeclarationsThrowsForWrongPropertyNameTail)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "objectsWrong";
+
+ ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId3,
+ {package.types[2]},
+ {sourceId3},
+ moduleDependenciesSourceId3,
+ {sourceId3}}),
+ QmlDesigner::PropertyNameDoesNotExists);
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationTypeName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].typeName = Storage::ImportedType{"Obj2"};
+ importsSourceId3.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId4, "QObject2"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationTailsTypeName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[4].propertyDeclarations[1].typeName = Storage::ImportedType{"Obj2"};
+ importsSourceId5.emplace_back(pathToModuleId, Storage::Version{}, sourceId5);
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId5, {package.types[4]}, {sourceId5}, moduleDependenciesSourceId5, {sourceId5}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId4, "QObject2"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationsPropertyName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].aliasPropertyName = "kids";
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId4, "QObject2"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationsPropertyNameTail)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "items";
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(AllOf(
+ IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration("objects",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationsToPropertyDeclaration)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations.pop_back();
+ package.types[2].propertyDeclarations.push_back(
+ Storage::PropertyDeclaration{"objects",
+ Storage::ImportedType{"QQuickItem"},
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly});
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangePropertyDeclarationsToIndirectAliasDeclaration)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ auto packageChanged = package;
+ packageChanged.types[2].propertyDeclarations.pop_back();
+ packageChanged.types[2].propertyDeclarations.push_back(
+ Storage::PropertyDeclaration{"objects",
+ Storage::ImportedType{"QQuickItem"},
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly});
+ storage.synchronize(SynchronizationPackage{importsSourceId3,
+ {packageChanged.types[2]},
+ {sourceId3},
+ moduleDependenciesSourceId3,
+ {sourceId3}});
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId2, "QObject"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasTargetPropertyDeclarationTraits)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[4].propertyDeclarations[0].traits = Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly;
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId5, {package.types[4]}, {sourceId5}, moduleDependenciesSourceId5, {sourceId5}});
+
+ ASSERT_THAT(
+ storage.fetchTypes(),
+ Contains(AllOf(
+ IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly),
+ IsPropertyDeclaration("objects",
+ fetchTypeId(sourceId2, "QObject"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasTargetPropertyDeclarationTypeName)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[4].propertyDeclarations[1].typeName = Storage::ImportedType{"Item"};
+
+ storage.synchronize(SynchronizationPackage{
+ importsSourceId5, {package.types[4]}, {sourceId5}, moduleDependenciesSourceId5, {sourceId5}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(
+ AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList),
+ IsPropertyDeclaration(
+ "objects",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsReadOnly))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationWithAnIndirectAliasThrows)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[4].propertyDeclarations.pop_back();
+
+ ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId5,
+ {package.types[4]},
+ {sourceId5},
+ moduleDependenciesSourceId5,
+ {sourceId5}}),
+ Sqlite::ConstraintPreventsModification);
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesRemoveStemPropertyDeclarationWithAnIndirectAliasThrows)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[0].propertyDeclarations.erase(package.types[0].propertyDeclarations.begin());
+
+ ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId1,
+ {package.types[0]},
+ {sourceId1},
+ moduleDependenciesSourceId1,
+ {sourceId1}}),
+ Sqlite::ConstraintPreventsModification);
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndIndirectAlias)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[2].propertyDeclarations.pop_back();
+ package.types[4].propertyDeclarations.pop_back();
+
+ storage.synchronize(SynchronizationPackage{importsSourceId3 + importsSourceId5,
+ {package.types[2], package.types[4]},
+ {sourceId3, sourceId5},
+ moduleDependenciesSourceId3 + moduleDependenciesSourceId5,
+ {sourceId3, sourceId5}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(IsPropertyDeclaration(
+ "items",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ Storage::PropertyDeclarationTraits::IsList))))));
+}
+
+TEST_F(ProjectStorage, SynchronizeTypesRemovePropertyDeclarationAndIndirectAliasSteam)
+{
+ auto package{createSynchronizationPackageWithIndirectAliases()};
+ storage.synchronize(package);
+ package.types[0].propertyDeclarations.clear();
+ package.types[2].propertyDeclarations.clear();
+
+ storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId3,
+ {package.types[0], package.types[2]},
+ {sourceId1, sourceId3},
+ moduleDependenciesSourceId1 + moduleDependenciesSourceId3,
+ {sourceId1, sourceId3}});
+
+ ASSERT_THAT(storage.fetchTypes(),
+ Contains(AllOf(IsStorageType(sourceId3,
+ "QAliasItem",
+ fetchTypeId(sourceId1, "QQuickItem"),
+ TypeAccessSemantics::Reference),
+ Field(&Storage::Type::propertyDeclarations, IsEmpty()))));
+}
} // namespace
diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp
index 9169d6b29a..89b50ebe1f 100644
--- a/tests/unit/unittest/qmltypesparser-test.cpp
+++ b/tests/unit/unittest/qmltypesparser-test.cpp
@@ -366,6 +366,22 @@ TEST_F(QmlTypesParser, Functions)
Field(&Storage::FunctionDeclaration::parameters, IsEmpty()))))));
}
+TEST_F(QmlTypesParser, SkipJavaScriptFunctions)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ Method {
+ name: "do"
+ isJavaScriptFunction: true
+ }
+ }})"};
+
+ parser.parse(source, imports, types, projectData);
+
+ ASSERT_THAT(types, ElementsAre(Field(&Storage::Type::functionDeclarations, IsEmpty())));
+}
+
TEST_F(QmlTypesParser, FunctionsWithQualifiedTypes)
{
QString source{R"(import QtQuick.tooling 1.2