diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h index d7d3aee7e8e..27f76462710 100644 --- a/src/libs/clangsupport/clangpathwatcher.h +++ b/src/libs/clangsupport/clangpathwatcher.h @@ -410,7 +410,7 @@ public: for (WatcherEntry entry : foundEntries) { if (idPaths.empty() || idPaths.back().id != entry.id) - idPaths.push_back({entry.id, {}}); + idPaths.emplace_back(entry.id, FilePathIds{}); idPaths.back().filePathIds.push_back(entry.filePathId); } diff --git a/src/libs/clangsupport/idpaths.h b/src/libs/clangsupport/idpaths.h index d0945f7ff5d..8410bbbbd5f 100644 --- a/src/libs/clangsupport/idpaths.h +++ b/src/libs/clangsupport/idpaths.h @@ -70,13 +70,23 @@ public: class IdPaths { public: - ProjectChunkId id; - FilePathIds filePathIds; + IdPaths(ProjectPartId projectPartId, SourceType sourceType, FilePathIds &&filePathIds) + : id{projectPartId, sourceType} + , filePathIds(std::move(filePathIds)) + {} + IdPaths(ProjectChunkId projectChunkId, FilePathIds &&filePathIds) + : id(projectChunkId) + , filePathIds(std::move(filePathIds)) + {} friend bool operator==(IdPaths first, IdPaths second) { return first.id == second.id && first.filePathIds == second.filePathIds; } + +public: + ProjectChunkId id; + FilePathIds filePathIds; }; using ProjectChunkIds = std::vector; diff --git a/src/libs/clangsupport/set_algorithm.h b/src/libs/clangsupport/set_algorithm.h index dae2b019335..6a17fe6f458 100644 --- a/src/libs/clangsupport/set_algorithm.h +++ b/src/libs/clangsupport/set_algorithm.h @@ -98,4 +98,22 @@ bool set_intersection_compare( return false; } + +template +Value mismatch_collect(InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + InputIt2 last2, + Value value, + BinaryPredicate predicate, + Callable callable) +{ + while (first1 != last1 && first2 != last2) { + if (predicate(*first1, *first2)) + value = callable(*first1, *first2, value); + ++first1, ++first2; + } + + return value; +} } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 8c2023834d9..f98e87eaf0f 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -190,6 +190,7 @@ struct Data // because we have a cycle dependency preCompiledHeaderStorage, buildDependencyProvider, filePathCache, + includeWatcher, generatedFiles}; PchCreatorManager pchCreatorManager{generatedFiles, environment, diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index 3aa8b3c5169..9d0f338b873 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -196,14 +196,17 @@ void PchCreator::doInMainThreadAfterFinished() if (m_projectPartPch.projectPartId.isValid()) { m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified, m_projectPartPch.projectPartId); - m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::Source}, - existingSources(m_watchedSources)}}); - m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::UserInclude}, - existingSources(m_watchedUserIncludes)}}); - m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::ProjectInclude}, - existingSources(m_watchedProjectIncludes)}}); - m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::SystemInclude}, - existingSources(m_watchedSystemIncludes)}}); + m_clangPathwatcher.updateIdPaths( + {{m_projectPartPch.projectPartId, SourceType::Source, existingSources(m_watchedSources)}, + {m_projectPartPch.projectPartId, + SourceType::UserInclude, + existingSources(m_watchedUserIncludes)}, + {m_projectPartPch.projectPartId, + SourceType::ProjectInclude, + existingSources(m_watchedProjectIncludes)}, + {m_projectPartPch.projectPartId, + SourceType::SystemInclude, + existingSources(m_watchedSystemIncludes)}}); m_pchManagerClient.precompiledHeadersUpdated(m_projectPartPch.projectPartId); } } diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 47ac3587658..ee3d3d02aab 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -55,7 +56,6 @@ PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, , m_projectPartsManager(projectParts) , m_generatedFiles(generatedFiles) , m_buildDependenciesStorage(buildDependenciesStorage) - { m_fileSystemWatcher.setNotifier(this); } @@ -72,6 +72,7 @@ ProjectPartIds toProjectPartIds(const ProjectPartContainers &projectParts) return projectPart.projectPartId; }); } + } // namespace void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp index f618559e401..599605d2ab1 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp @@ -26,12 +26,16 @@ #include "projectpartsmanager.h" #include +#include #include #include +#include #include #include +#include #include +#include namespace ClangBackEnd { @@ -73,6 +77,48 @@ Change changedSourceType(const SourceEntries &sources) return change; } +Change changedSourceType(SourceEntry sourceEntry, Change oldChange) +{ + switch (sourceEntry.sourceType) { + case SourceType::SystemInclude: + case SourceType::TopSystemInclude: + return Change::System; + case SourceType::ProjectInclude: + case SourceType::TopProjectInclude: + if (oldChange != Change::System) + return Change::Project; + break; + case SourceType::Source: + case SourceType::UserInclude: + break; + } + + return oldChange; +} + +FilePathIds existingSources(const FilePathIds &sources, const FilePathIds &generatedFilePathIds) +{ + FilePathIds existingSources; + existingSources.reserve(sources.size()); + std::set_difference(sources.begin(), + sources.end(), + generatedFilePathIds.begin(), + generatedFilePathIds.end(), + std::back_inserter(existingSources)); + + return existingSources; +} + +FilePathIds toFilePathIds(const V2::FileContainers &fileContainers, + FilePathCachingInterface &filePathCache) +{ + auto filePaths = Utils::transform>( + fileContainers, + [](const V2::FileContainer &container) { return FilePathView(container.filePath); }); + + return filePathCache.filePathIds(filePaths); +} + } // namespace ProjectPartsManager::UpToDataProjectParts ProjectPartsManager::update(ProjectPartContainers &&projectsParts) @@ -129,6 +175,11 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep auto systemSplit = updateSystemProjectParts.end(); + FilePathIds generatedFiles = toFilePathIds(m_generatedFiles.fileContainers(), m_filePathCache); + + std::vector watchedIdPaths; + watchedIdPaths.reserve(upToDateProjectParts.size() * 4); + for (ProjectPartContainer &projectPart : upToDateProjectParts) { auto oldSources = m_buildDependenciesProvider.createSourceEntriesFromStorage( projectPart.sourcePathIds, projectPart.projectPartId); @@ -136,7 +187,7 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart, Utils::clone(oldSources)); - auto newSources = buildDependency.sources; + const auto &newSources = buildDependency.sources; SourceEntries updatedSourceTyes; updatedSourceTyes.reserve(newSources.size()); @@ -170,17 +221,18 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep SourceEntries updatedTimeStamps; updatedTimeStamps.reserve(newSources.size()); - std::set_difference(newSources.begin(), - newSources.end(), - oldSources.begin(), - oldSources.end(), - std::back_inserter(updatedTimeStamps), - [](SourceEntry first, SourceEntry second) { - return std::tie(first.sourceId, first.timeStamp) - < std::tie(second.sourceId, second.timeStamp); - }); - - auto change = changedSourceType(updatedTimeStamps); + Change change = mismatch_collect( + newSources.begin(), + newSources.end(), + oldSources.begin(), + oldSources.end(), + Change::No, + [](SourceEntry first, SourceEntry second) { + return first.timeStamp > second.timeStamp; + }, + [](SourceEntry first, SourceEntry, Change change) { + return changedSourceType(first, change); + }); switch (change) { case Change::Project: @@ -192,11 +244,31 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep projectPart.projectPartId = -1; break; case Change::No: + UsedMacroFilter usedMacroFilter{newSources, {}, {}}; + + watchedIdPaths.emplace_back(projectPart.projectPartId, + SourceType::Source, + existingSources(usedMacroFilter.sources, generatedFiles)); + watchedIdPaths.emplace_back(projectPart.projectPartId, + SourceType::UserInclude, + existingSources(usedMacroFilter.userIncludes, + generatedFiles)); + watchedIdPaths.emplace_back(projectPart.projectPartId, + SourceType::ProjectInclude, + existingSources(usedMacroFilter.projectIncludes, + generatedFiles)); + watchedIdPaths.emplace_back(projectPart.projectPartId, + SourceType::SystemInclude, + existingSources(usedMacroFilter.systemIncludes, + generatedFiles)); break; } } } + if (watchedIdPaths.size()) + m_clangPathwatcher.updateIdPaths(watchedIdPaths); + std::inplace_merge(updateSystemProjectParts.begin(), systemSplit, updateSystemProjectParts.end()); upToDateProjectParts.erase(std::remove_if(upToDateProjectParts.begin(), upToDateProjectParts.end(), diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h index e32c41fde18..426aa0229f9 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h @@ -36,6 +36,9 @@ namespace ClangBackEnd { class BuildDependenciesProviderInterface; +class FilePathCachingInterface; +class GeneratedFilesInterface; +class ClangPathWatcherInterface; inline namespace Pch { @@ -44,10 +47,16 @@ class ProjectPartsManager final : public ProjectPartsManagerInterface public: ProjectPartsManager(ProjectPartsStorageInterface &projectPartsStorage, PrecompiledHeaderStorageInterface &precompiledHeaderStorage, - BuildDependenciesProviderInterface &buildDependenciesProvider) + BuildDependenciesProviderInterface &buildDependenciesProvider, + FilePathCachingInterface &filePathCache, + ClangPathWatcherInterface &clangPathwatcher, + GeneratedFilesInterface &generatedFiles) : m_projectPartsStorage(projectPartsStorage) , m_precompiledHeaderStorage(precompiledHeaderStorage) , m_buildDependenciesProvider(buildDependenciesProvider) + , m_filePathCache(filePathCache) + , m_clangPathwatcher(clangPathwatcher) + , m_generatedFiles(generatedFiles) {} UpToDataProjectParts update(ProjectPartContainers &&projectsParts) override; @@ -71,6 +80,9 @@ private: ProjectPartsStorageInterface &m_projectPartsStorage; PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; BuildDependenciesProviderInterface &m_buildDependenciesProvider; + FilePathCachingInterface &m_filePathCache; + ClangPathWatcherInterface &m_clangPathwatcher; + GeneratedFilesInterface &m_generatedFiles; }; } // namespace Pch diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index e6ae4a943d0..c5f7f7394d2 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -228,34 +228,26 @@ TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterSucess) { creator.generatePch(std::move(pchTask1)); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre( - AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre(id(main2Path))))))); - - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"))))))); EXPECT_CALL( mockClangPathWatcher, - updateIdPaths(ElementsAre( + updateIdPaths(UnorderedElementsAre( + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), + Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre(id(main2Path)))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h")))), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}), Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); + id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), + id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); creator.doInMainThreadAfterFinished(); } @@ -266,34 +258,26 @@ TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterFail) pchTask1.projectIncludeSearchPaths = {}; creator.generatePch(std::move(pchTask1)); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre( - AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre(id(main2Path))))))); - - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"))))))); EXPECT_CALL( mockClangPathWatcher, - updateIdPaths(ElementsAre( + updateIdPaths(UnorderedElementsAre( + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), + Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre(id(main2Path)))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h")))), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}), Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); + id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), + id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); creator.doInMainThreadAfterFinished(); } @@ -421,33 +405,26 @@ TEST_F(PchCreatorSlowTest, NoIncludesInTheMainThreadCalls) precompiledHeadersUpdated( Field(&ClangBackEnd::PrecompiledHeadersUpdatedMessage::projectPartIds, ElementsAre(Eq(creator.projectPartPch().projectPartId))))); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre( - AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre(id(main2Path))))))); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"))))))); EXPECT_CALL( mockClangPathWatcher, - updateIdPaths(ElementsAre( + updateIdPaths(UnorderedElementsAre( + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::Source}), + Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre(id(main2Path)))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::UserInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h")))), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}), Field(&ClangBackEnd::IdPaths::filePathIds, UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(AllOf( - Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); + id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))), + AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), + id(TESTDATA_DIR "/builddependencycollector/system/system2.h"))))))); EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(Gt(0), Eq(1))); creator.doInMainThreadAfterFinished(); diff --git a/tests/unit/unittest/projectpartsmanager-test.cpp b/tests/unit/unittest/projectpartsmanager-test.cpp index 877c28f8a80..2dd7a7afc44 100644 --- a/tests/unit/unittest/projectpartsmanager-test.cpp +++ b/tests/unit/unittest/projectpartsmanager-test.cpp @@ -25,6 +25,7 @@ #include "googletest.h" #include "mockbuilddependenciesprovider.h" +#include "mockclangpathwatcher.h" #include "mockfilepathcaching.h" #include "mockgeneratedfiles.h" #include "mockprecompiledheaderstorage.h" @@ -37,25 +38,48 @@ namespace { using ClangBackEnd::FilePathId; +using ClangBackEnd::FilePathIds; using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::ProjectPartContainers; using UpToDataProjectParts = ClangBackEnd::ProjectPartsManagerInterface::UpToDataProjectParts; using ClangBackEnd::SourceEntries; +using ClangBackEnd::SourceEntry; using ClangBackEnd::SourceType; +MATCHER_P3(IsIdPaths, + projectPartId, + sourceIds, + sourceType, + std::string(negation ? "isn't " : "is ") + + PrintToString(ClangBackEnd::IdPaths{{projectPartId, sourceType}, + Utils::clone(sourceIds)})) +{ + const ClangBackEnd::IdPaths &idPaths = arg; + + return idPaths.filePathIds == sourceIds && idPaths.id.sourceType == sourceType + && idPaths.id.id == projectPartId; +} + class ProjectPartsManager : public testing::Test { protected: ProjectPartsManager() { projectPartContainerWithoutPrecompiledHeader1.preCompiledHeaderWasGenerated = false; + ON_CALL(mockGeneratedFiles, fileContainers()).WillByDefault(ReturnRef(generatedFiles)); } NiceMock mockProjectPartsStorage; NiceMock mockPrecompiledHeaderStorage; NiceMock mockBuildDependenciesProvider; + NiceMock mockFilePathCaching; + NiceMock mockGeneratedFiles; + NiceMock mockClangPathWatcher; ClangBackEnd::ProjectPartsManager manager{mockProjectPartsStorage, mockPrecompiledHeaderStorage, - mockBuildDependenciesProvider}; + mockBuildDependenciesProvider, + mockFilePathCaching, + mockClangPathWatcher, + mockGeneratedFiles}; FilePathId firstHeader{1}; FilePathId secondHeader{2}; FilePathId firstSource{11}; @@ -649,7 +673,7 @@ TEST_F(ProjectPartsManager, SourcesTimeChanged) TEST_F(ProjectPartsManager, SourcesTimeNotChanged) { SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; - SourceEntries newSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 99}}; manager.update({projectPartContainer1}); ON_CALL(mockBuildDependenciesProvider, createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), @@ -832,4 +856,90 @@ TEST_F(ProjectPartsManager, ChangeFromUserIncludeToSource) ASSERT_THAT(upToDate.updateProject, IsEmpty()); } +TEST_F(ProjectPartsManager, DontWatchNewSources) +{ + EXPECT_CALL(mockClangPathWatcher, updateIdPaths(_)).Times(0); + + manager.update({projectPartContainer1}); +} + +TEST_F(ProjectPartsManager, DontWatchUpdatedSources) +{ + manager.update({projectPartContainer1}); + + EXPECT_CALL(mockClangPathWatcher, updateIdPaths(_)).Times(0); + + manager.update({updatedProjectPartContainer1}); +} + +TEST_F(ProjectPartsManager, DontWatchChangedTimeStamps) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 101}}; + ON_CALL(mockBuildDependenciesProvider, createSourceEntriesFromStorage(_, _)) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(_, _)) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + EXPECT_CALL(mockClangPathWatcher, updateIdPaths(_)).Times(0); + + manager.update({projectPartContainer1}); +} + +TEST_F(ProjectPartsManager, DontWatchChangedSources) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::ProjectInclude, 100}}; + ON_CALL(mockBuildDependenciesProvider, createSourceEntriesFromStorage(_, _)) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(_, _)) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + EXPECT_CALL(mockClangPathWatcher, updateIdPaths(_)).Times(0); + + manager.update({projectPartContainer1}); +} + +TEST_F(ProjectPartsManager, WatchNoUpdatedSources) +{ + manager.update({projectPartContainer1, projectPartContainer2}); + SourceEntries sources1{{1, SourceType::TopSystemInclude, 100}, + {2, SourceType::SystemInclude, 100}, + {3, SourceType::TopProjectInclude, 100}, + {4, SourceType::ProjectInclude, 100}, + {5, SourceType::UserInclude, 100}, + {6, SourceType::Source, 100}}; + SourceEntries sources2{{11, SourceType::TopSystemInclude, 100}, + {21, SourceType::SystemInclude, 100}, + {31, SourceType::TopProjectInclude, 100}, + {41, SourceType::ProjectInclude, 100}, + {51, SourceType::UserInclude, 100}, + {61, SourceType::Source, 100}}; + ON_CALL(mockBuildDependenciesProvider, createSourceEntriesFromStorage(_, Eq(1))) + .WillByDefault(Return(sources1)); + ON_CALL(mockBuildDependenciesProvider, + create(Field(&ProjectPartContainer::projectPartId, Eq(1)), _)) + .WillByDefault(Return(ClangBackEnd::BuildDependency{sources1, {}, {}, {}, {}})); + ON_CALL(mockBuildDependenciesProvider, createSourceEntriesFromStorage(_, Eq(2))) + .WillByDefault(Return(sources2)); + ON_CALL(mockBuildDependenciesProvider, + create(Field(&ProjectPartContainer::projectPartId, Eq(2)), _)) + .WillByDefault(Return(ClangBackEnd::BuildDependency{sources2, {}, {}, {}, {}})); + + EXPECT_CALL(mockClangPathWatcher, + updateIdPaths(UnorderedElementsAre( + IsIdPaths(1, FilePathIds{6}, SourceType::Source), + IsIdPaths(2, FilePathIds{61}, SourceType::Source), + IsIdPaths(1, FilePathIds{5}, SourceType::UserInclude), + IsIdPaths(2, FilePathIds{51}, SourceType::UserInclude), + IsIdPaths(1, FilePathIds{3, 4}, SourceType::ProjectInclude), + IsIdPaths(2, FilePathIds{31, 41}, SourceType::ProjectInclude), + IsIdPaths(1, FilePathIds{1, 2}, SourceType::SystemInclude), + IsIdPaths(2, FilePathIds{11, 21}, SourceType::SystemInclude)))); + + manager.update({projectPartContainer1, projectPartContainer2}); +} + } // namespace