ClangPchManager: Watch unchanged PCHs

Change-Id: I7f4c0f12e4fbf3714e5bfe7655cfa13cac85f71f
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2019-08-01 16:24:14 +02:00
parent 56d611e0a3
commit 4280a68d9f
10 changed files with 296 additions and 92 deletions

View File

@@ -410,7 +410,7 @@ public:
for (WatcherEntry entry : foundEntries) { for (WatcherEntry entry : foundEntries) {
if (idPaths.empty() || idPaths.back().id != entry.id) 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); idPaths.back().filePathIds.push_back(entry.filePathId);
} }

View File

@@ -70,13 +70,23 @@ public:
class IdPaths class IdPaths
{ {
public: public:
ProjectChunkId id; IdPaths(ProjectPartId projectPartId, SourceType sourceType, FilePathIds &&filePathIds)
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) friend bool operator==(IdPaths first, IdPaths second)
{ {
return first.id == second.id && first.filePathIds == second.filePathIds; return first.id == second.id && first.filePathIds == second.filePathIds;
} }
public:
ProjectChunkId id;
FilePathIds filePathIds;
}; };
using ProjectChunkIds = std::vector<ProjectChunkId>; using ProjectChunkIds = std::vector<ProjectChunkId>;

View File

@@ -98,4 +98,22 @@ bool set_intersection_compare(
return false; return false;
} }
template<typename InputIt1, typename InputIt2, typename BinaryPredicate, typename Callable, typename Value>
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 } // namespace ClangBackEnd

View File

@@ -190,6 +190,7 @@ struct Data // because we have a cycle dependency
preCompiledHeaderStorage, preCompiledHeaderStorage,
buildDependencyProvider, buildDependencyProvider,
filePathCache, filePathCache,
includeWatcher,
generatedFiles}; generatedFiles};
PchCreatorManager pchCreatorManager{generatedFiles, PchCreatorManager pchCreatorManager{generatedFiles,
environment, environment,

View File

@@ -196,14 +196,17 @@ void PchCreator::doInMainThreadAfterFinished()
if (m_projectPartPch.projectPartId.isValid()) { if (m_projectPartPch.projectPartId.isValid()) {
m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified, m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified,
m_projectPartPch.projectPartId); m_projectPartPch.projectPartId);
m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::Source}, m_clangPathwatcher.updateIdPaths(
existingSources(m_watchedSources)}}); {{m_projectPartPch.projectPartId, SourceType::Source, existingSources(m_watchedSources)},
m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::UserInclude}, {m_projectPartPch.projectPartId,
existingSources(m_watchedUserIncludes)}}); SourceType::UserInclude,
m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::ProjectInclude}, existingSources(m_watchedUserIncludes)},
existingSources(m_watchedProjectIncludes)}}); {m_projectPartPch.projectPartId,
m_clangPathwatcher.updateIdPaths({{{m_projectPartPch.projectPartId, SourceType::SystemInclude}, SourceType::ProjectInclude,
existingSources(m_watchedSystemIncludes)}}); existingSources(m_watchedProjectIncludes)},
{m_projectPartPch.projectPartId,
SourceType::SystemInclude,
existingSources(m_watchedSystemIncludes)}});
m_pchManagerClient.precompiledHeadersUpdated(m_projectPartPch.projectPartId); m_pchManagerClient.precompiledHeadersUpdated(m_projectPartPch.projectPartId);
} }
} }

View File

@@ -27,6 +27,7 @@
#include <builddependenciesstorage.h> #include <builddependenciesstorage.h>
#include <filepathcachinginterface.h> #include <filepathcachinginterface.h>
#include <filepathview.h>
#include <pchmanagerclientinterface.h> #include <pchmanagerclientinterface.h>
#include <pchtaskgeneratorinterface.h> #include <pchtaskgeneratorinterface.h>
#include <precompiledheadersupdatedmessage.h> #include <precompiledheadersupdatedmessage.h>
@@ -55,7 +56,6 @@ PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher,
, m_projectPartsManager(projectParts) , m_projectPartsManager(projectParts)
, m_generatedFiles(generatedFiles) , m_generatedFiles(generatedFiles)
, m_buildDependenciesStorage(buildDependenciesStorage) , m_buildDependenciesStorage(buildDependenciesStorage)
{ {
m_fileSystemWatcher.setNotifier(this); m_fileSystemWatcher.setNotifier(this);
} }
@@ -72,6 +72,7 @@ ProjectPartIds toProjectPartIds(const ProjectPartContainers &projectParts)
return projectPart.projectPartId; return projectPart.projectPartId;
}); });
} }
} // namespace } // namespace
void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message)

