QmlDesigner: Remove duplicate exports in qmldir

Fixes: QDS-13909
Change-Id: I9f369024d832d210c2efaed6410c462ef8af8bd7
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2024-10-24 18:28:34 +02:00
parent eab20da684
commit d0a8de5694
2 changed files with 106 additions and 3 deletions

View File

@@ -1167,6 +1167,32 @@ void rangeForTheSameFileName(const ProjectStorageUpdater::Components &components
} }
} }
namespace {
void removeDuplicates(Storage::Synchronization::ExportedTypes &exportedTypes)
{
using Storage::Synchronization::ExportedType;
auto factory = [](auto... projections) {
return [=](auto compare) {
return [=](const auto &first, const auto &second) {
return compare(std::forward_as_tuple(std::invoke(projections, first)...),
std::forward_as_tuple(std::invoke(projections, second)...));
};
};
};
auto compare = factory(&ExportedType::name, &ExportedType::version);
auto less = compare(std::ranges::less{});
auto equal = compare(std::ranges::equal_to{});
std::ranges::sort(exportedTypes, less);
auto duplicateExportedTypes = std::ranges::unique(exportedTypes, equal);
exportedTypes.erase(duplicateExportedTypes.begin(), duplicateExportedTypes.end());
}
} // namespace
Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdater::ComponentRange components) Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdater::ComponentRange components)
{ {
Storage::Synchronization::ExportedTypes exportedTypes; Storage::Synchronization::ExportedTypes exportedTypes;
@@ -1178,6 +1204,8 @@ Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdate
Storage::Version{component.majorVersion, component.minorVersion}); Storage::Version{component.majorVersion, component.minorVersion});
} }
removeDuplicates(exportedTypes);
return exportedTypes; return exportedTypes;
} }
@@ -1197,9 +1225,8 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
keyValue("directory id", directoryId), keyValue("directory id", directoryId),
keyValue("qmldir state", qmldirState)}; keyValue("qmldir state", qmldirState)};
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) { std::ranges::sort(components,
return first.fileName < second.fileName; [](auto &&first, auto &&second) { return first.fileName < second.fileName; });
});
auto directoryPath = m_pathCache.sourceContextPath(directoryId); auto directoryPath = m_pathCache.sourceContextPath(directoryId);

View File

@@ -830,6 +830,82 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents)
updater.update({.directories = directories}); updater.update({.directories = directories});
} }
TEST_F(ProjectStorageUpdater, skip_duplicate_qmldir_entries)
{
QString qmldir{R"(module Example
FirstType 1.0 First.qml
FirstType 1.0 First.qml
FirstType 2.0 First.qml
FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"};
setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(
projectStorageMock,
synchronize(AllOf(
Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
Field(
&SynchronizationPackage::types,
UnorderedElementsAre(
AllOf(IsStorageType("First.qml",
Storage::Synchronization::ImportedType{"Object"},
TypeTraitsKind::Reference,
qmlDocumentSourceId1,
Storage::Synchronization::ChangeLevel::Full),
Field(&Storage::Synchronization::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
IsExportedType(exampleModuleId, "FirstType", 2, 0),
IsExportedType(pathModuleId, "First", -1, -1)))),
AllOf(IsStorageType("First2.qml",
Storage::Synchronization::ImportedType{"Object2"},
TypeTraitsKind::Reference,
qmlDocumentSourceId2,
Storage::Synchronization::ChangeLevel::Full),
Field(&Storage::Synchronization::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
IsExportedType(pathModuleId, "First2", -1, -1)))),
AllOf(IsStorageType("Second.qml",
Storage::Synchronization::ImportedType{"Object3"},
TypeTraitsKind::Reference,
qmlDocumentSourceId3,
Storage::Synchronization::ChangeLevel::Full),
Field(&Storage::Synchronization::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
IsExportedType(pathModuleId, "Second", -1, -1)))))),
Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1,
qmlDocumentSourceId2,
qmlDocumentSourceId3)),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1,
qmlDocumentSourceId2,
qmlDocumentSourceId3)),
Field(&SynchronizationPackage::fileStatuses,
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
IsFileStatus(qmlDocumentSourceId1, 1, 21),
IsFileStatus(qmlDocumentSourceId2, 1, 21),
IsFileStatus(qmlDocumentSourceId3, 1, 21))),
Field(&SynchronizationPackage::updatedDirectoryInfoSourceIds,
UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::directoryInfos,
UnorderedElementsAre(IsDirectoryInfo(directoryPathSourceId,
qmlDocumentSourceId1,
ModuleId{},
FileType::QmlDocument),
IsDirectoryInfo(directoryPathSourceId,
qmlDocumentSourceId2,
ModuleId{},
FileType::QmlDocument),
IsDirectoryInfo(directoryPathSourceId,
qmlDocumentSourceId3,
ModuleId{},
FileType::QmlDocument))))));
updater.update({.directories = directories});
}
TEST_F(ProjectStorageUpdater, synchronize_add_only_qml_document_in_directory) TEST_F(ProjectStorageUpdater, synchronize_add_only_qml_document_in_directory)
{ {
QString qmldir{R"(module Example QString qmldir{R"(module Example