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>
This commit is contained in:
Marco Bubke
2022-05-24 18:07:17 +02:00
parent a9f9fac76d
commit 9194300ebe
5 changed files with 667 additions and 16 deletions

View File

@@ -399,11 +399,13 @@ private:
PropertyDeclarationId propertyDeclarationId, PropertyDeclarationId propertyDeclarationId,
ImportedTypeNameId aliasImportedTypeNameId, ImportedTypeNameId aliasImportedTypeNameId,
Utils::SmallString aliasPropertyName, Utils::SmallString aliasPropertyName,
Utils::SmallString aliasPropertyNameTail,
PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{}) PropertyDeclarationId aliasPropertyDeclarationId = PropertyDeclarationId{})
: typeId{typeId} : typeId{typeId}
, propertyDeclarationId{propertyDeclarationId} , propertyDeclarationId{propertyDeclarationId}
, aliasImportedTypeNameId{aliasImportedTypeNameId} , aliasImportedTypeNameId{aliasImportedTypeNameId}
, aliasPropertyName{std::move(aliasPropertyName)} , aliasPropertyName{std::move(aliasPropertyName)}
, aliasPropertyNameTail{std::move(aliasPropertyNameTail)}
, aliasPropertyDeclarationId{aliasPropertyDeclarationId} , aliasPropertyDeclarationId{aliasPropertyDeclarationId}
{} {}
@@ -419,6 +421,7 @@ private:
PropertyDeclarationId propertyDeclarationId; PropertyDeclarationId propertyDeclarationId;
ImportedTypeNameId aliasImportedTypeNameId; ImportedTypeNameId aliasImportedTypeNameId;
Utils::SmallString aliasPropertyName; Utils::SmallString aliasPropertyName;
Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationId aliasPropertyDeclarationId; PropertyDeclarationId aliasPropertyDeclarationId;
}; };
@@ -783,15 +786,21 @@ private:
auto callback = [&](long long typeId, auto callback = [&](long long typeId,
long long propertyDeclarationId, long long propertyDeclarationId,
long long propertyImportedTypeNameId, long long propertyImportedTypeNameId,
long long aliasPropertyDeclarationId) { long long aliasPropertyDeclarationId,
long long aliasPropertyDeclarationTailId) {
auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>( auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>(
aliasPropertyDeclarationId); aliasPropertyDeclarationId);
Utils::SmallString aliasPropertyNameTail;
if (aliasPropertyDeclarationTailId != -1)
aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>(
aliasPropertyDeclarationTailId);
relinkableAliasPropertyDeclarations relinkableAliasPropertyDeclarations
.emplace_back(TypeId{typeId}, .emplace_back(TypeId{typeId},
PropertyDeclarationId{propertyDeclarationId}, PropertyDeclarationId{propertyDeclarationId},
ImportedTypeNameId{propertyImportedTypeNameId}, ImportedTypeNameId{propertyImportedTypeNameId},
std::move(aliasPropertyName)); std::move(aliasPropertyName),
std::move(aliasPropertyNameTail));
updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId); updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
@@ -966,6 +975,20 @@ private:
relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds); 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) void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
{ {
for (const auto &aliasDeclaration : aliasDeclarations) { for (const auto &aliasDeclaration : aliasDeclarations) {
@@ -974,8 +997,9 @@ private:
if (!aliasTypeId) if (!aliasTypeId)
throw TypeNameDoesNotExists{}; throw TypeNameDoesNotExists{};
auto aliasId = fetchPropertyDeclarationIdByTypeIdAndNameUngarded( auto aliasId = fetchAliasId(aliasTypeId,
aliasTypeId, aliasDeclaration.aliasPropertyName); aliasDeclaration.aliasPropertyName,
aliasDeclaration.aliasPropertyNameTail);
updatePropertyDeclarationAliasIdAndTypeNameIdStatement updatePropertyDeclarationAliasIdAndTypeNameIdStatement
.write(&aliasDeclaration.propertyDeclarationId, .write(&aliasDeclaration.propertyDeclarationId,
@@ -1020,8 +1044,19 @@ private:
Prototypes &relinkablePrototypes) Prototypes &relinkablePrototypes)
{ {
std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) { std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
return std::tie(first.moduleId, first.name, first.version) if (first.moduleId < second.moduleId)
< std::tie(second.moduleId, second.name, second.version); 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>( auto range = selectExportedTypesForSourceIdsStatement.template range<Storage::ExportedTypeView>(
@@ -1105,7 +1140,8 @@ private:
PropertyDeclarationId{propertyDeclarationId}, PropertyDeclarationId{propertyDeclarationId},
fetchImportedTypeNameId(value.typeName, fetchImportedTypeNameId(value.typeName,
sourceId), sourceId),
std::move(value.aliasPropertyName)); value.aliasPropertyName,
value.aliasPropertyNameTail);
return Sqlite::CallbackControl::Abort; return Sqlite::CallbackControl::Abort;
}; };
@@ -1147,6 +1183,7 @@ private:
fetchImportedTypeNameId(value.typeName, fetchImportedTypeNameId(value.typeName,
sourceId), sourceId),
value.aliasPropertyName, value.aliasPropertyName,
value.aliasPropertyNameTail,
view.aliasId); view.aliasId);
} }
@@ -2065,10 +2102,17 @@ private:
propertyDeclarationTable, propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction, Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict); Sqlite::ForeignKeyAction::Restrict);
auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
"aliasPropertyDeclarationTailId",
propertyDeclarationTable,
Sqlite::ForeignKeyAction::NoAction,
Sqlite::ForeignKeyAction::Restrict);
propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn}); propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn}, propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
"aliasPropertyDeclarationId IS NOT NULL"); "aliasPropertyDeclarationId IS NOT NULL");
propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
"aliasPropertyDeclarationTailId IS NOT NULL");
propertyDeclarationTable.initialize(database); propertyDeclarationTable.initialize(database);
} }
@@ -2571,10 +2615,12 @@ public:
"propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT " "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
"NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)", "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
database}; database};
ReadStatement<4, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
"SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
"target.propertyDeclarationId FROM propertyDeclarations AS alias JOIN propertyDeclarations " "alias.aliasPropertyDeclarationId, ifnull(alias.aliasPropertyDeclarationTailId, -1) FROM "
"AS target ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId WHERE " "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 " "alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN "
"(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) " "(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
"WHERE typeId=?1)", "WHERE typeId=?1)",

