diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h index 48b3ba2700c..289f8fd0394 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h @@ -22,8 +22,7 @@ public: friend bool operator==(const FileStatus &first, const FileStatus &second) { return first.sourceId == second.sourceId && first.size == second.size - && first.lastModified == second.lastModified && first.size >= 0 - && first.lastModified >= 0; + && first.lastModified == second.lastModified; } friend bool operator!=(const FileStatus &first, const FileStatus &second) @@ -46,9 +45,9 @@ public: return first.sourceId < second; } - bool isValid() const { return sourceId && size >= 0 && lastModified >= 0; } + bool isExisting() const { return sourceId && size >= 0 && lastModified >= 0; } - explicit operator bool() const { return isValid(); } + explicit operator bool() const { return bool(sourceId); } template friend void convertToString(String &string, const FileStatus &fileStatus) diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp index 856d8ddd617..a06c2d527ff 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp @@ -31,9 +31,9 @@ SourceIds FileSystem::directoryEntries(const QString &directoryPath) const return sourceIds; } -QStringList FileSystem::qmlFileNames(const QString &directoryPath) const +QStringList FileSystem::fileNames(const QString &directoryPath, const QStringList &nameFilters) const { - return QDir{directoryPath}.entryList({"*.qml"}, QDir::Files); + return QDir{directoryPath}.entryList(nameFilters, QDir::Files); } long long FileSystem::lastModified(SourceId sourceId) const diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h index ae58b229d82..e7ae3dad53d 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h @@ -25,7 +25,7 @@ public: {} SourceIds directoryEntries(const QString &directoryPath) const override; - QStringList qmlFileNames(const QString &directoryPath) const override; + QStringList fileNames(const QString &directoryPath, const QStringList &nameFilters) const override; long long lastModified(SourceId sourceId) const override; FileStatus fileStatus(SourceId sourceId) const override; QString contentAsQString(const QString &filePath) const override; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesysteminterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesysteminterface.h index ff7608c9a3f..9e96638546f 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesysteminterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesysteminterface.h @@ -15,7 +15,7 @@ class FileSystemInterface { public: virtual SourceIds directoryEntries(const QString &directoryPath) const = 0; - virtual QStringList qmlFileNames(const QString &directoryPath) const = 0; + virtual QStringList fileNames(const QString &directoryPath, const QStringList &nameFilters) const = 0; virtual long long lastModified(SourceId sourceId) const = 0; virtual FileStatus fileStatus(SourceId sourceId) const = 0; virtual void remove(const SourceIds &sourceIds) = 0; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp index 9e12164c6f6..326f374aeea 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp @@ -1335,7 +1335,7 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag package.updatedSourceIds); synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds); synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths, - package.updatedPropertyEditorQmlPathSourceContextIds); + package.updatedPropertyEditorQmlPathDirectoryIds); deleteNotUpdatedTypes(updatedTypeIds, package.updatedSourceIds, @@ -1413,6 +1413,9 @@ ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName, Storage::Mo projectStorageCategory(), keyValue("module name", moduleName)}; + if (moduleName.empty()) + return ModuleId{}; + auto moduleId = moduleCache.id({moduleName, kind}); tracer.end(keyValue("module id", moduleId)); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h index 71279f57412..a8f3d1d6e95 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h @@ -1331,7 +1331,7 @@ public: ModuleExportedImports moduleExportedImports; ModuleIds updatedModuleIds; PropertyEditorQmlPaths propertyEditorQmlPaths; - SourceContextIds updatedPropertyEditorQmlPathSourceContextIds; + SourceContextIds updatedPropertyEditorQmlPathDirectoryIds; TypeAnnotations typeAnnotations; SourceIds updatedTypeAnnotationSourceIds; }; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp index d89ef04b246..e535f323176 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp @@ -37,12 +37,21 @@ void convertToString(String &string, const ProjectStorageUpdater::FileState &sta case ProjectStorageUpdater::FileState::Changed: convertToString(string, "Changed"); break; - case ProjectStorageUpdater::FileState::NotChanged: - convertToString(string, "NotChanged"); + case ProjectStorageUpdater::FileState::Unchanged: + convertToString(string, "Unchanged"); break; case ProjectStorageUpdater::FileState::NotExists: convertToString(string, "NotExists"); break; + case ProjectStorageUpdater::FileState::NotExistsUnchanged: + convertToString(string, "NotExistsUnchanged"); + break; + case ProjectStorageUpdater::FileState::Added: + convertToString(string, "Added"); + break; + case ProjectStorageUpdater::FileState::Removed: + convertToString(string, "Removed"); + break; } } @@ -92,7 +101,7 @@ ProjectStorageUpdater::Components createComponents( { ProjectStorageUpdater::Components components; - auto qmlFileNames = fileSystem.qmlFileNames(directory); + auto qmlFileNames = fileSystem.fileNames(directory, {"*.qml"}); components.reserve(static_cast(qmlDirParserComponents.size() + qmlFileNames.size())); @@ -289,35 +298,87 @@ void ProjectStorageUpdater::update(Update update) } namespace { + +bool isChanged(ProjectStorageUpdater::FileState state) +{ + using FileState = ProjectStorageUpdater::FileState; + switch (state) { + case FileState::Changed: + case FileState::Added: + case FileState::Removed: + return true; + case FileState::NotExists: + case FileState::NotExistsUnchanged: + case FileState::Unchanged: + break; + } + return false; +} + +bool isUnchanged(ProjectStorageUpdater::FileState state) +{ + return !isChanged(state); +} + template ProjectStorageUpdater::FileState combineState(FileStates... fileStates) { - if (((fileStates == ProjectStorageUpdater::FileState::Changed) || ...)) + if (((fileStates == ProjectStorageUpdater::FileState::Removed) && ...)) + return ProjectStorageUpdater::FileState::Removed; + + if (((fileStates == ProjectStorageUpdater::FileState::Added) && ...)) + return ProjectStorageUpdater::FileState::Added; + + if ((isChanged(fileStates) || ...)) return ProjectStorageUpdater::FileState::Changed; - if (((fileStates == ProjectStorageUpdater::FileState::NotChanged) || ...)) - return ProjectStorageUpdater::FileState::NotChanged; + if (((fileStates == ProjectStorageUpdater::FileState::Unchanged) || ...)) + return ProjectStorageUpdater::FileState::Unchanged; return ProjectStorageUpdater::FileState::NotExists; } +bool isExisting(ProjectStorageUpdater::FileState state) +{ + using FileState = ProjectStorageUpdater::FileState; + switch (state) { + case FileState::Changed: + case FileState::Added: + case FileState::Unchanged: + return true; + case FileState::NotExistsUnchanged: + case FileState::NotExists: + case FileState::Removed: + break; + } + return false; +} + +bool isNotExisting(ProjectStorageUpdater::FileState state) +{ + return !isExisting(state); +} + } // namespace void ProjectStorageUpdater::updateDirectoryChanged(Utils::SmallStringView directoryPath, + Utils::SmallStringView annotationDirectoryPath, FileState qmldirState, + FileState annotationDirectoryState, SourcePath qmldirSourcePath, SourceId qmldirSourceId, SourceContextId directoryId, + SourceContextId annotationDirectoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds, Tracer &tracer) { QmlDirParser parser; - if (qmldirState != FileState::NotExists) + if (isExisting(qmldirState)) parser.parse(m_fileSystem.contentAsQString(QString{qmldirSourcePath})); - if (qmldirState != FileState::NotChanged) { + if (isChanged(qmldirState)) { tracer.tick("append updated source id", keyValue("module id", qmldirSourceId)); package.updatedSourceIds.push_back(qmldirSourceId); } @@ -374,6 +435,17 @@ void ProjectStorageUpdater::updateDirectoryChanged(Utils::SmallStringView direct qmldirSourceId); tracer.tick("append updated project source id", keyValue("module id", moduleId)); package.updatedDirectoryInfoDirectoryIds.push_back(directoryId); + + if (isExisting(annotationDirectoryState)) { + annotationDirectoryChanged(annotationDirectoryPath, + directoryId, + annotationDirectoryId, + moduleId, + package, + notUpdatedSourceIds); + } else if (annotationDirectoryState == FileState::Removed) { + package.updatedPropertyEditorQmlPathDirectoryIds.push_back(annotationDirectoryId); + } } void ProjectStorageUpdater::updateDirectories(const QStringList &directories, @@ -417,11 +489,12 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct auto exisitingSubdirectoryPaths = m_fileSystem.subdirectories(directoryPath.toQString()); Directories existingSubdirecories; - for (const QString &subdirectory : exisitingSubdirectoryPaths) { - if (subdirectory.endsWith("/designer") || subdirectory.endsWith("/QtQuick/Scene2D") - || subdirectory.endsWith("/QtQuick/Scene3D")) + + for (Utils::PathString subdirectoryPath : exisitingSubdirectoryPaths) { + if (subdirectoryPath.endsWith("designer") || subdirectoryPath.endsWith("/QtQuick/Scene2D") + || subdirectoryPath.endsWith("/QtQuick/Scene3D")) continue; - Utils::PathString subdirectoryPath = subdirectory; + SourceContextId sourceContextId = m_pathCache.sourceContextId(subdirectoryPath); subdirectories.emplace_back(subdirectoryPath, sourceContextId); existingSubdirecories.emplace_back(subdirectoryPath, sourceContextId); @@ -454,6 +527,64 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct } } +void ProjectStorageUpdater::annotationDirectoryChanged( + Utils::SmallStringView directoryPath, + SourceContextId directoryId, + SourceContextId annotationDirectoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds) +{ + NanotraceHR::Tracer tracer{"annotation directory changed", + category(), + keyValue("directory path", directoryPath), + keyValue("directory id", directoryId)}; + + package.updatedPropertyEditorQmlPathDirectoryIds.push_back(annotationDirectoryId); + + updatePropertyEditorFiles(directoryPath, annotationDirectoryId, moduleId, package, notUpdatedSourceIds); +} + +void ProjectStorageUpdater::updatePropertyEditorFiles( + Utils::SmallStringView directoryPath, + SourceContextId directoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds) +{ + NanotraceHR::Tracer tracer{"update property editor files", + category(), + keyValue("directory path", directoryPath), + keyValue("directory id", directoryId)}; + + const auto fileNames = m_fileSystem.fileNames(QString{directoryPath}, + {"*Pane.qml", + "*Specifics.qml", + "*SpecificsDynamic.qml"}); + for (const QString &fileName : fileNames) + updatePropertyEditorFile(fileName, directoryId, moduleId, package, notUpdatedSourceIds); +} + +void ProjectStorageUpdater::updatePropertyEditorFile( + const QString &fileName, + SourceContextId directoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds) +{ + Utils::PathString propertyEditorFileName{fileName}; + auto propertyEditorSourceId = m_pathCache.sourceId(directoryId, propertyEditorFileName); + + fileState(propertyEditorSourceId, package, notUpdatedSourceIds); + + QRegularExpression regex{R"xo((\w+)(Specifics|Pane|SpecificsDynamic).qml)xo"}; + auto match = regex.match(fileName); + + Storage::TypeNameString typeName{match.capturedView(1)}; + + package.propertyEditorQmlPaths.emplace_back(moduleId, typeName, propertyEditorSourceId, directoryId); +} + void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath, const SourceContextIds &subdirectoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, @@ -462,32 +593,39 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa { NanotraceHR::Tracer tracer{"update directory", category(), keyValue("directory", directoryPath)}; - SourcePath qmldirSourcePath{directoryPath + "/qmldir"}; - auto [directoryId, qmldirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath); + SourcePath qmldirPath{directoryPath + "/qmldir"}; + auto [directoryId, qmldirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirPath); auto directoryState = fileState(directoryId, package, notUpdatedSourceIds); - if (directoryState != FileState::NotExists) + if (isExisting(directoryState)) watchedSourceIdsIds.directoryIds.push_back(SourceId::create(SourceNameId{}, directoryId)); auto qmldirState = fileState(qmldirSourceId, package, notUpdatedSourceIds); - if (qmldirState != FileState::NotExists) + if (isExisting(qmldirState)) watchedSourceIdsIds.qmldirSourceIds.push_back(qmldirSourceId); - switch (combineState(directoryState, qmldirState)) { - case FileState::Changed: { + SourcePath annotationDirectoryPath{directoryPath + "/designer"}; + auto annotationDirectoryId = m_pathCache.sourceContextId(annotationDirectoryPath); + auto annotationDirectoryState = fileState(annotationDirectoryId, package, notUpdatedSourceIds); + + switch (combineState(directoryState, qmldirState, annotationDirectoryState)) { + case FileState::Changed: + case FileState::Added: tracer.tick("update directory changed"); updateDirectoryChanged(directoryPath, + annotationDirectoryPath, qmldirState, - qmldirSourcePath, + annotationDirectoryState, + qmldirPath, qmldirSourceId, directoryId, + annotationDirectoryId, package, notUpdatedSourceIds, watchedSourceIdsIds, tracer); break; - } - case FileState::NotChanged: { + case FileState::Unchanged: tracer.tick("update directory not changed"); parseDirectoryInfos(m_projectStorage.fetchDirectoryInfos(directoryId), @@ -495,13 +633,9 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa notUpdatedSourceIds, watchedSourceIdsIds); break; - } - case FileState::NotExists: { + case FileState::Removed: { tracer.tick("update directory don't exits"); - auto directorySourceId = SourceId::create(SourceNameId{}, directoryId); - package.updatedFileStatusSourceIds.push_back(directorySourceId); - package.updatedFileStatusSourceIds.push_back(qmldirSourceId); package.updatedDirectoryInfoDirectoryIds.push_back(directoryId); package.updatedSourceIds.push_back(qmldirSourceId); auto qmlDirectoryInfos = m_projectStorage.fetchDirectoryInfos(directoryId); @@ -512,9 +646,11 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa keyValue("source id", directoryInfo.sourceId)); package.updatedFileStatusSourceIds.push_back(directoryInfo.sourceId); } - break; } + case FileState::NotExists: + case FileState::NotExistsUnchanged: + break; } updateSubdirectories(directoryPath, @@ -525,7 +661,7 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa notUpdatedSourceIds, watchedSourceIdsIds); - tracer.end(keyValue("qmldir source path", qmldirSourcePath), + tracer.end(keyValue("qmldir source path", qmldirPath), keyValue("directory id", directoryId), keyValue("qmldir source id", qmldirSourceId), keyValue("qmldir state", qmldirState), @@ -630,7 +766,7 @@ void ProjectStorageUpdater::updateTypeAnnotations( if (state == FileState::Changed) updateTypeAnnotation(directoryPath, fileInfo.filePath(), sourceId, directoryId, package); - if (state != FileState::NotChanged) + if (state != FileState::Unchanged) updatedSourceIdsDictonary[directoryId].push_back(sourceId); } } @@ -643,7 +779,7 @@ void ProjectStorageUpdater::updateTypeAnnotationDirectories( for (auto &[directoryId, updatedSourceIds] : updatedSourceIdsDictonary) { auto directoryState = fileState(directoryId, package, notUpdatedSourceIds); - if (directoryState != FileState::NotChanged) { + if (directoryState != FileState::Unchanged) { auto existingTypeAnnotationSourceIds = m_projectStorage.typeAnnotationSourceIds( directoryId); @@ -708,7 +844,7 @@ void ProjectStorageUpdater::updatePropertyEditorPath( tracer.tick("append updated property editor qml path source id", keyValue("source id", directoryId)); - package.updatedPropertyEditorQmlPathSourceContextIds.push_back(directoryId); + package.updatedPropertyEditorQmlPathDirectoryIds.push_back(directoryId); auto dir = QDir{directoryPath}; const auto fileInfos = dir.entryInfoList({"*Pane.qml", "*Specifics.qml"}, QDir::Files); for (const auto &fileInfo : fileInfos) @@ -950,6 +1086,7 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Direct auto state = fileState(directoryInfo.sourceId, package, notUpdatedSourceIds); switch (state) { + case FileState::Added: case FileState::Changed: { tracer.tick("append updated source ids", keyValue("source id", directoryInfo.sourceId)); package.updatedSourceIds.push_back(directoryInfo.sourceId); @@ -958,12 +1095,14 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Direct m_qmlTypesParser.parse(content, package.imports, package.types, directoryInfo); break; } - case FileState::NotChanged: { + case FileState::Unchanged: { tracer.tick("append not updated source ids", keyValue("source id", directoryInfo.sourceId)); notUpdatedSourceIds.sourceIds.push_back(directoryInfo.sourceId); break; } case FileState::NotExists: + case FileState::NotExistsUnchanged: + case FileState::Removed: throw CannotParseQmlTypesFile{}; } @@ -1003,8 +1142,8 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil watchedSourceIds.qmlSourceIds.push_back(sourceId); switch (state) { - case FileState::NotChanged: - if (qmldirState == FileState::NotExists) { + case FileState::Unchanged: + if (isNotExisting(qmldirState)) { tracer.tick("append not updated source id", keyValue("source id", sourceId)); notUpdatedSourceIds.sourceIds.emplace_back(sourceId); @@ -1017,6 +1156,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil type.changeLevel = Storage::Synchronization::ChangeLevel::Minimal; break; case FileState::NotExists: + case FileState::Removed: tracer.tick("file does not exits", keyValue("source id", sourceId)); for (const auto &exportedType : exportedTypes) m_errorNotifier.qmlDocumentDoesNotExistsForQmldirEntry(exportedType.name, @@ -1024,6 +1164,9 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil sourceId, qmldirSourceId); break; + case FileState::NotExistsUnchanged: + break; + case FileState::Added: case FileState::Changed: tracer.tick("update from qml document", keyValue("source id", sourceId)); const auto content = m_fileSystem.contentAsQString(QString{qmlFilePath}); @@ -1033,7 +1176,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil const auto &directoryInfo = package.directoryInfos.emplace_back( directoryId, sourceId, ModuleId{}, Storage::Synchronization::FileType::QmlDocument); - tracer.tick("append project data", keyValue("project data", directoryInfo)); + tracer.tick("append directory info", keyValue("project data", directoryInfo)); tracer.tick("append updated source id", keyValue("source id", sourceId)); package.updatedSourceIds.push_back(sourceId); @@ -1054,13 +1197,13 @@ void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId, NanotraceHR::Tracer tracer{"parse qml component", category(), keyValue("source id", sourceId)}; auto state = fileState(sourceId, package, notUpdatedSourceIds); - if (state == FileState::NotChanged) + if (isUnchanged(state)) return; tracer.tick("append updated source id", keyValue("source id", sourceId)); package.updatedSourceIds.push_back(sourceId); - if (state == FileState::NotExists) + if (isNotExisting(state)) return; SourcePath sourcePath = m_pathCache.sourcePath(sourceId); @@ -1186,33 +1329,42 @@ ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState( keyValue("source id", sourceId)}; auto currentFileStatus = m_fileStatusCache.find(sourceId); + auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId); - if (!currentFileStatus.isValid()) { - tracer.tick("append updated file status source id", keyValue("source id", sourceId)); + if (!currentFileStatus.isExisting()) { + if (projectStorageFileStatus.isExisting()) { + package.updatedFileStatusSourceIds.push_back(sourceId); + return FileState::Removed; + } + + if (projectStorageFileStatus) { + notUpdatedSourceIds.fileStatusSourceIds.push_back(sourceId); + return FileState::NotExistsUnchanged; + } + + package.fileStatuses.push_back(currentFileStatus); package.updatedFileStatusSourceIds.push_back(sourceId); - tracer.end(keyValue("state", FileState::NotExists)); return FileState::NotExists; } - auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId); - - if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) { - tracer.tick("append file status", keyValue("file status", sourceId)); + if (!projectStorageFileStatus) { + package.fileStatuses.push_back(currentFileStatus); + package.updatedFileStatusSourceIds.push_back(sourceId); + + return FileState::Added; + } + + if (projectStorageFileStatus != currentFileStatus) { package.fileStatuses.push_back(currentFileStatus); - - tracer.tick("append updated file status source id", keyValue("source id", sourceId)); package.updatedFileStatusSourceIds.push_back(sourceId); - tracer.end(keyValue("state", FileState::Changed)); return FileState::Changed; } - tracer.tick("append not updated file status source id", keyValue("source id", sourceId)); notUpdatedSourceIds.fileStatusSourceIds.push_back(sourceId); - tracer.end(keyValue("state", FileState::NotChanged)); - return FileState::NotChanged; + return FileState::Unchanged; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h index de042968930..f6cf60c736c 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h @@ -104,11 +104,7 @@ public: const_iterator m_end; }; - enum class FileState { - NotChanged, - Changed, - NotExists, - }; + enum class FileState { Unchanged, Changed, NotExists, NotExistsUnchanged, Added, Removed }; struct WatchedSourceIdsIds { @@ -157,15 +153,33 @@ private: NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds); void updateDirectoryChanged(Utils::SmallStringView directoryPath, + Utils::SmallStringView annotationDirectoryPath, FileState qmldirState, + FileState annotationDirectoryState, SourcePath qmldirSourcePath, SourceId qmldirSourceId, SourceContextId directoryId, + SourceContextId annotationDirectoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIdsIds &watchedSourceIdsIds, ProjectStorageTracing::Category::TracerType &tracer); - + void annotationDirectoryChanged(Utils::SmallStringView directoryPath, + SourceContextId directoryId, + SourceContextId annotationDirectoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds); + void updatePropertyEditorFiles(Utils::SmallStringView directyPath, + SourceContextId directoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds); + void updatePropertyEditorFile(const QString &fileName, + SourceContextId directoryId, + ModuleId moduleId, + Storage::Synchronization::SynchronizationPackage &package, + NotUpdatedSourceIds ¬UpdatedSourceIds); void updatePropertyEditorPaths(const QString &propertyEditorResourcesPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds); diff --git a/tests/unit/tests/mocks/filesystemmock.h b/tests/unit/tests/mocks/filesystemmock.h index f8544e509f6..8346dca9439 100644 --- a/tests/unit/tests/mocks/filesystemmock.h +++ b/tests/unit/tests/mocks/filesystemmock.h @@ -15,7 +15,10 @@ public: directoryEntries, (const QString &directoryPath), (const, override)); - MOCK_METHOD(QStringList, qmlFileNames, (const QString &directoryPath), (const, override)); + MOCK_METHOD(QStringList, + fileNames, + (const QString &directoryPath, const QStringList &nameFilters), + (const, override)); MOCK_METHOD(long long, lastModified, (QmlDesigner::SourceId sourceId), (const, override)); MOCK_METHOD(QmlDesigner::FileStatus, fileStatus, (QmlDesigner::SourceId sourceId), (const, override)); MOCK_METHOD(void, remove, (const QmlDesigner::SourceIds &sourceIds), (override)); diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index defef8918c2..73909bbf66e 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -853,11 +853,11 @@ std::ostream &operator<<(std::ostream &out, const SynchronizationPackage &packag << ", updatedSourceIds: " << package.updatedSourceIds << ", fileStatuses: " << package.fileStatuses << ", updatedFileStatusSourceIds: " << package.updatedFileStatusSourceIds - << ", updatedDirectoryInfoDirectoryIds: " << package.updatedDirectoryInfoDirectoryIds << ", directoryInfos: " << package.directoryInfos + << ", updatedDirectoryInfoDirectoryIds: " << package.updatedDirectoryInfoDirectoryIds << ", propertyEditorQmlPaths: " << package.propertyEditorQmlPaths << ", updatedPropertyEditorQmlPathSourceIds: " - << package.updatedPropertyEditorQmlPathSourceContextIds + << package.updatedPropertyEditorQmlPathDirectoryIds << ", typeAnnotations: " << package.typeAnnotations << ", updatedTypeAnnotationSourceIds: " << package.updatedTypeAnnotationSourceIds << ")"; @@ -963,7 +963,8 @@ std::ostream &operator<<(std::ostream &out, const ModuleExportedImport &import) std::ostream &operator<<(std::ostream &out, const PropertyEditorQmlPath &path) { - return out << "(" << path.moduleId << ", " << path.typeName << ", " << path.pathId << ")"; + return out << "(" << path.moduleId << ", " << path.typeName << ", " << path.pathId << ", " + << path.directoryId << ", " << path.typeId << ")"; } std::ostream &operator<<(std::ostream &out, const TypeAnnotation &annotation) diff --git a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp index 94b7ac5b9a5..96aa0a6ede8 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp @@ -1079,7 +1079,7 @@ protected: "Item3D", sourceId3, sourceContextIdPath6); - package.updatedPropertyEditorQmlPathSourceContextIds.emplace_back(sourceContextIdPath6); + package.updatedPropertyEditorQmlPathDirectoryIds.emplace_back(sourceContextIdPath6); return package; } @@ -5774,6 +5774,13 @@ TEST_F(ProjectStorage, get_module_id) ASSERT_TRUE(id); } +TEST_F(ProjectStorage, get_invalid_module_id_for_empty_name) +{ + auto id = storage.moduleId("", ModuleKind::QmlLibrary); + + ASSERT_FALSE(id); +} + TEST_F(ProjectStorage, get_same_module_id_again) { auto initialId = storage.moduleId("Qml", ModuleKind::QmlLibrary); diff --git a/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp index 0136fa7c343..2d7df558c9b 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp @@ -133,7 +133,7 @@ MATCHER(PackageIsEmpty, std::string(negation ? "isn't empty" : "is empty")) && package.updatedModuleDependencySourceIds.empty() && package.moduleExportedImports.empty() && package.updatedModuleIds.empty() && package.propertyEditorQmlPaths.empty() - && package.updatedPropertyEditorQmlPathSourceContextIds.empty() + && package.updatedPropertyEditorQmlPathDirectoryIds.empty() && package.typeAnnotations.empty() && package.updatedTypeAnnotationSourceIds.empty(); } @@ -188,6 +188,11 @@ public: qmltypes1SourceId, qmltypes2SourceId, itemLibraryPathSourceId}); + setFilesDontExistsUnchanged({createDirectorySourceId("/path/designer"), + createDirectorySourceId("/root/designer"), + createDirectorySourceId("/path/one/designer"), + createDirectorySourceId("/path/two/designer"), + createDirectorySourceId("/path/three/designer")}); setFilesAdded({qmldir1SourceId, qmldir2SourceId, qmldir3SourceId}); @@ -279,7 +284,8 @@ public: void setFilesRemoved(const QmlDesigner::SourceIds &sourceIds) { for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))).WillByDefault(Return(FileStatus{})); + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) .WillByDefault(Return(FileStatus{sourceId, 1, 21})); } @@ -288,15 +294,34 @@ public: void setFilesDontExists(const QmlDesigner::SourceIds &sourceIds) { for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))).WillByDefault(Return(FileStatus{})); + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{})); + .WillByDefault(Return(FileStatus{SourceId{}, -1, -1})); } } + void setFilesDontExistsUnchanged(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + } + } + + void setFileNames(QStringView directoryPath, + const QStringList &fileNames, + const QStringList &nameFilters) + { + ON_CALL(fileSystemMock, fileNames(Eq(directoryPath), UnorderedElementsAreArray(nameFilters))) + .WillByDefault(Return(fileNames)); + } + void setQmlFileNames(QStringView directoryPath, const QStringList &qmlFileNames) { - ON_CALL(fileSystemMock, qmlFileNames(Eq(directoryPath))).WillByDefault(Return(qmlFileNames)); + setFileNames(directoryPath, qmlFileNames, {"*.qml"}); } void setDirectoryInfos(SourceContextId directorySourceId, const DirectoryInfos &directoryInfos) @@ -376,6 +401,7 @@ protected: SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); SourceContextId directoryPathId = qmlDirPathSourceId.contextId(); SourceId directoryPathSourceId = SourceId::create(QmlDesigner::SourceNameId{}, directoryPathId); + SourceId annotationDirectorySourceId = createDirectorySourceId("/path/designer"); SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml"); SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First2.qml"); SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml"); @@ -2277,10 +2303,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir) UnorderedElementsAre(IsExportedType(pathModuleId, "Second", -1, -1)))))), Field("SynchronizationPackage::updatedSourceIds", &SynchronizationPackage::updatedSourceIds, - UnorderedElementsAre(qmlDirPathSourceId, - qmlDocumentSourceId1, - qmlDocumentSourceId2, - qmlDocumentSourceId3)), + UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3)), Field("SynchronizationPackage::updatedFileStatusSourceIds", &SynchronizationPackage::updatedFileStatusSourceIds, UnorderedElementsAre(directoryPathSourceId, @@ -2291,6 +2314,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir) Field("SynchronizationPackage::fileStatuses", &SynchronizationPackage::fileStatuses, UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21), + IsFileStatus(qmlDirPathSourceId, -1, -1), IsFileStatus(qmlDocumentSourceId1, 1, 21), IsFileStatus(qmlDocumentSourceId2, 1, 21), IsFileStatus(qmlDocumentSourceId3, 1, 21))), @@ -2331,7 +2355,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_parsed_type_if_qml_document_does_not_exists) { setFilesDontExists({qmlDocumentSourceId1}); - setFilesAdded({directoryPathSourceId}); + setFilesAdded({directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId2}); QString qmldir{R"(module Example FirstType 1.0 First.qml FirstType 2.2 First2.qml)"}; @@ -2379,6 +2403,7 @@ TEST_F(ProjectStorageUpdater, &SynchronizationPackage::fileStatuses, UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21), IsFileStatus(qmlDirPathSourceId, 1, 21), + IsFileStatus(qmlDocumentSourceId1, -1, -1), IsFileStatus(qmlDocumentSourceId2, 1, 21))), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, @@ -2397,9 +2422,14 @@ TEST_F(ProjectStorageUpdater, updater.update({.directories = directories}); } -TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_throws_if_directory_does_not_exists) +TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_if_directory_is_removed) { - setFilesDontExists({qmlDirPathSourceId, directoryPathSourceId}); + setFilesRemoved({qmlDirPathSourceId, + directoryPathSourceId, + annotationDirectorySourceId, + qmlDocumentSourceId1, + qmlDocumentSourceId2, + qmlDocumentSourceId3}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}, @@ -2419,6 +2449,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_throws_if Field("SynchronizationPackage::updatedFileStatusSourceIds", &SynchronizationPackage::updatedFileStatusSourceIds, UnorderedElementsAre(directoryPathSourceId, + annotationDirectorySourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2, @@ -2438,7 +2469,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_throws_if TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_add_qml_document) { - setFilesDontExists({qmlDirPathSourceId}); + setFilesDontExistsUnchanged({qmlDirPathSourceId}); setFilesChanged({directoryPathSourceId}); setFilesAdded({qmlDocumentSourceId3}); setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); @@ -2446,43 +2477,50 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_add_qml_d {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); - EXPECT_CALL( - projectStorageMock, - synchronize(AllOf( - Field("SynchronizationPackage::imports", - &SynchronizationPackage::imports, - UnorderedElementsAre(import3)), - Field("SynchronizationPackage::types", - &SynchronizationPackage::types, - UnorderedElementsAre(AllOf( - IsStorageType("Second.qml", - ImportedType{"Object3"}, - TypeTraitsKind::Reference, - qmlDocumentSourceId3, - ChangeLevel::Full), - Field("Type::exportedTypes", - &Type::exportedTypes, - UnorderedElementsAre(IsExportedType(pathModuleId, "Second", -1, -1)))))), - Field("SynchronizationPackage::updatedSourceIds", - &SynchronizationPackage::updatedSourceIds, - UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)), - Field("SynchronizationPackage::updatedFileStatusSourceIds", - &SynchronizationPackage::updatedFileStatusSourceIds, - UnorderedElementsAre(directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId3)), - Field("SynchronizationPackage::fileStatuses", - &SynchronizationPackage::fileStatuses, - UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21), - IsFileStatus(qmlDocumentSourceId3, 1, 21))), - Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", - &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(directoryPathId)), - Field("SynchronizationPackage::directoryInfos", - &SynchronizationPackage::directoryInfos, - UnorderedElementsAre( - IsDirectoryInfo(directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument), - IsDirectoryInfo(directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument), - IsDirectoryInfo( - directoryPathId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument)))))); + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::imports", + &SynchronizationPackage::imports, + UnorderedElementsAre(import3)), + Field("SynchronizationPackage::types", + &SynchronizationPackage::types, + UnorderedElementsAre( + AllOf(IsStorageType("Second.qml", + ImportedType{"Object3"}, + TypeTraitsKind::Reference, + qmlDocumentSourceId3, + ChangeLevel::Full), + Field("Type::exportedTypes", + &Type::exportedTypes, + UnorderedElementsAre( + IsExportedType(pathModuleId, "Second", -1, -1)))))), + Field("SynchronizationPackage::updatedSourceIds", + &SynchronizationPackage::updatedSourceIds, + UnorderedElementsAre(qmlDocumentSourceId3)), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + UnorderedElementsAre(directoryPathSourceId, qmlDocumentSourceId3)), + Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21), + IsFileStatus(qmlDocumentSourceId3, 1, 21))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(directoryPathId)), + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre(IsDirectoryInfo(directoryPathId, + qmlDocumentSourceId1, + ModuleId{}, + FileType::QmlDocument), + IsDirectoryInfo(directoryPathId, + qmlDocumentSourceId2, + ModuleId{}, + FileType::QmlDocument), + IsDirectoryInfo(directoryPathId, + qmlDocumentSourceId3, + ModuleId{}, + FileType::QmlDocument)))))); updater.update({.directories = directories}); } @@ -2506,13 +2544,14 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_removes_q Field("SynchronizationPackage::types", &SynchronizationPackage::types, IsEmpty()), Field("SynchronizationPackage::updatedSourceIds", &SynchronizationPackage::updatedSourceIds, - UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)), + UnorderedElementsAre(qmlDocumentSourceId3)), Field("SynchronizationPackage::updatedFileStatusSourceIds", &SynchronizationPackage::updatedFileStatusSourceIds, UnorderedElementsAre(directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId3)), Field("SynchronizationPackage::fileStatuses", &SynchronizationPackage::fileStatuses, - UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21))), + UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21), + IsFileStatus(qmlDirPathSourceId, -1, -1))), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, UnorderedElementsAre(directoryPathId)), @@ -2672,7 +2711,9 @@ TEST_F(ProjectStorageUpdater, watcher_updates_subdirectories) TEST_F(ProjectStorageUpdater, watcher_updates_removed_directory) { + auto annotationDirectorySourceId = createDirectorySourceId("/path/designer"); setFilesRemoved({directoryPathSourceId, + annotationDirectorySourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2, @@ -2696,13 +2737,14 @@ TEST_F(ProjectStorageUpdater, watcher_updates_removed_directory) Field("SynchronizationPackage::updatedFileStatusSourceIds", &SynchronizationPackage::updatedFileStatusSourceIds, UnorderedElementsAre(directoryPathSourceId, + annotationDirectorySourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3)), Field("SynchronizationPackage::fileStatuses", &SynchronizationPackage::fileStatuses, - UnorderedElementsAre()), + IsEmpty()), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, UnorderedElementsAre(directoryPathId)), @@ -3439,7 +3481,9 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qml_documents) TEST_F(ProjectStorageUpdater, watcher_updates_removed_qml_documents) { + setFilesDontExistsUnchanged({annotationDirectorySourceId, qmlDirPathSourceId}); setFilesRemoved({qmlDocumentSourceId2}); + setFilesChanged({qmlDocumentSourceId1}); EXPECT_CALL(projectStorageMock, synchronize( @@ -3450,11 +3494,13 @@ TEST_F(ProjectStorageUpdater, watcher_updates_removed_qml_documents) &SynchronizationPackage::types, UnorderedElementsAre(AllOf( IsStorageType("First.qml", - ImportedType{"Object"}, + Storage::Synchronization::ImportedType{"Object"}, TypeTraitsKind::Reference, qmlDocumentSourceId1, - ChangeLevel::ExcludeExportedTypes), - Field("Type::exportedTypes", &Type::exportedTypes, IsEmpty())))), + Storage::Synchronization::ChangeLevel::ExcludeExportedTypes), + Field("exportedTypes", + &Storage::Synchronization::Type::exportedTypes, + IsEmpty())))), Field("SynchronizationPackage::updatedSourceIds", &SynchronizationPackage::updatedSourceIds, UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)), @@ -4162,21 +4208,21 @@ TEST_F(ProjectStorageUpdater, update_property_editor_panes) setFilesChanged({directorySourceId}); auto qmlModuleId = storage.moduleId("QML", ModuleKind::QmlLibrary); - EXPECT_CALL( - projectStorageMock, - synchronize(AllOf( - Field("SynchronizationPackage::fileStatuses", - &SynchronizationPackage::fileStatuses, - UnorderedElementsAre(IsFileStatus(directorySourceId, 1, 21))), - Field("SynchronizationPackage::updatedFileStatusSourceIds", - &SynchronizationPackage::updatedFileStatusSourceIds, - UnorderedElementsAre(directorySourceId)), - Field("SynchronizationPackage::propertyEditorQmlPaths", - &SynchronizationPackage::propertyEditorQmlPaths, - Contains(IsPropertyEditorQmlPath(qmlModuleId, "QtObject", sourceId, directoryId))), - Field("SynchronizationPackage::updatedPropertyEditorQmlPathSourceContextIds", - &SynchronizationPackage::updatedPropertyEditorQmlPathSourceContextIds, - ElementsAre(directoryId))))); + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + UnorderedElementsAre(IsFileStatus(directorySourceId, 1, 21))), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + UnorderedElementsAre(directorySourceId)), + Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + Contains(IsPropertyEditorQmlPath( + qmlModuleId, "QtObject", sourceId, directoryId))), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + ElementsAre(directoryId))))); updater.update({.propertyEditorResourcesPath = propertyEditorQmlPath}); } @@ -4213,8 +4259,8 @@ TEST_F(ProjectStorageUpdater, update_property_editor_specifics) {IsPropertyEditorQmlPath(qtQuickModuleId, "Text", textSourceId, qtQuickDirectoryId), IsPropertyEditorQmlPath( controlsModuleId, "Button", buttonSourceId, controlsDirectoryId)})), - Field("SynchronizationPackage::updatedPropertyEditorQmlPathSourceContextIds", - &SynchronizationPackage::updatedPropertyEditorQmlPathSourceContextIds, + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, ElementsAre(qtQuickDirectoryId, controlsDirectoryId))))); updater.update({.propertyEditorResourcesPath = propertyEditorQmlPath}); @@ -4373,4 +4419,242 @@ TEST_F(ProjectStorageUpdater, update_type_annotations_removed_directory) updater.update({.typeAnnotationPaths = {itemLibraryPath}}); } +TEST_F(ProjectStorageUpdater, synchronize_property_editor_qml_paths_directory) +{ + QStringList directories = {"/path/one"}; + setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + setFilesChanged({path1SourceId, designer1SourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + IsSupersetOf({IsFileStatus(designer1SourceId, 1, 21)})), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + IsSupersetOf({designer1SourceId})), + Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + Each(Field("PropertyEditorQmlPath::directoryId", + &PropertyEditorQmlPath::directoryId, + designer1DirectoryId))), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + UnorderedElementsAre(designer1DirectoryId)), + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + IsEmpty()), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(path1SourceContextId))))); + + updater.update({.directories = directories}); +} + +TEST_F(ProjectStorageUpdater, dont_synchronize_empty_property_editor_qml_paths_directory) +{ + QStringList directories = {"/path/one", "/path/two"}; + setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + setSubdirectoryPaths(u"/path/two", {}); + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + SourceContextId designer2DirectoryId = sourcePathCache.sourceContextId("/path/two/designer"); + SourceId designer2SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer2DirectoryId); + setFilesChanged({path1SourceId, path2SourceId, designer1SourceId}); + setFilesDontExists({designer2SourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + IsSupersetOf({IsFileStatus(designer1SourceId, 1, 21)})), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + IsSupersetOf({designer1SourceId, designer2SourceId})), + Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + Each(Field("PropertyEditorQmlPath::directoryId", + &PropertyEditorQmlPath::directoryId, + designer1DirectoryId))), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + UnorderedElementsAre(designer1DirectoryId)), + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + IsEmpty()), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(path1SourceContextId, path2SourceContextId))))); + + updater.update({.directories = directories}); +} + +TEST_F(ProjectStorageUpdater, remove_property_editor_qml_paths_if_designer_directory_is_removed) +{ + QStringList directories = {"/path/one"}; + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + setFilesDontChanged({path1SourceId, qmldir1SourceId}); + setFilesRemoved({designer1SourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + IsEmpty()), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + IsSupersetOf({designer1SourceId})), + Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + IsEmpty()), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + UnorderedElementsAre(designer1DirectoryId)), + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + IsEmpty()), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(path1SourceContextId))))); + + updater.update({.directories = directories}); +} + +TEST_F(ProjectStorageUpdater, + synchronize_annotation_property_editor_qml_paths_directory_if_designer_directory_is_changed) +{ + QStringList directories = {"/path/one"}; + setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + QString qmldir{R"(module Bar)"}; + setContent(u"/path/one/qmldir", qmldir); + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( + "/path/one/designer/FooSpecifics.qml"); + SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( + "/path/one/designer/HuoSpecificsDynamic.qml"); + SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( + "/path/one/designer/CaoPane.qml"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + setFilesChanged({designer1SourceId}); + setFilesDontChanged({path1SourceId, qmldir1SourceId}); + auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); + setFileNames(u"/path/one/designer", + {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, + {"*Pane.qml", "*Specifics.qml", "*SpecificsDynamic.qml"}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + IsSupersetOf({IsPropertyEditorQmlPath(barModuleId, + Eq("Foo"), + propertyEditorSpecificSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Huo"), + propertyEditorSpecificDynamicSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Cao"), + propertyEditorPaneSourceId, + designer1DirectoryId)})), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + Contains(designer1DirectoryId))))); + + updater.update({.directories = directories}); +} + +TEST_F(ProjectStorageUpdater, + synchronize_property_editor_qml_paths_directory_if_qml_directory_is_changed) +{ + QStringList directories = {"/path/one"}; + setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + QString qmldir{R"(module Bar)"}; + setContent(u"/path/one/qmldir", qmldir); + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( + "/path/one/designer/FooSpecifics.qml"); + SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( + "/path/one/designer/HuoSpecificsDynamic.qml"); + SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( + "/path/one/designer/CaoPane.qml"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + setFilesChanged({path1SourceId}); + setFilesDontChanged({qmldir1SourceId, designer1SourceId}); + auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); + setFileNames(u"/path/one/designer", + {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, + {"*Pane.qml", "*Specifics.qml", "*SpecificsDynamic.qml"}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + IsSupersetOf({IsPropertyEditorQmlPath(barModuleId, + Eq("Foo"), + propertyEditorSpecificSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Huo"), + propertyEditorSpecificDynamicSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Cao"), + propertyEditorPaneSourceId, + designer1DirectoryId)})), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + Contains(designer1DirectoryId))))); + + updater.update({.directories = directories}); +} + +TEST_F(ProjectStorageUpdater, synchronize_property_editor_qml_paths_directory_if_qmldir_is_changed) +{ + QStringList directories = {"/path/one"}; + setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + QString qmldir{R"(module Bar)"}; + setContent(u"/path/one/qmldir", qmldir); + SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( + "/path/one/designer/FooSpecifics.qml"); + SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( + "/path/one/designer/HuoSpecificsDynamic.qml"); + SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( + "/path/one/designer/CaoPane.qml"); + SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + setFilesChanged({qmldir1SourceId}); + setFilesDontChanged({path1SourceId, designer1SourceId}); + auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); + setFileNames(u"/path/one/designer", + {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, + {"*Pane.qml", "*Specifics.qml", "*SpecificsDynamic.qml"}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::propertyEditorQmlPaths", + &SynchronizationPackage::propertyEditorQmlPaths, + IsSupersetOf({IsPropertyEditorQmlPath(barModuleId, + Eq("Foo"), + propertyEditorSpecificSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Huo"), + propertyEditorSpecificDynamicSourceId, + designer1DirectoryId), + IsPropertyEditorQmlPath(barModuleId, + Eq("Cao"), + propertyEditorPaneSourceId, + designer1DirectoryId)})), + Field("SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds", + &SynchronizationPackage::updatedPropertyEditorQmlPathDirectoryIds, + Contains(designer1DirectoryId))))); + + updater.update({.directories = directories}); +} + } // namespace diff --git a/tests/unit/tests/utils/google-using-declarations.h b/tests/unit/tests/utils/google-using-declarations.h index 2d5fb1119af..213608916fb 100644 --- a/tests/unit/tests/utils/google-using-declarations.h +++ b/tests/unit/tests/utils/google-using-declarations.h @@ -19,6 +19,7 @@ using testing::ByMove; using testing::ByRef; using testing::ContainerEq; using testing::Contains; +using testing::Each; using testing::ElementsAre; using testing::Eq; using testing::Exactly;