View File

@@ -26,12 +26,16 @@
#include "projectpartsmanager.h" #include "projectpartsmanager.h"
#include <builddependenciesproviderinterface.h> #include <builddependenciesproviderinterface.h>
#include <clangpathwatcherinterface.h>
#include <filecontainerv2.h> #include <filecontainerv2.h>
#include <filepathcachinginterface.h> #include <filepathcachinginterface.h>
#include <generatedfilesinterface.h>
#include <projectpartcontainer.h> #include <projectpartcontainer.h>
#include <set_algorithm.h> #include <set_algorithm.h>
#include <usedmacrofilter.h>
#include <algorithm> #include <algorithm>
#include <utils/algorithm.h>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -73,6 +77,48 @@ Change changedSourceType(const SourceEntries &sources)
return change; 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<std::vector<FilePathView>>(
fileContainers,
[](const V2::FileContainer &container) { return FilePathView(container.filePath); });
return filePathCache.filePathIds(filePaths);
}
} // namespace } // namespace
ProjectPartsManager::UpToDataProjectParts ProjectPartsManager::update(ProjectPartContainers &&projectsParts) ProjectPartsManager::UpToDataProjectParts ProjectPartsManager::update(ProjectPartContainers &&projectsParts)
@@ -129,6 +175,11 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep
auto systemSplit = updateSystemProjectParts.end(); auto systemSplit = updateSystemProjectParts.end();
FilePathIds generatedFiles = toFilePathIds(m_generatedFiles.fileContainers(), m_filePathCache);
std::vector<IdPaths> watchedIdPaths;
watchedIdPaths.reserve(upToDateProjectParts.size() * 4);
for (ProjectPartContainer &projectPart : upToDateProjectParts) { for (ProjectPartContainer &projectPart : upToDateProjectParts) {
auto oldSources = m_buildDependenciesProvider.createSourceEntriesFromStorage( auto oldSources = m_buildDependenciesProvider.createSourceEntriesFromStorage(
projectPart.sourcePathIds, projectPart.projectPartId); projectPart.sourcePathIds, projectPart.projectPartId);
@@ -136,7 +187,7 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart, BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart,
Utils::clone(oldSources)); Utils::clone(oldSources));
auto newSources = buildDependency.sources; const auto &newSources = buildDependency.sources;
SourceEntries updatedSourceTyes; SourceEntries updatedSourceTyes;
updatedSourceTyes.reserve(newSources.size()); updatedSourceTyes.reserve(newSources.size());
@@ -170,17 +221,18 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep
SourceEntries updatedTimeStamps; SourceEntries updatedTimeStamps;
updatedTimeStamps.reserve(newSources.size()); updatedTimeStamps.reserve(newSources.size());
std::set_difference(newSources.begin(), Change change = mismatch_collect(
newSources.end(), newSources.begin(),
oldSources.begin(), newSources.end(),
oldSources.end(), oldSources.begin(),
std::back_inserter(updatedTimeStamps), oldSources.end(),
[](SourceEntry first, SourceEntry second) { Change::No,
return std::tie(first.sourceId, first.timeStamp) [](SourceEntry first, SourceEntry second) {
< std::tie(second.sourceId, second.timeStamp); return first.timeStamp > second.timeStamp;
}); },
[](SourceEntry first, SourceEntry, Change change) {
auto change = changedSourceType(updatedTimeStamps); return changedSourceType(first, change);
});
switch (change) { switch (change) {
case Change::Project: case Change::Project:
@@ -192,11 +244,31 @@ ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDep
projectPart.projectPartId = -1; projectPart.projectPartId = -1;
break; break;
case Change::No: 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; break;
} }
} }
} }
if (watchedIdPaths.size())
m_clangPathwatcher.updateIdPaths(watchedIdPaths);
std::inplace_merge(updateSystemProjectParts.begin(), systemSplit, updateSystemProjectParts.end()); std::inplace_merge(updateSystemProjectParts.begin(), systemSplit, updateSystemProjectParts.end());
upToDateProjectParts.erase(std::remove_if(upToDateProjectParts.begin(), upToDateProjectParts.erase(std::remove_if(upToDateProjectParts.begin(),
upToDateProjectParts.end(), upToDateProjectParts.end(),

View File

@@ -36,6 +36,9 @@
namespace ClangBackEnd { namespace ClangBackEnd {
class BuildDependenciesProviderInterface; class BuildDependenciesProviderInterface;
class FilePathCachingInterface;
class GeneratedFilesInterface;
class ClangPathWatcherInterface;
inline namespace Pch { inline namespace Pch {
@@ -44,10 +47,16 @@ class ProjectPartsManager final : public ProjectPartsManagerInterface
public: public:
ProjectPartsManager(ProjectPartsStorageInterface &projectPartsStorage, ProjectPartsManager(ProjectPartsStorageInterface &projectPartsStorage,
PrecompiledHeaderStorageInterface &precompiledHeaderStorage, PrecompiledHeaderStorageInterface &precompiledHeaderStorage,
BuildDependenciesProviderInterface &buildDependenciesProvider) BuildDependenciesProviderInterface &buildDependenciesProvider,
FilePathCachingInterface &filePathCache,
ClangPathWatcherInterface &clangPathwatcher,
GeneratedFilesInterface &generatedFiles)
: m_projectPartsStorage(projectPartsStorage) : m_projectPartsStorage(projectPartsStorage)
, m_precompiledHeaderStorage(precompiledHeaderStorage) , m_precompiledHeaderStorage(precompiledHeaderStorage)
, m_buildDependenciesProvider(buildDependenciesProvider) , m_buildDependenciesProvider(buildDependenciesProvider)
, m_filePathCache(filePathCache)
, m_clangPathwatcher(clangPathwatcher)
, m_generatedFiles(generatedFiles)
{} {}
UpToDataProjectParts update(ProjectPartContainers &&projectsParts) override; UpToDataProjectParts update(ProjectPartContainers &&projectsParts) override;
@@ -71,6 +80,9 @@ private:
ProjectPartsStorageInterface &m_projectPartsStorage; ProjectPartsStorageInterface &m_projectPartsStorage;
PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage;
BuildDependenciesProviderInterface &m_buildDependenciesProvider; BuildDependenciesProviderInterface &m_buildDependenciesProvider;
FilePathCachingInterface &m_filePathCache;
ClangPathWatcherInterface &m_clangPathwatcher;
GeneratedFilesInterface &m_generatedFiles;
}; };
} // namespace Pch } // namespace Pch

View File

@@ -228,34 +228,26 @@ TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterSucess)
{ {
creator.generatePch(std::move(pchTask1)); 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( EXPECT_CALL(
mockClangPathWatcher, 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}), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}),
Field(&ClangBackEnd::IdPaths::filePathIds, Field(&ClangBackEnd::IdPaths::filePathIds,
UnorderedElementsAre( UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))),
EXPECT_CALL(mockClangPathWatcher, AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}),
updateIdPaths(ElementsAre(AllOf( Field(&ClangBackEnd::IdPaths::filePathIds,
Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), UnorderedElementsAre(
Field(&ClangBackEnd::IdPaths::filePathIds, id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
creator.doInMainThreadAfterFinished(); creator.doInMainThreadAfterFinished();
} }
@@ -266,34 +258,26 @@ TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterFail)
pchTask1.projectIncludeSearchPaths = {}; pchTask1.projectIncludeSearchPaths = {};
creator.generatePch(std::move(pchTask1)); 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( EXPECT_CALL(
mockClangPathWatcher, 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}), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}),
Field(&ClangBackEnd::IdPaths::filePathIds, Field(&ClangBackEnd::IdPaths::filePathIds,
UnorderedElementsAre( UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))),
EXPECT_CALL(mockClangPathWatcher, AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}),
updateIdPaths(ElementsAre(AllOf( Field(&ClangBackEnd::IdPaths::filePathIds,
Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), UnorderedElementsAre(
Field(&ClangBackEnd::IdPaths::filePathIds, id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
creator.doInMainThreadAfterFinished(); creator.doInMainThreadAfterFinished();
} }
@@ -421,33 +405,26 @@ TEST_F(PchCreatorSlowTest, NoIncludesInTheMainThreadCalls)
precompiledHeadersUpdated( precompiledHeadersUpdated(
Field(&ClangBackEnd::PrecompiledHeadersUpdatedMessage::projectPartIds, Field(&ClangBackEnd::PrecompiledHeadersUpdatedMessage::projectPartIds,
ElementsAre(Eq(creator.projectPartPch().projectPartId))))); 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( EXPECT_CALL(
mockClangPathWatcher, 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}), AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::ProjectInclude}),
Field(&ClangBackEnd::IdPaths::filePathIds, Field(&ClangBackEnd::IdPaths::filePathIds,
UnorderedElementsAre( UnorderedElementsAre(
id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"),
id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))),
EXPECT_CALL(mockClangPathWatcher, AllOf(Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}),
updateIdPaths(ElementsAre(AllOf( Field(&ClangBackEnd::IdPaths::filePathIds,
Field(&ClangBackEnd::IdPaths::id, ProjectChunkId{1, SourceType::SystemInclude}), UnorderedElementsAre(
Field(&ClangBackEnd::IdPaths::filePathIds, id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
id(TESTDATA_DIR "/builddependencycollector/system/system1.h"),
id(TESTDATA_DIR "/builddependencycollector/system/system2.h")))))));
EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(Gt(0), Eq(1))); EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(Gt(0), Eq(1)));
creator.doInMainThreadAfterFinished(); creator.doInMainThreadAfterFinished();

View File

@@ -25,6 +25,7 @@
#include "googletest.h" #include "googletest.h"
#include "mockbuilddependenciesprovider.h" #include "mockbuilddependenciesprovider.h"
#include "mockclangpathwatcher.h"
#include "mockfilepathcaching.h" #include "mockfilepathcaching.h"
#include "mockgeneratedfiles.h" #include "mockgeneratedfiles.h"
#include "mockprecompiledheaderstorage.h" #include "mockprecompiledheaderstorage.h"
@@ -37,25 +38,48 @@
namespace { namespace {
using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathId;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::ProjectPartContainer;
using ClangBackEnd::ProjectPartContainers; using ClangBackEnd::ProjectPartContainers;
using UpToDataProjectParts = ClangBackEnd::ProjectPartsManagerInterface::UpToDataProjectParts; using UpToDataProjectParts = ClangBackEnd::ProjectPartsManagerInterface::UpToDataProjectParts;
using ClangBackEnd::SourceEntries; using ClangBackEnd::SourceEntries;
using ClangBackEnd::SourceEntry;
using ClangBackEnd::SourceType; 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 class ProjectPartsManager : public testing::Test
{ {
protected: protected:
ProjectPartsManager() ProjectPartsManager()
{ {
projectPartContainerWithoutPrecompiledHeader1.preCompiledHeaderWasGenerated = false; projectPartContainerWithoutPrecompiledHeader1.preCompiledHeaderWasGenerated = false;
ON_CALL(mockGeneratedFiles, fileContainers()).WillByDefault(ReturnRef(generatedFiles));
} }
NiceMock<MockProjectPartsStorage> mockProjectPartsStorage; NiceMock<MockProjectPartsStorage> mockProjectPartsStorage;
NiceMock<MockPrecompiledHeaderStorage> mockPrecompiledHeaderStorage; NiceMock<MockPrecompiledHeaderStorage> mockPrecompiledHeaderStorage;
NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider; NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider;
NiceMock<MockFilePathCaching> mockFilePathCaching;
NiceMock<MockGeneratedFiles> mockGeneratedFiles;
NiceMock<MockClangPathWatcher> mockClangPathWatcher;
ClangBackEnd::ProjectPartsManager manager{mockProjectPartsStorage, ClangBackEnd::ProjectPartsManager manager{mockProjectPartsStorage,
mockPrecompiledHeaderStorage, mockPrecompiledHeaderStorage,
mockBuildDependenciesProvider}; mockBuildDependenciesProvider,
mockFilePathCaching,
mockClangPathWatcher,
mockGeneratedFiles};
FilePathId firstHeader{1}; FilePathId firstHeader{1};
FilePathId secondHeader{2}; FilePathId secondHeader{2};
FilePathId firstSource{11}; FilePathId firstSource{11};
@@ -649,7 +673,7 @@ TEST_F(ProjectPartsManager, SourcesTimeChanged)
TEST_F(ProjectPartsManager, SourcesTimeNotChanged) TEST_F(ProjectPartsManager, SourcesTimeNotChanged)
{ {
SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; SourceEntries oldSources{{1, SourceType::SystemInclude, 100}};
SourceEntries newSources{{1, SourceType::SystemInclude, 100}}; SourceEntries newSources{{1, SourceType::SystemInclude, 99}};
manager.update({projectPartContainer1}); manager.update({projectPartContainer1});
ON_CALL(mockBuildDependenciesProvider, ON_CALL(mockBuildDependenciesProvider,
createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds),
@@ -832,4 +856,90 @@ TEST_F(ProjectPartsManager, ChangeFromUserIncludeToSource)
ASSERT_THAT(upToDate.updateProject, IsEmpty()); 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 } // namespace