View File

@@ -640,10 +640,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName typeName, ImportedTypeName typeName,
PropertyDeclarationTraits traits, PropertyDeclarationTraits traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, typeName{std::move(typeName)} , typeName{std::move(typeName)}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{traits} , traits{traits}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
{} {}
@@ -651,9 +654,11 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
TypeId propertyTypeId, TypeId propertyTypeId,
PropertyDeclarationTraits traits, PropertyDeclarationTraits traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{traits} , traits{traits}
, propertyTypeId{propertyTypeId} , propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
@@ -662,9 +667,12 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
long long propertyTypeId, long long propertyTypeId,
int traits, int traits,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, traits{static_cast<PropertyDeclarationTraits>(traits)} , traits{static_cast<PropertyDeclarationTraits>(traits)}
, propertyTypeId{propertyTypeId} , propertyTypeId{propertyTypeId}
, kind{PropertyKind::Property} , kind{PropertyKind::Property}
@@ -672,10 +680,13 @@ public:
explicit PropertyDeclaration(Utils::SmallStringView name, explicit PropertyDeclaration(Utils::SmallStringView name,
ImportedTypeName aliasTypeName, ImportedTypeName aliasTypeName,
Utils::SmallStringView aliasPropertyName) Utils::SmallStringView aliasPropertyName,
Utils::SmallStringView aliasPropertyNameTail = {})
: name{name} : name{name}
, typeName{std::move(aliasTypeName)} , typeName{std::move(aliasTypeName)}
, aliasPropertyName{aliasPropertyName} , aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
, kind{PropertyKind::Alias} , kind{PropertyKind::Alias}
{} {}
@@ -683,6 +694,7 @@ public:
{ {
return first.name == second.name && first.typeName == second.typeName return first.name == second.name && first.typeName == second.typeName
&& first.aliasPropertyName == second.aliasPropertyName && first.aliasPropertyName == second.aliasPropertyName
&& first.aliasPropertyNameTail == second.aliasPropertyNameTail
&& first.traits == second.traits && first.kind == second.kind; && first.traits == second.traits && first.kind == second.kind;
} }
@@ -690,6 +702,7 @@ public:
Utils::SmallString name; Utils::SmallString name;
ImportedTypeName typeName; ImportedTypeName typeName;
Utils::SmallString aliasPropertyName; Utils::SmallString aliasPropertyName;
Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationTraits traits = {}; PropertyDeclarationTraits traits = {};
TypeId propertyTypeId; TypeId propertyTypeId;
TypeId typeId; TypeId typeId;

