aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2021-10-21 17:23:18 +0200
committerMarco Bubke <marco.bubke@qt.io>2021-12-08 15:00:44 +0000
commit56af8b905e17254b86bad73a02c023b043039a31 (patch)
tree179f1083022ed13a39c8882cc8a48718998eb928
parent1fdc358eef46bdc195bb935fd95a17a3828c0818 (diff)
QmlDesigner: Improve project storage update
Task-number: QDS-4920 Change-Id: If5a839a6862bab50fe3a3e049cb1214f04eeca1a Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h58
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h6
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h41
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp241
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h39
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp53
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h8
-rw-r--r--tests/unit/unittest/projectstorage-test.cpp26
-rw-r--r--tests/unit/unittest/projectstorageupdater-test.cpp356
-rw-r--r--tests/unit/unittest/qmltypesparser-test.cpp3
10 files changed, 700 insertions, 131 deletions
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
index 5df23b7385..83131404de 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
@@ -77,14 +77,15 @@ public:
TypeIds typeIdsToBeDeleted;
- auto sourceIdValues = Utils::transform<std::vector>(package.sourceIds, [](SourceId sourceId) {
- return &sourceId;
- });
+ auto updatedSourceIdValues = Utils::transform<std::vector>(package.updatedSourceIds,
+ [](SourceId sourceId) {
+ return &sourceId;
+ });
- std::sort(sourceIdValues.begin(), sourceIdValues.end());
+ std::sort(updatedSourceIdValues.begin(), updatedSourceIdValues.end());
- synchronizeFileStatuses(package.fileStatuses, sourceIdValues);
- synchronizeImports(package.imports, sourceIdValues);
+ synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
+ synchronizeImports(package.imports, updatedSourceIdValues);
synchronizeTypes(package.types,
updatedTypeIds,
insertedAliasPropertyDeclarations,
@@ -92,10 +93,10 @@ public:
relinkableAliasPropertyDeclarations,
relinkablePropertyDeclarations,
relinkablePrototypes,
- sourceIdValues);
+ updatedSourceIdValues);
deleteNotUpdatedTypes(updatedTypeIds,
- sourceIdValues,
+ updatedSourceIdValues,
typeIdsToBeDeleted,
relinkableAliasPropertyDeclarations,
relinkablePropertyDeclarations,
@@ -503,7 +504,7 @@ private:
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
- const std::vector<int> &sourceIdValues)
+ const std::vector<int> &updatedSourceIdValues)
{
Storage::ExportedTypes exportedTypes;
exportedTypes.reserve(types.size() * 3);
@@ -517,7 +518,7 @@ private:
extractExportedTypes(typeId, type, exportedTypes);
}
- synchronizeExportedTypes(sourceIdValues,
+ synchronizeExportedTypes(updatedSourceIdValues,
updatedTypeIds,
exportedTypes,
relinkableAliasPropertyDeclarations,
@@ -532,8 +533,13 @@ private:
relinkablePropertyDeclarations);
}
- void synchronizeFileStatuses(FileStatuses &fileStatuses, const std::vector<int> &sourceIdValues)
+ void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds)
{
+ auto updatedSourceIdValues = Utils::transform<std::vector>(updatedSourceIds,
+ [](SourceId sourceId) {
+ return &sourceId;
+ });
+
auto compareKey = [](auto &&first, auto &&second) {
return first.sourceId.id - second.sourceId.id;
};
@@ -543,7 +549,7 @@ private:
});
auto range = selectFileStatusesForSourceIdsStatement.template range<FileStatus>(
- Utils::span(sourceIdValues));
+ Utils::span(updatedSourceIdValues));
auto insert = [&](const FileStatus &fileStatus) {
insertFileStatusStatement.write(&fileStatus.sourceId,
@@ -567,15 +573,15 @@ private:
Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove);
}
- void synchronizeImports(Storage::Imports &imports, std::vector<int> &sourceIdValues)
+ void synchronizeImports(Storage::Imports &imports, std::vector<int> &updatedSourceIdValues)
{
- deleteDocumentImportsForDeletedDocuments(imports, sourceIdValues);
+ deleteDocumentImportsForDeletedDocuments(imports, updatedSourceIdValues);
- synchronizeDocumentImports(imports, sourceIdValues);
+ synchronizeDocumentImports(imports, updatedSourceIdValues);
}
void deleteDocumentImportsForDeletedDocuments(Storage::Imports &imports,
- const std::vector<int> &sourceIdValues)
+ const std::vector<int> &updatedSourceIdValues)
{
std::vector<int> importSourceIds = Utils::transform<std::vector<int>>(
imports, [](const Storage::Import &import) { return &import.sourceId; });
@@ -584,8 +590,8 @@ private:
std::vector<int> documentSourceIdsToBeDeleted;
- std::set_difference(sourceIdValues.begin(),
- sourceIdValues.end(),
+ std::set_difference(updatedSourceIdValues.begin(),
+ updatedSourceIdValues.end(),
importSourceIds.begin(),
importSourceIds.end(),
std::back_inserter(documentSourceIdsToBeDeleted));
@@ -767,7 +773,7 @@ private:
}
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
- const std::vector<int> &sourceIdValues,
+ const std::vector<int> &updatedSourceIdValues,
const TypeIds &typeIdsToBeDeleted,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
@@ -788,7 +794,7 @@ private:
};
selectNotUpdatedTypesInSourcesStatement.readCallback(callback,
- Utils::span(sourceIdValues),
+ Utils::span(updatedSourceIdValues),
Utils::span(updatedTypeIdValues));
for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted)
callback(&typeIdToBeDeleted);
@@ -853,7 +859,7 @@ private:
updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations);
}
- void synchronizeExportedTypes(const std::vector<int> &sourceIdValues,
+ void synchronizeExportedTypes(const std::vector<int> &updatedSourceIdValues,
const TypeIds &updatedTypeIds,
Storage::ExportedTypes &exportedTypes,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
@@ -869,9 +875,8 @@ private:
&updatedTypeIds.data()->id),
updatedTypeIds.size()};
- auto range = selectExportedTypesForSourceIdsStatement
- .template range<Storage::ExportedTypeView>(Utils::span{sourceIdValues},
- typeIdValues);
+ auto range = selectExportedTypesForSourceIdsStatement.template range<Storage::ExportedTypeView>(
+ Utils::span{updatedSourceIdValues}, typeIdValues);
auto compareKey = [](const Storage::ExportedTypeView &view,
const Storage::ExportedType &type) -> long long {
@@ -1151,7 +1156,8 @@ private:
PropertyCompare<AliasPropertyDeclaration>{});
}
- void synchronizeDocumentImports(Storage::Imports &imports, const std::vector<int> &sourceIdValues)
+ void synchronizeDocumentImports(Storage::Imports &imports,
+ const std::vector<int> &updatedSourceIdValues)
{
std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
return std::tie(first.sourceId, first.moduleId, first.version)
@@ -1159,7 +1165,7 @@ private:
});
auto range = selectDocumentImportForSourceIdStatement.template range<Storage::ImportView>(
- Utils::span{sourceIdValues});
+ Utils::span{updatedSourceIdValues});
auto compareKey = [](const Storage::ImportView &view,
const Storage::Import &import) -> long long {
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
index 42790bded6..c95d3e00e2 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
@@ -107,4 +107,10 @@ public:
const char *what() const noexcept override { return "Cannot parse qml types file!"; }
};
+class CannotParseQmlDocumentFile : std::exception
+{
+public:
+ const char *what() const noexcept override { return "Cannot parse qml types file!"; }
+};
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
index 366da00407..b564372a86 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
@@ -47,6 +47,8 @@ enum class PropertyDeclarationTraits : unsigned int {
enum class TypeNameKind { Native = 0, Exported = 1, QualifiedExported = 2 };
+enum class FileType : char { QmlTypes, QmlDocument };
+
constexpr PropertyDeclarationTraits operator|(PropertyDeclarationTraits first,
PropertyDeclarationTraits second)
{
@@ -630,7 +632,7 @@ public:
PropertyDeclarationId aliasId;
};
-enum class ChangeLevel { Full, Minimal };
+enum class ChangeLevel : char { Full, Minimal, ExcludeExportedTypes };
class Type
{
@@ -669,6 +671,18 @@ public:
{}
explicit Type(Utils::SmallStringView typeName,
+ ImportedTypeName prototype,
+ TypeAccessSemantics accessSemantics,
+ SourceId sourceId,
+ ChangeLevel changeLevel)
+ : typeName{typeName}
+ , prototype{std::move(prototype)}
+ , accessSemantics{accessSemantics}
+ , sourceId{sourceId}
+ , changeLevel{changeLevel}
+ {}
+
+ explicit Type(Utils::SmallStringView typeName,
Utils::SmallStringView prototype,
int accessSemantics,
int sourceId)
@@ -721,8 +735,16 @@ using Types = std::vector<Type>;
class ProjectData
{
public:
+ ProjectData(ModuleId extraModuleId, SourceId sourceId, FileType fileType)
+ : extraModuleId{extraModuleId}
+ , sourceId{sourceId}
+ , fileType{fileType}
+ {}
+
+public:
ModuleId extraModuleId;
SourceId sourceId;
+ FileType fileType;
};
using ProjectDatas = std::vector<ProjectData>;
@@ -731,30 +753,33 @@ class SynchronizationPackage
{
public:
SynchronizationPackage() = default;
- SynchronizationPackage(Imports imports, Types types, SourceIds sourceIds)
+ SynchronizationPackage(Imports imports, Types types, SourceIds updatedSourceIds)
: imports{std::move(imports)}
, types{std::move(types)}
- , sourceIds(std::move(sourceIds))
+ , updatedSourceIds(std::move(updatedSourceIds))
{}
SynchronizationPackage(Types types)
: types{std::move(types)}
{}
- SynchronizationPackage(SourceIds sourceIds)
- : sourceIds(std::move(sourceIds))
+ SynchronizationPackage(SourceIds updatedSourceIds)
+ : updatedSourceIds(std::move(updatedSourceIds))
{}
- SynchronizationPackage(SourceIds sourceIds, FileStatuses fileStatuses)
- : sourceIds(std::move(sourceIds))
+ SynchronizationPackage(SourceIds updatedSourceIds, FileStatuses fileStatuses)
+ : updatedSourceIds(std::move(updatedSourceIds))
, fileStatuses(std::move(fileStatuses))
{}
public:
Imports imports;
Types types;
- SourceIds sourceIds;
+ SourceIds updatedSourceIds;
FileStatuses fileStatuses;
+ ProjectDatas projectDatas;
+ ModuleIds updatedProjectDataModuleIds;
+ SourceIds updatedFileStatusSourceIds;
};
} // namespace QmlDesigner::Storage
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
index cc91a06fae..3f3ac32166 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
@@ -38,6 +38,7 @@
#include <functional>
namespace QmlDesigner {
+namespace {
ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirParser::Component> &components)
{
@@ -50,45 +51,103 @@ ComponentReferences createComponentReferences(const QMultiHash<QString, QmlDirPa
return componentReferences;
}
+SourceIds filterNotUpdatedSourceIds(SourceIds updatedSourceIds, SourceIds notUpdatedSourceIds)
+{
+ std::sort(updatedSourceIds.begin(), updatedSourceIds.end());
+ std::sort(notUpdatedSourceIds.begin(), notUpdatedSourceIds.end());
+
+ SourceIds filteredUpdatedSourceIds;
+ filteredUpdatedSourceIds.reserve(updatedSourceIds.size());
+
+ std::set_difference(updatedSourceIds.cbegin(),
+ updatedSourceIds.cend(),
+ notUpdatedSourceIds.cbegin(),
+ notUpdatedSourceIds.cend(),
+ std::back_inserter(filteredUpdatedSourceIds));
+
+ filteredUpdatedSourceIds.erase(std::unique(filteredUpdatedSourceIds.begin(),
+ filteredUpdatedSourceIds.end()),
+ filteredUpdatedSourceIds.end());
+
+ return filteredUpdatedSourceIds;
+}
+
+void addSourceIds(SourceIds &sourceIds, const Storage::ProjectDatas &projectDatas)
+{
+ for (const auto &projectData : projectDatas)
+ sourceIds.push_back(projectData.sourceId);
+}
+
+} // namespace
+
void ProjectUpdater::update()
{
Storage::SynchronizationPackage package;
+ SourceIds notUpdatedFileStatusSourceIds;
+ SourceIds notUpdatedSourceIds;
+
for (const QString &qmldirPath : m_projectManager.qtQmlDirs()) {
SourcePath qmldirSourcePath{qmldirPath};
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
- switch (fileState(qmlDirSourceId, package.fileStatuses)) {
+ auto state = fileState(qmlDirSourceId,
+ package.fileStatuses,
+ package.updatedFileStatusSourceIds,
+ notUpdatedFileStatusSourceIds);
+ switch (state) {
case FileState::Changed: {
QmlDirParser parser;
parser.parse(m_fileSystem.contentAsQString(qmldirPath));
- package.sourceIds.push_back(qmlDirSourceId);
+ package.updatedSourceIds.push_back(qmlDirSourceId);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString moduleName{parser.typeNamespace()};
ModuleId moduleId = m_projectStorage.moduleId(moduleName);
- parseTypeInfos(parser.typeInfos(), directoryId, package);
+ const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
+ addSourceIds(package.updatedSourceIds, qmlProjectDatas);
+ addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
+
+ parseTypeInfos(parser.typeInfos(),
+ directoryId,
+ moduleId,
+ package,
+ notUpdatedFileStatusSourceIds,
+ notUpdatedSourceIds);
parseQmlComponents(createComponentReferences(parser.components()),
directoryId,
moduleId,
- package);
+ package,
+ notUpdatedFileStatusSourceIds);
+ package.updatedProjectDataModuleIds.push_back(moduleId);
break;
}
case FileState::NotChanged: {
- auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
- parseTypeInfos(qmlProjectDatas, package);
+ const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
+ parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
+ parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds);
break;
}
case FileState::NotExists: {
- // sourceIds.push_back(qmlDirSourceId);
+ package.updatedSourceIds.push_back(qmlDirSourceId);
+ auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
+ for (const Storage::ProjectData &projectData : qmlProjectDatas) {
+ package.updatedSourceIds.push_back(projectData.sourceId);
+ }
+
break;
}
}
}
+ package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
+ std::move(notUpdatedSourceIds));
+ package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
+ std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedFileStatusSourceIds));
+
m_projectStorage.synchronize(std::move(package));
}
@@ -96,7 +155,10 @@ void ProjectUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) {}
void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceContextId directoryId,
- Storage::SynchronizationPackage &package)
+ ModuleId moduleId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds)
{
QString directory{m_pathCache.sourceContextPath(directoryId)};
@@ -104,37 +166,137 @@ void ProjectUpdater::parseTypeInfos(const QStringList &typeInfos,
SourceId sourceId = m_pathCache.sourceId(directoryId, Utils::SmallString{typeInfo});
QString qmltypesPath = directory + "/" + typeInfo;
- Storage::ProjectData projectData{ModuleId{}, sourceId};
+ auto projectData = package.projectDatas.emplace_back(moduleId,
+ sourceId,
+ Storage::FileType::QmlTypes);
- parseTypeInfo(projectData, qmltypesPath, package);
+ parseTypeInfo(projectData,
+ qmltypesPath,
+ package,
+ notUpdatedFileStatusSourceIds,
+ notUpdatedSourceIds);
}
}
void ProjectUpdater::parseTypeInfos(const Storage::ProjectDatas &projectDatas,
- Storage::SynchronizationPackage &package)
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds)
{
for (const Storage::ProjectData &projectData : projectDatas) {
+ if (projectData.fileType != Storage::FileType::QmlTypes)
+ continue;
+
QString qmltypesPath = m_pathCache.sourcePath(projectData.sourceId).toQString();
- parseTypeInfo(projectData, qmltypesPath, package);
+ parseTypeInfo(projectData,
+ qmltypesPath,
+ package,
+ notUpdatedFileStatusSourceIds,
+ notUpdatedSourceIds);
}
}
void ProjectUpdater::parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath,
- Storage::SynchronizationPackage &package)
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds)
{
- if (fileState(projectData.sourceId, package.fileStatuses) == FileState::Changed) {
- package.sourceIds.push_back(projectData.sourceId);
+ auto state = fileState(projectData.sourceId,
+ package.fileStatuses,
+ package.updatedFileStatusSourceIds,
+ notUpdatedFileStatusSourceIds);
+ switch (state) {
+ case FileState::Changed: {
+ package.updatedSourceIds.push_back(projectData.sourceId);
+
const auto content = m_fileSystem.contentAsQString(qmltypesPath);
m_qmlTypesParser.parse(content, package.imports, package.types, projectData);
+ break;
+ }
+ case FileState::NotChanged: {
+ notUpdatedSourceIds.push_back(projectData.sourceId);
+ break;
+ }
+ case FileState::NotExists:
+ break;
}
}
+void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
+ Utils::SmallStringView directory,
+ Utils::SmallStringView typeName,
+ Storage::Version version,
+ ModuleId moduleId,
+ SourceContextId directoryId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds)
+{
+ SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
+
+ Storage::Type type;
+
+ auto state = fileState(sourceId,
+ package.fileStatuses,
+ package.updatedFileStatusSourceIds,
+ notUpdatedFileStatusSourceIds);
+ switch (state) {
+ case FileState::NotChanged:
+ type.changeLevel = Storage::ChangeLevel::Minimal;
+ break;
+ case FileState::NotExists:
+ throw CannotParseQmlDocumentFile{};
+ case FileState::Changed:
+ const auto content = m_fileSystem.contentAsQString(
+ QString{Utils::PathString{directory} + "/" + fileName});
+ type = m_qmlDocumentParser.parse(content, package.imports);
+ break;
+ }
+
+ package.projectDatas.emplace_back(moduleId, sourceId, Storage::FileType::QmlDocument);
+
+ package.updatedSourceIds.push_back(sourceId);
+
+ type.typeName = fileName;
+ type.accessSemantics = Storage::TypeAccessSemantics::Reference;
+ type.sourceId = sourceId;
+ type.exportedTypes.push_back(Storage::ExportedType{moduleId, typeName, version});
+
+ package.types.push_back(std::move(type));
+}
+
+void ProjectUpdater::parseQmlComponent(Utils::SmallStringView fileName,
+ Utils::SmallStringView filePath,
+ SourceId sourceId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds)
+{
+ auto state = fileState(sourceId,
+ package.fileStatuses,
+ package.updatedFileStatusSourceIds,
+ notUpdatedFileStatusSourceIds);
+ if (state != FileState::Changed)
+ return;
+
+ package.updatedSourceIds.push_back(sourceId);
+
+ const auto content = m_fileSystem.contentAsQString(QString{filePath});
+ auto type = m_qmlDocumentParser.parse(content, package.imports);
+
+ type.typeName = fileName;
+ type.accessSemantics = Storage::TypeAccessSemantics::Reference;
+ type.sourceId = sourceId;
+ type.changeLevel = Storage::ChangeLevel::ExcludeExportedTypes;
+
+ package.types.push_back(std::move(type));
+}
+
void ProjectUpdater::parseQmlComponents(ComponentReferences components,
SourceContextId directoryId,
ModuleId moduleId,
- Storage::SynchronizationPackage &package)
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds)
{
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return std::tie(first.get().typeName, first.get().majorVersion, first.get().minorVersion)
@@ -148,33 +310,42 @@ void ProjectUpdater::parseQmlComponents(ComponentReferences components,
components.erase(newEnd, components.end());
- QString directory{m_pathCache.sourceContextPath(directoryId)};
+ auto directory = m_pathCache.sourceContextPath(directoryId);
for (const QmlDirParser::Component &component : components) {
- Utils::SmallString fileName{component.fileName};
- SourceId sourceId = m_pathCache.sourceId(directoryId, fileName);
+ parseQmlComponent(Utils::SmallString{component.fileName},
+ directory,
+ Utils::SmallString{component.typeName},
+ Storage::Version{component.majorVersion, component.minorVersion},
+ moduleId,
+ directoryId,
+ package,
+ notUpdatedFileStatusSourceIds);
+ }
+}
- if (fileState(sourceId, package.fileStatuses) != FileState::Changed)
+void ProjectUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds)
+{
+ for (const Storage::ProjectData &projectData : projectDatas) {
+ if (projectData.fileType != Storage::FileType::QmlDocument)
continue;
- package.sourceIds.push_back(sourceId);
-
- const auto content = m_fileSystem.contentAsQString(directory + "/" + component.fileName);
- auto type = m_qmlDocumentParser.parse(content, package.imports);
-
- type.typeName = fileName;
- type.accessSemantics = Storage::TypeAccessSemantics::Reference;
- type.sourceId = sourceId;
- type.exportedTypes.push_back(
- Storage::ExportedType{moduleId,
- Utils::SmallString{component.typeName},
- Storage::Version{component.majorVersion, component.minorVersion}});
+ SourcePath qmlDocumentPath = m_pathCache.sourcePath(projectData.sourceId);
- package.types.push_back(std::move(type));
+ parseQmlComponent(qmlDocumentPath.name(),
+ qmlDocumentPath,
+ projectData.sourceId,
+ package,
+ notUpdatedFileStatusSourceIds);
}
}
-ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, FileStatuses &fileStatuses) const
+ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId,
+ FileStatuses &fileStatuses,
+ SourceIds &updatedSourceIds,
+ SourceIds &notUpdatedSourceIds) const
{
auto currentFileStatus = m_fileStatusCache.find(sourceId);
@@ -185,9 +356,11 @@ ProjectUpdater::FileState ProjectUpdater::fileState(SourceId sourceId, FileStatu
if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) {
fileStatuses.push_back(currentFileStatus);
+ updatedSourceIds.push_back(currentFileStatus.sourceId);
return FileState::Changed;
}
+ notUpdatedSourceIds.push_back(currentFileStatus.sourceId);
return FileState::NotChanged;
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
index e3323d7609..237c75e5da 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
@@ -88,18 +88,45 @@ private:
void parseTypeInfos(const QStringList &typeInfos,
SourceContextId directoryId,
- Storage::SynchronizationPackage &package);
+ ModuleId moduleId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds);
void parseTypeInfos(const Storage::ProjectDatas &projectDatas,
- Storage::SynchronizationPackage &package);
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds);
void parseTypeInfo(const Storage::ProjectData &projectData,
const QString &qmltypesPath,
- Storage::SynchronizationPackage &package);
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds,
+ SourceIds &notUpdatedSourceIds);
void parseQmlComponents(ComponentReferences components,
SourceContextId directoryId,
ModuleId moduleId,
- Storage::SynchronizationPackage &package);
-
- FileState fileState(SourceId sourceId, FileStatuses &fileStatuses) const;
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds);
+ void parseQmlComponents(const Storage::ProjectDatas &projectDatas,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds);
+ void parseQmlComponent(Utils::SmallStringView fileName,
+ Utils::SmallStringView directory,
+ Utils::SmallStringView typeName,
+ Storage::Version version,
+ ModuleId moduleId,
+ SourceContextId directoryId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds);
+ void parseQmlComponent(Utils::SmallStringView fileName,
+ Utils::SmallStringView filePath,
+ SourceId sourceId,
+ Storage::SynchronizationPackage &package,
+ SourceIds &notUpdatedFileStatusSourceIds);
+
+ FileState fileState(SourceId sourceId,
+ FileStatuses &fileStatuses,
+ SourceIds &updatedSourceIds,
+ SourceIds &notUpdatedSourceIds) const;
private:
ProjectManagerInterface &m_projectManager;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 3123ffcf1d..49831bab17 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -1070,8 +1070,56 @@ const char *importKindToText(ImportKind kind)
return "";
}
+const char *fileTypeToText(FileType fileType)
+{
+ switch (fileType) {
+ case FileType::QmlDocument:
+ return "QmlDocument";
+ case FileType::QmlTypes:
+ return "QmlTypes";
+ }
+
+ return "";
+}
+
+const char *changeLevelToText(ChangeLevel changeLevel)
+{
+ switch (changeLevel) {
+ case ChangeLevel::Full:
+ return "Full";
+ case ChangeLevel::Minimal:
+ return "Minimal";
+ case ChangeLevel::ExcludeExportedTypes:
+ return "ExcludeExportedTypes";
+ }
+
+ return "";
+}
+
} // namespace
+std::ostream &operator<<(std::ostream &out, FileType fileType)
+{
+ return out << fileTypeToText(fileType);
+}
+
+std::ostream &operator<<(std::ostream &out, ChangeLevel changeLevel)
+{
+ return out << changeLevelToText(changeLevel);
+}
+
+std::ostream &operator<<(std::ostream &out, const SynchronizationPackage &package)
+{
+ return out << "(" << package.imports << ", " << package.types << ", "
+ << package.updatedSourceIds << ", " << package.fileStatuses << ", "
+ << package.updatedFileStatusSourceIds << ", " << package.projectDatas << ")";
+}
+
+std::ostream &operator<<(std::ostream &out, const ProjectData &data)
+{
+ return out << "(" << data.extraModuleId << ", " << data.sourceId << ", " << data.fileType << ")";
+}
+
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics)
{
return out << typeAccessSemanticsToString(accessSemantics)
@@ -1106,7 +1154,7 @@ std::ostream &operator<<(std::ostream &out, const NativeType &nativeType)
std::ostream &operator<<(std::ostream &out, const ImportedType &importedType)
{
- return out << "(\"" << importedType.name << ")";
+ return out << "(\"" << importedType.name << "\")";
}
std::ostream &operator<<(std::ostream &out, const QualifiedImportedType &importedType)
{
@@ -1120,7 +1168,8 @@ std::ostream &operator<<(std::ostream &out, const Type &type)
<< type.prototypeId << ", " << type.accessSemantics << ", source: " << type.sourceId
<< ", exports: " << type.exportedTypes << ", properties: " << type.propertyDeclarations
<< ", functions: " << type.functionDeclarations
- << ", signals: " << type.signalDeclarations << ")";
+ << ", signals: " << type.signalDeclarations << ", changeLevel: " << type.changeLevel
+ << ")";
}
std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyDeclaration)
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index 074fada6d9..d84534b9b0 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -263,6 +263,10 @@ class EnumeratorDeclaration;
enum class ImportKind : char;
class Import;
enum class IsQualified : int;
+class ProjectData;
+class SynchronizationPackage;
+enum class FileType : char;
+enum class ChangeLevel : char;
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics);
std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
@@ -282,6 +286,10 @@ std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumera
std::ostream &operator<<(std::ostream &out, const ImportKind &importKind);
std::ostream &operator<<(std::ostream &out, const Import &import);
std::ostream &operator<<(std::ostream &out, IsQualified isQualified);
+std::ostream &operator<<(std::ostream &out, const ProjectData &data);
+std::ostream &operator<<(std::ostream &out, const SynchronizationPackage &package);
+std::ostream &operator<<(std::ostream &out, FileType fileType);
+std::ostream &operator<<(std::ostream &out, ChangeLevel changeLevel);
} // namespace Storage
diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp
index 43ac728fd9..dd46b0ae59 100644
--- a/tests/unit/unittest/projectstorage-test.cpp
+++ b/tests/unit/unittest/projectstorage-test.cpp
@@ -266,7 +266,7 @@ protected:
Storage::ExportedType{qmlModuleId, "Obj", Storage::Version{2}},
Storage::ExportedType{qmlNativeModuleId, "QObject"}}});
- package.sourceIds = {sourceId1, sourceId2};
+ package.updatedSourceIds = {sourceId1, sourceId2};
return package;
}
@@ -324,8 +324,8 @@ protected:
Storage::ImportedType{"QObject"},
Storage::PropertyDeclarationTraits::IsList});
- package.sourceIds.push_back(sourceId3);
- package.sourceIds.push_back(sourceId4);
+ package.updatedSourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId4);
return package;
}
@@ -359,7 +359,7 @@ protected:
package.types.back().propertyDeclarations.push_back(
Storage::PropertyDeclaration{"objects", Storage::ImportedType{"AliasItem"}, "objects"});
- package.sourceIds.push_back(sourceId5);
+ package.updatedSourceIds.push_back(sourceId5);
return package;
}
@@ -403,7 +403,7 @@ protected:
Storage::ExportedType{qmlModuleId, "BuiltInObj", Storage::Version{3, 4}},
Storage::ExportedType{qmlNativeModuleId, "QObject4"}}});
- package.sourceIds.push_back(sourceId1);
+ package.updatedSourceIds.push_back(sourceId1);
return package;
}
@@ -2400,7 +2400,7 @@ TEST_F(ProjectStorage,
sourceId5,
{Storage::ExportedType{qtQuickModuleId, "Object2"},
Storage::ExportedType{qtQuickModuleId, "Obj2"}}});
- package.sourceIds.push_back(sourceId5);
+ package.updatedSourceIds.push_back(sourceId5);
storage.synchronize(package);
@@ -2849,7 +2849,7 @@ TEST_F(ProjectStorage, QualifiedPrototype)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -2884,7 +2884,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -2908,7 +2908,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
}
@@ -2924,7 +2924,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -2948,7 +2948,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object", Storage::Version{2}}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -2981,7 +2981,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -3013,7 +3013,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain)
sourceId3,
{Storage::ExportedType{qtQuickModuleId, "Object"}}});
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
- package.sourceIds.push_back(sourceId3);
+ package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp
index c26aaa7b70..ef3109be2a 100644
--- a/tests/unit/unittest/projectstorageupdater-test.cpp
+++ b/tests/unit/unittest/projectstorageupdater-test.cpp
@@ -47,21 +47,24 @@ using QmlDesigner::SourceId;
using QmlDesigner::Storage::TypeAccessSemantics;
namespace Storage = QmlDesigner::Storage;
using QmlDesigner::IdPaths;
+using QmlDesigner::Storage::FileType;
using QmlDesigner::Storage::SynchronizationPackage;
using QmlDesigner::Storage::Version;
-MATCHER_P4(IsStorageType,
+MATCHER_P5(IsStorageType,
typeName,
prototype,
accessSemantics,
sourceId,
+ changeLevel,
std::string(negation ? "isn't " : "is ")
- + PrintToString(Storage::Type{typeName, prototype, accessSemantics, sourceId}))
+ + PrintToString(Storage::Type(typeName, prototype, accessSemantics, sourceId, changeLevel)))
{
const Storage::Type &type = arg;
return type.typeName == typeName && type.accessSemantics == accessSemantics
- && type.sourceId == sourceId && Storage::ImportedTypeName{prototype} == type.prototype;
+ && type.sourceId == sourceId && Storage::ImportedTypeName{prototype} == type.prototype
+ && type.changeLevel == changeLevel;
}
MATCHER_P3(IsPropertyDeclaration,
@@ -107,12 +110,27 @@ MATCHER_P3(IsFileStatus,
&& fileStatus.lastModified == lastModified;
}
+MATCHER_P3(IsProjectData,
+ moduleId,
+ sourceId,
+ fileType,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::ProjectData{moduleId, sourceId, fileType}))
+{
+ const Storage::ProjectData &projectData = arg;
+
+ return projectData.sourceId == sourceId && projectData.extraModuleId == moduleId
+ && projectData.fileType == fileType;
+}
+
MATCHER(PackageIsEmpty, std::string(negation ? "isn't empty" : "is empty"))
{
const Storage::SynchronizationPackage &package = arg;
return package.imports.empty() && package.types.empty() && package.fileStatuses.empty()
- && package.sourceIds.empty();
+ && package.updatedSourceIds.empty() && package.projectDatas.empty()
+ && package.updatedFileStatusSourceIds.empty()
+ && package.updatedProjectDataModuleIds.empty();
}
class ProjectStorageUpdater : public testing::Test
@@ -135,15 +153,9 @@ public:
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
.WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421}));
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(
- Return(QmlDesigner::Storage::ProjectDatas{{ModuleId{}, qmltypesPathSourceId},
- {ModuleId{}, qmltypes2PathSourceId}}));
-
- QString qmldir{"module Example\ntypeinfo example.qmltypes\n"};
ON_CALL(projectManagerMock, qtQmlDirs()).WillByDefault(Return(QStringList{"/path/qmldir"}));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillByDefault(Return(qmldir));
+ .WillByDefault(Return(qmldirContent));
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 12}));
@@ -170,6 +182,10 @@ public:
.WillByDefault(Return(qmlDocument2));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
.WillByDefault(Return(qmlDocument3));
+ ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
+ .WillByDefault(Return(qmltypes1));
+ ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes"))))
+ .WillByDefault(Return(qmltypes2));
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _)).WillByDefault([&](auto, auto &imports) {
imports.push_back(import1);
@@ -183,6 +199,16 @@ public:
imports.push_back(import3);
return thirdType;
});
+ ON_CALL(qmlTypesParserMock, parse(Eq(qmltypes1), _, _, _))
+ .WillByDefault([&](auto, auto &imports, auto &types, auto) {
+ types.push_back(objectType);
+ imports.push_back(import4);
+ });
+ ON_CALL(qmlTypesParserMock, parse(Eq(qmltypes2), _, _, _))
+ .WillByDefault([&](auto, auto &imports, auto &types, auto) {
+ types.push_back(itemType);
+ imports.push_back(import5);
+ });
}
protected:
@@ -203,8 +229,6 @@ protected:
sourcePathCache,
qmlDocumentParserMock,
qmlTypesParserMock};
- SourceId objectTypeSourceId{sourcePathCache.sourceId("/path/Object")};
-
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes");
SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
@@ -216,9 +240,14 @@ protected:
Storage::Type objectType{"QObject",
Storage::NativeType{},
Storage::TypeAccessSemantics::Reference,
- objectTypeSourceId,
+ qmltypesPathSourceId,
{Storage::ExportedType{exampleModuleId, "Object"},
Storage::ExportedType{exampleModuleId, "Obj"}}};
+ Storage::Type itemType{"QItem",
+ Storage::NativeType{},
+ Storage::TypeAccessSemantics::Reference,
+ qmltypes2PathSourceId,
+ {Storage::ExportedType{exampleModuleId, "Item"}}};
QString qmlDocument1{"First{}"};
QString qmlDocument2{"Second{}"};
QString qmlDocument3{"Third{}"};
@@ -228,6 +257,11 @@ protected:
Storage::Import import1{qmlModuleId, Storage::Version{2, 3}, qmlDocumentSourceId1};
Storage::Import import2{qmlModuleId, Storage::Version{}, qmlDocumentSourceId2};
Storage::Import import3{qmlModuleId, Storage::Version{2}, qmlDocumentSourceId3};
+ Storage::Import import4{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId};
+ Storage::Import import5{qmlModuleId, Storage::Version{2, 3}, qmltypes2PathSourceId};
+ QString qmldirContent{"module Example\ntypeinfo example.qmltypes\n"};
+ QString qmltypes1{"Module {\ndependencies: [module1]}"};
+ QString qmltypes2{"Module {\ndependencies: [module2]}"};
};
TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
@@ -266,7 +300,8 @@ TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
{
- QString qmldir{"module Example\ntypeinfo example.qmltypes\n"};
+ QString qmldir{R"(module Example
+ typeinfo example.qmltypes)"};
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillRepeatedly(Return(qmldir));
@@ -277,7 +312,8 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsInvalid)
{
- QString qmldir{"module Example\ntypeinfo example.qmltypes\n"};
+ QString qmldir{R"(module Example
+ typeinfo example.qmltypes)"};
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillRepeatedly(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypesPathSourceId)))
@@ -290,7 +326,8 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsI
TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsInvalid)
{
- QString qmldir{"module Example\ntypeinfo example.qmltypes\n"};
+ QString qmldir{R"(module Example
+ typeinfo example.qmltypes)"};
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
.WillRepeatedly(Return(qmldir));
ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId))).WillByDefault(Return(FileStatus{}));
@@ -302,7 +339,9 @@ TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsI
TEST_F(ProjectStorageUpdater, ParseQmlTypes)
{
- QString qmldir{"module Example\ntypeinfo example.qmltypes\ntypeinfo example2.qmltypes\n"};
+ QString qmldir{R"(module Example
+ typeinfo example.qmltypes
+ typeinfo example2.qmltypes)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
QString qmltypes{"Module {\ndependencies: []}"};
QString qmltypes2{"Module {\ndependencies: [foo]}"};
@@ -333,8 +372,6 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
{
- auto qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
- auto qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
Storage::Import import{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId};
QString qmltypes{"Module {\ndependencies: []}"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
@@ -350,11 +387,17 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
synchronize(
AllOf(Field(&SynchronizationPackage::imports, ElementsAre(import)),
Field(&SynchronizationPackage::types, ElementsAre(Eq(objectType))),
- Field(&SynchronizationPackage::sourceIds,
+ Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmltypesPathSourceId, 21, 421))))));
+ IsFileStatus(qmltypesPathSourceId, 21, 421))),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(exampleModuleId,
+ qmltypesPathSourceId,
+ FileType::QmlTypes))),
+ Field(&SynchronizationPackage::updatedProjectDataModuleIds,
+ UnorderedElementsAre(exampleModuleId)))));
updater.update();
}
@@ -394,8 +437,10 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlDocuments)
TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
{
- QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstTypeV2 2.2 "
- "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstTypeV2 2.2 First.2.qml
+ SecondType 2.2 Second.qml)"};
QString qmlDocument1{"First{}"};
QString qmlDocument2{"Second{}"};
QString qmlDocument3{"Third{}"};
@@ -414,10 +459,21 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
updater.update();
}
+TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
+{
+ QString qmldir{R"(module Example
+ NonexitingType 1.0 NonexitingType.qml)"};
+ ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+
+ ASSERT_THROW(updater.update(), QmlDesigner::CannotParseQmlDocumentFile);
+}
+
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
{
- QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstType 2.2 "
- "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First.2.qml
+ SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
EXPECT_CALL(
@@ -429,22 +485,30 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
AllOf(IsStorageType("First.qml",
Storage::ImportedType{"Object"},
TypeAccessSemantics::Reference,
- qmlDocumentSourceId1),
+ qmlDocumentSourceId1,
+ Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
AllOf(IsStorageType("First.2.qml",
Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference,
- qmlDocumentSourceId2),
+ qmlDocumentSourceId2,
+ Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))),
AllOf(IsStorageType("Second.qml",
Storage::ImportedType{"Object3"},
TypeAccessSemantics::Reference,
- qmlDocumentSourceId3),
+ qmlDocumentSourceId3,
+ Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))),
- Field(&SynchronizationPackage::sourceIds,
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId,
qmlDocumentSourceId1,
qmlDocumentSourceId2,
@@ -453,15 +517,93 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
IsFileStatus(qmlDocumentSourceId1, 22, 12),
IsFileStatus(qmlDocumentSourceId2, 22, 13),
- IsFileStatus(qmlDocumentSourceId3, 22, 14))))));
+ IsFileStatus(qmlDocumentSourceId3, 22, 14))),
+ Field(&SynchronizationPackage::updatedProjectDataModuleIds,
+ UnorderedElementsAre(exampleModuleId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(
+ IsProjectData(exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmlDocumentSourceId3, FileType::QmlDocument))))));
+
+ updater.update();
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeRemoved)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First.2.qml
+ typeinfo example.qmltypes
+ typeinfo example2.qmltypes
+ )"};
+ ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
+ .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 13}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
+ .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
+ ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(QmlDesigner::Storage::ProjectDatas{
+ {exampleModuleId, qmltypesPathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmltypes2PathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument},
+ {exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument},
+ {exampleModuleId, qmlDocumentSourceId3, FileType::QmlDocument}}));
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import4)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ AllOf(IsStorageType("First.qml",
+ Storage::ImportedType{"Object"},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId1,
+ Storage::ChangeLevel::Full),
+ Field(&Storage::Type::exportedTypes,
+ ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
+ AllOf(IsStorageType("First.2.qml",
+ Storage::NativeType{},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId2,
+ Storage::ChangeLevel::Minimal),
+ Field(&Storage::Type::exportedTypes,
+ ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmltypesPathSourceId,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
+ IsFileStatus(qmlDocumentSourceId1, 22, 12),
+ IsFileStatus(qmltypesPathSourceId, 21, 421))),
+ Field(&SynchronizationPackage::updatedProjectDataModuleIds,
+ UnorderedElementsAre(exampleModuleId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(
+ IsProjectData(exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmltypesPathSourceId, FileType::QmlTypes),
+ IsProjectData(exampleModuleId, qmltypes2PathSourceId, FileType::QmlTypes))))));
updater.update();
}
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
{
- QString qmldir{"module Example\nFirstType 1.0 First.qml\nFirstType 2.2 "
- "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First.2.qml
+ SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
@@ -475,29 +617,50 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
AllOf(IsStorageType("First.qml",
Storage::ImportedType{"Object"},
TypeAccessSemantics::Reference,
- qmlDocumentSourceId1),
+ qmlDocumentSourceId1,
+ Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes,
ElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0)))),
AllOf(IsStorageType("First.2.qml",
Storage::ImportedType{"Object2"},
TypeAccessSemantics::Reference,
- qmlDocumentSourceId2),
+ qmlDocumentSourceId2,
+ Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes,
- ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))))),
- Field(&SynchronizationPackage::sourceIds,
- UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ ElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::NativeType{},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId3,
+ Storage::ChangeLevel::Minimal),
+ Field(&Storage::Type::exportedTypes,
+ ElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
Field(&SynchronizationPackage::fileStatuses,
UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
IsFileStatus(qmlDocumentSourceId1, 22, 12),
- IsFileStatus(qmlDocumentSourceId2, 22, 13))))));
+ IsFileStatus(qmlDocumentSourceId2, 22, 13))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(
+ IsProjectData(exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument),
+ IsProjectData(exampleModuleId, qmlDocumentSourceId3, FileType::QmlDocument))))));
updater.update();
}
TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
{
- QString qmldir{"module Example\nFirstType 1.1 First.qml\nFirstType 2.2 "
- "First.2.qml\nSecondType 2.1 OldSecond.qml\nSecondType 2.2 Second.qml\n"};
+ QString qmldir{R"(module Example
+ FirstType 1.1 First.qml
+ FirstType 2.2 First.2.qml
+ SecondType 2.2 Second.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
@@ -505,4 +668,115 @@ TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
updater.pathsWithIdsChanged({});
}
+TEST_F(ProjectStorageUpdater, AddSourceIdForForInvalidQmldirFileStatus)
+{
+ ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(QmlDesigner::Storage::ProjectDatas{
+ {exampleModuleId, qmltypesPathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmltypes2PathSourceId, FileType::QmlTypes}}));
+ ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId))).WillByDefault(Return(FileStatus{}));
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types, IsEmpty()),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+ updater.update();
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
+{
+ ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(QmlDesigner::Storage::ProjectDatas{
+ {exampleModuleId, qmltypesPathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmltypes2PathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument},
+ {exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument}}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::ImportedType{"Object"},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId1,
+ Storage::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First.2.qml",
+ Storage::ImportedType{"Object2"},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId2,
+ Storage::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
+ IsFileStatus(qmltypes2PathSourceId, 21, 421),
+ IsFileStatus(qmlDocumentSourceId1, 22, 12),
+ IsFileStatus(qmlDocumentSourceId2, 22, 13))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.update();
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedFiles)
+{
+ ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(QmlDesigner::Storage::ProjectDatas{
+ {exampleModuleId, qmltypesPathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmltypes2PathSourceId, FileType::QmlTypes},
+ {exampleModuleId, qmlDocumentSourceId1, FileType::QmlDocument},
+ {exampleModuleId, qmlDocumentSourceId2, FileType::QmlDocument}}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
+ .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
+ .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
+ .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 13}));
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import4)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(Eq(objectType),
+ AllOf(IsStorageType("First.qml",
+ Storage::ImportedType{"Object"},
+ TypeAccessSemantics::Reference,
+ qmlDocumentSourceId1,
+ Storage::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
+ IsFileStatus(qmlDocumentSourceId1, 22, 12))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.update();
+}
+
} // namespace
diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp
index 9de60a1807..0c2c3c26bb 100644
--- a/tests/unit/unittest/qmltypesparser-test.cpp
+++ b/tests/unit/unittest/qmltypesparser-test.cpp
@@ -174,7 +174,8 @@ protected:
Storage::Types types;
SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
QmlDesigner::Storage::ProjectData projectData{storage.moduleId("QtQml-cppnative"),
- qmltypesFileSourceId};
+ qmltypesFileSourceId,
+ Storage::FileType::QmlTypes};
SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
ModuleId directoryModuleId{storage.moduleId("path/to/")};
};