View File

@@ -1188,8 +1188,8 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD
using Utils::operator<<; using Utils::operator<<;
return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName return out << "(\"" << propertyDeclaration.name << "\", " << propertyDeclaration.typeName
<< ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", " << ", " << propertyDeclaration.typeId << ", " << propertyDeclaration.traits << ", "
<< propertyDeclaration.typeId << ", \"" << propertyDeclaration.aliasPropertyName << propertyDeclaration.propertyTypeId << ", \""
<< "\")"; << propertyDeclaration.aliasPropertyName << "\")";
} }
std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits) std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits)

View File

@@ -334,6 +334,160 @@ protected:
return package; 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 createSynchronizationPackageWithAliases2()
{ {
auto package{createSynchronizationPackageWithAliases()}; auto package{createSynchronizationPackageWithAliases()};
@@ -485,11 +639,13 @@ protected:
QmlDesigner::SourcePathView path3{"/path3/to"}; QmlDesigner::SourcePathView path3{"/path3/to"};
QmlDesigner::SourcePathView path4{"/path4/to"}; QmlDesigner::SourcePathView path4{"/path4/to"};
QmlDesigner::SourcePathView path5{"/path5/to"}; QmlDesigner::SourcePathView path5{"/path5/to"};
QmlDesigner::SourcePathView path6{"/path6/to"};
SourceId sourceId1{sourcePathCache.sourceId(path1)}; SourceId sourceId1{sourcePathCache.sourceId(path1)};
SourceId sourceId2{sourcePathCache.sourceId(path2)}; SourceId sourceId2{sourcePathCache.sourceId(path2)};
SourceId sourceId3{sourcePathCache.sourceId(path3)}; SourceId sourceId3{sourcePathCache.sourceId(path3)};
SourceId sourceId4{sourcePathCache.sourceId(path4)}; SourceId sourceId4{sourcePathCache.sourceId(path4)};
SourceId sourceId5{sourcePathCache.sourceId(path5)}; SourceId sourceId5{sourcePathCache.sourceId(path5)};
SourceId sourceId6{sourcePathCache.sourceId(path6)};
SourceId qmlProjectSourceId{sourcePathCache.sourceId("/path1/qmldir")}; SourceId qmlProjectSourceId{sourcePathCache.sourceId("/path1/qmldir")};
SourceId qtQuickProjectSourceId{sourcePathCache.sourceId("/path2/qmldir")}; SourceId qtQuickProjectSourceId{sourcePathCache.sourceId("/path2/qmldir")};
ModuleId qmlModuleId{storage.moduleId("Qml")}; ModuleId qmlModuleId{storage.moduleId("Qml")};
@@ -503,10 +659,12 @@ protected:
Storage::Imports importsSourceId2; Storage::Imports importsSourceId2;
Storage::Imports importsSourceId3; Storage::Imports importsSourceId3;
Storage::Imports importsSourceId4; Storage::Imports importsSourceId4;
Storage::Imports importsSourceId5;
Storage::Imports moduleDependenciesSourceId1; Storage::Imports moduleDependenciesSourceId1;
Storage::Imports moduleDependenciesSourceId2; Storage::Imports moduleDependenciesSourceId2;
Storage::Imports moduleDependenciesSourceId3; Storage::Imports moduleDependenciesSourceId3;
Storage::Imports moduleDependenciesSourceId4; Storage::Imports moduleDependenciesSourceId4;
Storage::Imports moduleDependenciesSourceId5;
}; };
TEST_F(ProjectStorage, FetchSourceContextIdReturnsAlwaysTheSameIdForTheSamePath) TEST_F(ProjectStorage, FetchSourceContextIdReturnsAlwaysTheSameIdForTheSamePath)
@@ -4309,4 +4467,422 @@ TEST_F(ProjectStorage, ModuleExportedImportWithQualifiedImportedType)
UnorderedElementsAre(IsExportedType(myModuleModuleId, "MyItem")))))); 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 } // namespace

View File

@@ -366,6 +366,22 @@ TEST_F(QmlTypesParser, Functions)
Field(&Storage::FunctionDeclaration::parameters, IsEmpty())))))); 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) TEST_F(QmlTypesParser, FunctionsWithQualifiedTypes)
{ {
QString source{R"(import QtQuick.tooling 1.2 QString source{R"(import QtQuick.tooling 1.2