ClangPchManager: Merge system pch tasks

The merging of the include search paths is quite heuristic but we could
provide an option to disable pch merging so users can decide themselves.
Maybe we could give user feedback why we cannot merge but this is quite
advanced.

Task-number: QTCREATORBUG-21381
Change-Id: Iac6af0c587b631d2151f63d6d97215ed6919819f
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2019-01-30 18:48:59 +01:00
parent 14a44948d8
commit 0082a82fc6
13 changed files with 544 additions and 121 deletions

View File

@@ -182,6 +182,13 @@ public:
{ {
CompilerMacros macros = compilerMacros; CompilerMacros macros = compilerMacros;
macros.erase(std::remove_if(macros.begin(),
macros.end(),
[](const auto &macro) {
return macro.type == CompilerMacroType::NotDefined;
}),
macros.end());
std::sort(macros.begin(), std::sort(macros.begin(),
macros.end(), macros.end(),
[](const CompilerMacro &first, const CompilerMacro &second) { [](const CompilerMacro &first, const CompilerMacro &second) {

View File

@@ -31,6 +31,8 @@
namespace ClangBackEnd { namespace ClangBackEnd {
enum class CompilerMacroType : unsigned char { Define, NotDefined };
class CompilerMacro class CompilerMacro
{ {
public: public:
@@ -40,39 +42,57 @@ public:
: key(std::move(key)) : key(std::move(key))
, value(std::move(value)) , value(std::move(value))
, index(index) , index(index)
, type(CompilerMacroType::Define)
{}
CompilerMacro(Utils::SmallString &&key)
: key(std::move(key))
{}
CompilerMacro(const Utils::SmallString &key)
: key(key)
{} {}
friend QDataStream &operator<<(QDataStream &out, const CompilerMacro &compilerMacro) friend QDataStream &operator<<(QDataStream &out, const CompilerMacro &compilerMacro)
{ {
out << compilerMacro.key; out << compilerMacro.key;
out << compilerMacro.value; out << compilerMacro.value;
out << compilerMacro.index;
out << static_cast<unsigned char>(compilerMacro.type);
return out; return out;
} }
friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro) friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro)
{ {
unsigned char type;
in >> compilerMacro.key; in >> compilerMacro.key;
in >> compilerMacro.value; in >> compilerMacro.value;
in >> compilerMacro.index;
in >> type;
compilerMacro.type = static_cast<CompilerMacroType>(type);
return in; return in;
} }
friend bool operator==(const CompilerMacro &first, const CompilerMacro &second) friend bool operator==(const CompilerMacro &first, const CompilerMacro &second)
{ {
return first.key == second.key return first.key == second.key && first.value == second.value && first.type == second.type;
&& first.value == second.value;
} }
friend bool operator<(const CompilerMacro &first, const CompilerMacro &second) friend bool operator<(const CompilerMacro &first, const CompilerMacro &second)
{ {
return std::tie(first.key, first.value) < std::tie(second.key, second.value); return std::tie(first.key, first.type, first.value)
< std::tie(second.key, second.type, second.value);
} }
public: public:
Utils::SmallString key; Utils::SmallString key;
Utils::SmallString value; Utils::SmallString value;
int index = 0; int index = -1;
CompilerMacroType type = CompilerMacroType::NotDefined;
}; };
using CompilerMacros = std::vector<CompilerMacro>; using CompilerMacros = std::vector<CompilerMacro>;

View File

@@ -43,7 +43,7 @@ public:
FilePathIds &&includes, FilePathIds &&includes,
FilePathIds &&allIncludes, FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros, CompilerMacros &&compilerMacros,
UsedMacros &&usedMacros, Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments, Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths,
@@ -54,7 +54,6 @@ public:
, includes(includes) , includes(includes)
, allIncludes(allIncludes) , allIncludes(allIncludes)
, compilerMacros(compilerMacros) , compilerMacros(compilerMacros)
, usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments)) , toolChainArguments(std::move(toolChainArguments))
@@ -67,7 +66,7 @@ public:
FilePathIds &&includes, FilePathIds &&includes,
FilePathIds &&allIncludes, FilePathIds &&allIncludes,
CompilerMacros &&compilerMacros, CompilerMacros &&compilerMacros,
UsedMacros &&usedMacros, Utils::SmallStringVector &&usedMacros,
Utils::SmallStringVector toolChainArguments, Utils::SmallStringVector toolChainArguments,
IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths systemIncludeSearchPaths,
IncludeSearchPaths projectIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths,
@@ -78,7 +77,6 @@ public:
, includes(includes) , includes(includes)
, allIncludes(allIncludes) , allIncludes(allIncludes)
, compilerMacros(compilerMacros) , compilerMacros(compilerMacros)
, usedMacros(usedMacros)
, systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths))
, projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths))
, toolChainArguments(std::move(toolChainArguments)) , toolChainArguments(std::move(toolChainArguments))
@@ -92,7 +90,6 @@ public:
return first.systemPchPath == second.systemPchPath return first.systemPchPath == second.systemPchPath
&& first.projectPartIds == second.projectPartIds && first.includes == second.includes && first.projectPartIds == second.projectPartIds && first.includes == second.includes
&& first.compilerMacros == second.compilerMacros && first.compilerMacros == second.compilerMacros
&& first.usedMacros == second.usedMacros
&& first.systemIncludeSearchPaths == second.systemIncludeSearchPaths && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths
&& first.projectIncludeSearchPaths == second.projectIncludeSearchPaths && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths
&& first.toolChainArguments == second.toolChainArguments && first.toolChainArguments == second.toolChainArguments
@@ -109,13 +106,13 @@ public:
FilePathIds includes; FilePathIds includes;
FilePathIds allIncludes; FilePathIds allIncludes;
CompilerMacros compilerMacros; CompilerMacros compilerMacros;
UsedMacros usedMacros;
IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths systemIncludeSearchPaths;
IncludeSearchPaths projectIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths;
Utils::SmallStringVector toolChainArguments; Utils::SmallStringVector toolChainArguments;
Utils::Language language = Utils::Language::Cxx; Utils::Language language = Utils::Language::Cxx;
Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98; Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98;
Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None; Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None;
bool isMerged = false;
}; };
class PchTaskSet class PchTaskSet

View File

@@ -42,9 +42,9 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
for (auto &projectPart : projectParts) { for (auto &projectPart : projectParts) {
BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart);
UsedMacroFilter filter{buildDependency.includes, buildDependency.usedMacros}; UsedMacroFilter filter{buildDependency.includes,
buildDependency.usedMacros,
filter.filter(projectPart.compilerMacros); projectPart.compilerMacros};
pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(), pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(),
std::move(filter.topSystemIncludes), std::move(filter.topSystemIncludes),
@@ -53,7 +53,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts,
std::move(filter.systemUsedMacros), std::move(filter.systemUsedMacros),
projectPart.toolChainArguments, projectPart.toolChainArguments,
projectPart.systemIncludeSearchPaths, projectPart.systemIncludeSearchPaths,
projectPart.projectIncludeSearchPaths, {},
projectPart.language, projectPart.language,
projectPart.languageVersion, projectPart.languageVersion,
projectPart.languageExtension}, projectPart.languageExtension},

View File

@@ -30,20 +30,10 @@
namespace ClangBackEnd { namespace ClangBackEnd {
void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets, void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets,
Utils::SmallStringVector &&/*toolChainArguments*/) Utils::SmallStringVector && /*toolChainArguments*/)
{ {
PchTasks systemTasks; mergeSystemTasks(taskSets);
systemTasks.reserve(taskSets.size()); addProjectTasksToQueue(taskSets);
PchTasks projectTasks;
projectTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets) {
projectTasks.push_back(std::move(taskSet.project));
systemTasks.push_back(std::move(taskSet.system));
}
m_pchTaskQueue.addSystemPchTasks(std::move(systemTasks));
m_pchTaskQueue.addProjectPchTasks(std::move(projectTasks));
m_pchTaskQueue.processEntries(); m_pchTaskQueue.processEntries();
} }
@@ -52,4 +42,117 @@ void PchTasksMerger::removePchTasks(const Utils::SmallStringVector &projectPartI
m_pchTaskQueue.removePchTasks(projectPartIds); m_pchTaskQueue.removePchTasks(projectPartIds);
} }
template<typename Container, typename Result = std::remove_const_t<std::remove_reference_t<Container>>>
Result merge(Container &&first, Container &&second)
{
Result result;
result.reserve(first.size() + second.size());
std::set_union(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::make_move_iterator(second.begin()),
std::make_move_iterator(second.end()),
std::back_inserter(result));
return result;
}
CompilerMacros PchTasksMerger::mergeMacros(const CompilerMacros &firstCompilerMacros,
const CompilerMacros &secondCompilerMacros)
{
return merge(firstCompilerMacros, secondCompilerMacros);
}
bool PchTasksMerger::hasDuplicates(const CompilerMacros &compilerMacros)
{
auto found = std::adjacent_find(compilerMacros.begin(),
compilerMacros.end(),
[](const CompilerMacro &first, const CompilerMacro &second) {
return first.key == second.key;
});
return found == compilerMacros.end();
}
IncludeSearchPaths mergeIncludeSearchPaths(IncludeSearchPaths &&first, IncludeSearchPaths &&second)
{
if (first.size() > second.size())
return merge(first, second);
return merge(first, second);
}
bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask)
{
if (firstTask.language != secondTask.language || firstTask.isMerged || secondTask.isMerged)
return false;
CompilerMacros macros = mergeMacros(firstTask.compilerMacros, secondTask.compilerMacros);
secondTask.isMerged = hasDuplicates(macros);
if (secondTask.isMerged && firstTask.language == secondTask.language) {
firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds),
std::move(secondTask.projectPartIds));
firstTask.includes = merge(std::move(firstTask.includes), std::move(secondTask.includes));
firstTask.allIncludes = merge(std::move(firstTask.allIncludes),
std::move(secondTask.allIncludes));
firstTask.compilerMacros = std::move(macros);
firstTask.systemIncludeSearchPaths = mergeIncludeSearchPaths(
std::move(firstTask.systemIncludeSearchPaths),
std::move(secondTask.systemIncludeSearchPaths));
firstTask.languageVersion = std::max(firstTask.languageVersion, secondTask.languageVersion);
firstTask.languageExtension = firstTask.languageExtension | secondTask.languageExtension;
}
return secondTask.isMerged;
}
void PchTasksMerger::mergePchTasks(PchTasks &tasks)
{
auto begin = tasks.begin();
while (begin != tasks.end()) {
begin = std::find_if(begin, tasks.end(), [](const auto &task) { return !task.isMerged; });
if (begin != tasks.end()) {
PchTask &baseTask = *begin;
++begin;
std::for_each(begin, tasks.end(), [&](PchTask &currentTask) {
mergePchTasks(baseTask, currentTask);
});
}
}
}
void PchTasksMerger::addProjectTasksToQueue(PchTaskSets &taskSets)
{
PchTasks projectTasks;
projectTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets)
projectTasks.push_back(std::move(taskSet.project));
m_pchTaskQueue.addProjectPchTasks(std::move(projectTasks));
}
void PchTasksMerger::mergeSystemTasks(PchTaskSets &taskSets)
{
PchTasks systemTasks;
systemTasks.reserve(taskSets.size());
for (PchTaskSet &taskSet : taskSets)
systemTasks.push_back(std::move(taskSet.system));
mergePchTasks(systemTasks);
systemTasks.erase(std::remove_if(systemTasks.begin(),
systemTasks.end(),
[](const PchTask &task) { return task.isMerged; }),
systemTasks.end());
m_pchTaskQueue.addSystemPchTasks(std::move(systemTasks));
}
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -32,7 +32,7 @@ namespace ClangBackEnd {
class PchTaskQueueInterface; class PchTaskQueueInterface;
class PchTasksMerger : public PchTasksMergerInterface class PchTasksMerger final : public PchTasksMergerInterface
{ {
public: public:
PchTasksMerger(PchTaskQueueInterface &pchTaskQueue) PchTasksMerger(PchTaskQueueInterface &pchTaskQueue)
@@ -42,6 +42,18 @@ public:
void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) override; void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) override;
void removePchTasks(const Utils::SmallStringVector &projectPartIds) override; void removePchTasks(const Utils::SmallStringVector &projectPartIds) override;
static CompilerMacros mergeMacros(const CompilerMacros &firstCompilerMacros,
const CompilerMacros &secondCompilerMacros);
static bool hasDuplicates(const CompilerMacros &compilerMacros);
static bool mergePchTasks(PchTask &first, PchTask &second);
static void mergePchTasks(PchTasks &tasks);
private:
void addProjectTasksToQueue(PchTaskSets &taskSets);
void mergeSystemTasks(PchTaskSets &taskSets);
private: private:
PchTaskQueueInterface &m_pchTaskQueue; PchTaskQueueInterface &m_pchTaskQueue;
}; };

View File

@@ -32,6 +32,27 @@
namespace ClangBackEnd { namespace ClangBackEnd {
template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
inline OutputIterator set_greedy_intersection(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
OutputIterator result,
Compare comp)
{
while (first1 != last1 && first2 != last2)
if (comp(*first1, *first2))
++first1;
else if (comp(*first2, *first1))
++first2;
else {
*result = *first1;
++first1;
++result;
}
return result;
}
class UsedMacroFilter class UsedMacroFilter
{ {
public: public:
@@ -41,11 +62,14 @@ public:
FilePathIds system; FilePathIds system;
}; };
UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros) UsedMacroFilter(const SourceEntries &includes,
const UsedMacros &usedMacros,
const CompilerMacros &compilerMacros)
{ {
filterIncludes(includes); filterIncludes(includes);
systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes);
projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes);
filter(compilerMacros);
} }
void filterIncludes(const SourceEntries &includes) void filterIncludes(const SourceEntries &includes)
@@ -98,7 +122,8 @@ private:
allIncludes.emplace_back(include.sourceId); allIncludes.emplace_back(include.sourceId);
} }
static UsedMacros filterUsedMarcos(const UsedMacros &usedMacros, const FilePathIds &filePathId) static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros,
const FilePathIds &filePathId)
{ {
struct Compare struct Compare
{ {
@@ -113,52 +138,57 @@ private:
} }
}; };
UsedMacros filtertedMacros; Utils::SmallStringVector filtertedMacros;
filtertedMacros.reserve(usedMacros.size()); filtertedMacros.reserve(usedMacros.size());
std::set_intersection(usedMacros.begin(), set_greedy_intersection(usedMacros.begin(),
usedMacros.end(), usedMacros.end(),
filePathId.begin(), filePathId.begin(),
filePathId.end(), filePathId.end(),
std::back_inserter(filtertedMacros), std::back_inserter(filtertedMacros),
Compare{}); Compare{});
std::sort(filtertedMacros.begin(), std::sort(filtertedMacros.begin(), filtertedMacros.end());
filtertedMacros.end(),
[](const UsedMacro &first, const UsedMacro &second) {
return first.macroName < second.macroName;
});
return filtertedMacros; return filtertedMacros;
} }
static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro, static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro,
const UsedMacros &usedMacros) const Utils::SmallStringVector &usedMacros)
{ {
CompilerMacros filtertedCompilerMacros;
filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size());
struct Compare struct Compare
{ {
bool operator()(const UsedMacro &usedMacro, bool operator()(const CompilerMacro &compilerMacro, Utils::SmallStringView usedMacro)
const CompilerMacro &compileMacro)
{ {
return usedMacro.macroName < compileMacro.key; return compilerMacro.key < usedMacro;
} }
bool operator()(const CompilerMacro &compileMacro, bool operator()(Utils::SmallStringView usedMacro, const CompilerMacro &compilerMacro)
const UsedMacro &usedMacro)
{ {
return compileMacro.key < usedMacro.macroName; return usedMacro < compilerMacro.key;
} }
}; };
CompilerMacros filtertedCompilerMacros; set_greedy_intersection(indexedCompilerMacro.begin(),
filtertedCompilerMacros.reserve(indexedCompilerMacro.size()); indexedCompilerMacro.end(),
usedMacros.begin(),
usedMacros.end(),
std::back_inserter(filtertedCompilerMacros),
Compare{});
std::set_intersection(indexedCompilerMacro.begin(), auto split = filtertedCompilerMacros.end();
indexedCompilerMacro.end(),
usedMacros.begin(), std::set_difference(usedMacros.begin(),
usedMacros.end(), usedMacros.end(),
std::back_inserter(filtertedCompilerMacros), filtertedCompilerMacros.begin(),
Compare{}); filtertedCompilerMacros.end(),
std::back_inserter(filtertedCompilerMacros),
Compare{});
std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end());
return filtertedCompilerMacros; return filtertedCompilerMacros;
} }
@@ -169,8 +199,8 @@ public:
FilePathIds systemIncludes; FilePathIds systemIncludes;
FilePathIds topProjectIncludes; FilePathIds topProjectIncludes;
FilePathIds topSystemIncludes; FilePathIds topSystemIncludes;
UsedMacros projectUsedMacros; Utils::SmallStringVector projectUsedMacros;
UsedMacros systemUsedMacros; Utils::SmallStringVector systemUsedMacros;
CompilerMacros projectCompilerMacros; CompilerMacros projectCompilerMacros;
CompilerMacros systemCompilerMacros; CompilerMacros systemCompilerMacros;
}; };

View File

@@ -62,6 +62,10 @@ public:
{ {
return !(first == second); return !(first == second);
} }
operator Utils::SmallStringView() const { return macroName; }
operator const Utils::SmallString &() const { return macroName; }
public: public:
Utils::SmallString macroName; Utils::SmallString macroName;
FilePathId filePathId; FilePathId filePathId;

View File

@@ -511,7 +511,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath)
TYPED_TEST(CommandLineBuilder, CompilerMacros) TYPED_TEST(CommandLineBuilder, CompilerMacros)
{ {
this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}}; this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}, {"SAN"}};
Builder<TypeParam> builder{this->emptyProjectInfo}; Builder<TypeParam> builder{this->emptyProjectInfo};

View File

@@ -1157,10 +1157,9 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes)
std::ostream &operator<<(std::ostream &out, const PchTask &task) std::ostream &operator<<(std::ostream &out, const PchTask &task)
{ {
return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros
<< ", " << task.usedMacros << ", " << toText(task.language) << ", " << toText(task.language) << ", " << task.systemIncludeSearchPaths << ", "
<< task.systemIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " << task.toolChainArguments << ", "
<< task.toolChainArguments << ", " << toText(task.languageVersion) << ", " << toText(task.languageVersion) << ", " << toText(task.languageExtension) << ")";
<< toText(task.languageExtension) << ")";
} }
std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet)

View File

@@ -99,7 +99,6 @@ TEST_F(PchTaskGenerator, AddProjectParts)
Field(&PchTask::allIncludes, IsEmpty()), Field(&PchTask::allIncludes, IsEmpty()),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})),
Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})),
Field(&PchTask::systemIncludeSearchPaths, Field(&PchTask::systemIncludeSearchPaths,
ElementsAre( ElementsAre(
IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
@@ -120,7 +119,6 @@ TEST_F(PchTaskGenerator, AddProjectParts)
Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)), Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})),
Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"YI", 1}, UsedMacro{"SAN", 3})),
Field(&PchTask::systemIncludeSearchPaths, Field(&PchTask::systemIncludeSearchPaths,
ElementsAre( ElementsAre(
IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},

View File

@@ -31,11 +31,14 @@
namespace { namespace {
using ClangBackEnd::CompilerMacro;
using ClangBackEnd::CompilerMacros;
using ClangBackEnd::IncludeSearchPath; using ClangBackEnd::IncludeSearchPath;
using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::IncludeSearchPathType;
using ClangBackEnd::PchTask; using ClangBackEnd::PchTask;
using ClangBackEnd::PchTaskSet; using ClangBackEnd::PchTaskSet;
using Merger = ClangBackEnd::PchTasksMerger;
using Id = ClangBackEnd::FilePathId;
class PchTasksMerger : public testing::Test class PchTasksMerger : public testing::Test
{ {
protected: protected:
@@ -51,48 +54,58 @@ protected:
ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue}; ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue};
PchTask systemTask1{"ProjectPart1", PchTask systemTask1{"ProjectPart1",
{1, 2}, {1, 2},
{1, 2}, {1, 2, 3},
{{"YI", "1", 1}, {"SAN", "3", 3}}, {{"YI", "1", 1}, {"SAN", "3", 3}},
{{"LIANG", 0}, {"YI", 1}}, {"YI", "LIANG"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask projectTask1{"ProjectPart1", PchTask projectTask1{"ProjectPart1",
{11, 12}, {11, 12},
{11, 12}, {11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"ER", 2}, {"SAN", 3}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 1, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 2, IncludeSearchPathType::BuiltIn}},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {{"/to/path1", 1, IncludeSearchPathType::User},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {"/to/path2", 2, IncludeSearchPathType::User}}};
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask systemTask2{"ProjectPart2", PchTask systemTask2{"ProjectPart2",
{1, 2}, {11, 12},
{1, 2}, {11, 12, 13},
{{"YI", "1", 1}, {"SAN", "3", 3}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"LIANG", 0}, {"YI", 1}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask projectTask2{"ProjectPart2", PchTask projectTask2{"ProjectPart2",
{11, 12}, {11, 12},
{11, 12}, {11, 12},
{{"SE", "4", 4}, {"WU", "5", 5}}, {{"SE", "4", 4}, {"WU", "5", 5}},
{{"ER", 2}, {"SAN", 3}}, {"ER", "SAN"},
{"--yi"}, {"--yi"},
{IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, {{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, {"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, {"/framework/path", 1, IncludeSearchPathType::System}},
{IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, {{"/to/path1", 1, IncludeSearchPathType::User},
IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; {"/to/path2", 2, IncludeSearchPathType::User}}};
PchTask systemTask3{"ProjectPart3",
{1, 2},
{1, 2},
{{"YI", "2", 1}, {"SAN", "3", 3}},
{"YI", "LIANG"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
{"/framework/path", 1, IncludeSearchPathType::System}},
{{"/to/path1", 1, IncludeSearchPathType::User},
{"/to/path2", 2, IncludeSearchPathType::User}}};
Utils::SmallStringVector toolChainArguments = {"toolChainArguments"}; Utils::SmallStringVector toolChainArguments = {"toolChainArguments"};
}; };
@@ -103,21 +116,33 @@ TEST_F(PchTasksMerger, AddProjectTasks)
EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2))); EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2)));
EXPECT_CALL(mockPchTaskQueue, processEntries()); EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks( merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
{{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}}, {clone(systemTask1), clone(projectTask2)}},
std::move(toolChainArguments)); std::move(toolChainArguments));
} }
TEST_F(PchTasksMerger, AddSystemTasks) TEST_F(PchTasksMerger, AddSystemTasks)
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1, systemTask2))); EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(_, systemTask3)));
EXPECT_CALL(mockPchTaskQueue, processEntries()); EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks( merger.mergeTasks({{clone(systemTask1), clone(projectTask1)},
{{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}}, {clone(systemTask2), clone(projectTask2)},
std::move(toolChainArguments)); {clone(systemTask3), clone(projectTask2)}},
std::move(toolChainArguments));
}
TEST_F(PchTasksMerger, AddSystemOnlyOneTask)
{
InSequence s;
EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1)));
EXPECT_CALL(mockPchTaskQueue, processEntries());
merger.mergeTasks({{clone(systemTask1), clone(projectTask1)}},
std::move(toolChainArguments));
} }
TEST_F(PchTasksMerger, RemoveTasks) TEST_F(PchTasksMerger, RemoveTasks)
@@ -126,4 +151,233 @@ TEST_F(PchTasksMerger, RemoveTasks)
merger.removePchTasks({"project1", "project2"}); merger.removePchTasks({"project1", "project2"});
} }
TEST_F(PchTasksMerger, MergeMacros)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto macros = Merger::mergeMacros(compilerMacros1, compilerMacros2);
ASSERT_THAT(macros,
ElementsAre(CompilerMacro{"BA"},
CompilerMacro{"ER", "2", 2},
CompilerMacro{"SE", "4", 1},
CompilerMacro{"YI", "1", 1},
CompilerMacro{"YI"},
CompilerMacro{"SAN", "3", 3}));
} }
TEST_F(PchTasksMerger, MacrosCanBeMerged)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"QI"}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"BA"}, {"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_TRUE(canBeMerged);
}
TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseDifferentValue)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "1", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, MacrosCannotBeMergedBecauseUndefinedMacro)
{
CompilerMacros compilerMacros1{{"ER", "2", 2}, {"SE", "4", 1}, {"YI"}, {"SAN", "3", 3}};
CompilerMacros compilerMacros2{{"ER", "2", 2}, {"YI", "1", 1}, {"SAN", "3", 3}};
auto canBeMerged = Merger::hasDuplicates(Merger::mergeMacros(compilerMacros1, compilerMacros2));
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, CanMergePchTasks)
{
auto canBeMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_TRUE(canBeMerged);
}
TEST_F(PchTasksMerger, CannotMergePchTasks)
{
auto canBeMerged = Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_FALSE(canBeMerged);
}
TEST_F(PchTasksMerger, IsMergedIsSet)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_TRUE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, IsMergedIsNotSet)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_FALSE(systemTask3.isMerged);
}
TEST_F(PchTasksMerger, DontMergeLanguage)
{
systemTask2.language = Utils::Language::C;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, MergeCompilerMacros)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4},
CompilerMacro{"WU", "5", 5},
CompilerMacro{"YI", "1", 1},
CompilerMacro{"SAN", "3", 3}));
}
TEST_F(PchTasksMerger, DontMergeCompilerMacros)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3}));
}
TEST_F(PchTasksMerger, MergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2, 11, 12));
}
TEST_F(PchTasksMerger, DontMergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2));
}
TEST_F(PchTasksMerger, MergeAllIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3, 11, 12, 13));
}
TEST_F(PchTasksMerger, DontAllMergeIncludes)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3));
}
TEST_F(PchTasksMerger, MergeProjectIds)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.projectPartIds, ElementsAre("ProjectPart1", "ProjectPart2"));
}
TEST_F(PchTasksMerger, DontMergeProjectIds)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.projectPartIds, ElementsAre("ProjectPart1"));
}
TEST_F(PchTasksMerger, MergeIncludeSearchPaths)
{
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.systemIncludeSearchPaths,
ElementsAre(IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}));
}
TEST_F(PchTasksMerger, DontMergeIncludeSearchPaths)
{
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.systemIncludeSearchPaths,
ElementsAre(IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System},
IncludeSearchPath{"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}));
}
TEST_F(PchTasksMerger, ChooseLanguageVersionFromFirstTask)
{
systemTask2.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX17);
}
TEST_F(PchTasksMerger, ChooseLanguageVersionFromSecondTask)
{
systemTask1.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX17);
}
TEST_F(PchTasksMerger, DontChooseLanguageVersion)
{
systemTask3.languageVersion = Utils::LanguageVersion::CXX17;
Merger::mergePchTasks(systemTask1, systemTask3);
ASSERT_THAT(systemTask1.languageVersion, Utils::LanguageVersion::CXX98);
}
TEST_F(PchTasksMerger, FirstTaskIsNotMergedAgain)
{
systemTask1.isMerged = true;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(systemTask2.isMerged);
}
TEST_F(PchTasksMerger, DontMergeAlreadyMergedFirstTask)
{
systemTask1.isMerged = true;
bool isMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(isMerged);
}
TEST_F(PchTasksMerger, SecondTaskIsNotMergedAgain)
{
systemTask2.isMerged = true;
Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_THAT(systemTask1.includes, ElementsAre(1, 2));
}
TEST_F(PchTasksMerger, DontMergeAlreadyMergedSecondTask)
{
systemTask2.isMerged = true;
bool isMerged = Merger::mergePchTasks(systemTask1, systemTask2);
ASSERT_FALSE(isMerged);
}
} // namespace

View File

@@ -46,7 +46,7 @@ protected:
{3, SourceType::ProjectInclude, 0}, {3, SourceType::ProjectInclude, 0},
{4, SourceType::TopSystemInclude, 0}, {4, SourceType::TopSystemInclude, 0},
{5, SourceType::TopProjectInclude, 0}}; {5, SourceType::TopProjectInclude, 0}};
UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"SAN", 3}, {"SE", 4}, {"WU", 5}}; UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"LIU", 2}, {"QI", 3}, {"SAN", 3}, {"SE", 4}, {"WU", 5}};
CompilerMacros compileMacros{{"YI", "1", 1}, CompilerMacros compileMacros{{"YI", "1", 1},
{"ER", "2", 2}, {"ER", "2", 2},
{"SAN", "3", 3}, {"SAN", "3", 3},
@@ -57,36 +57,35 @@ protected:
TEST_F(UsedMacroFilter, SystemIncludes) TEST_F(UsedMacroFilter, SystemIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4})); ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4}));
} }
TEST_F(UsedMacroFilter, ProjectIncludes) TEST_F(UsedMacroFilter, ProjectIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5}));
} }
TEST_F(UsedMacroFilter, TopSystemIncludes) TEST_F(UsedMacroFilter, TopSystemIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4}));
} }
TEST_F(UsedMacroFilter, TopProjectIncludes) TEST_F(UsedMacroFilter, TopProjectIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5}));
} }
TEST_F(UsedMacroFilter, AllIncludes) TEST_F(UsedMacroFilter, AllIncludes)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.allIncludes, ASSERT_THAT(filter.allIncludes,
ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5}));
@@ -94,36 +93,36 @@ TEST_F(UsedMacroFilter, AllIncludes)
TEST_F(UsedMacroFilter, SystemUsedMacros) TEST_F(UsedMacroFilter, SystemUsedMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.systemUsedMacros, ElementsAre(UsedMacro{"ER", 2}, UsedMacro{"SE", 4})); ASSERT_THAT(filter.systemUsedMacros, ElementsAre("ER", "SE", "LIU"));
} }
TEST_F(UsedMacroFilter, ProjectUsedMacros) TEST_F(UsedMacroFilter, ProjectUsedMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
ASSERT_THAT(filter.projectUsedMacros, ElementsAre(UsedMacro{"WU", 5}, UsedMacro{"SAN", 3})); ASSERT_THAT(filter.projectUsedMacros, ElementsAre("QI", "WU", "SAN"));
} }
TEST_F(UsedMacroFilter, SystemCompileMacros) TEST_F(UsedMacroFilter, SystemCompileMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
filter.filter(compileMacros);
ASSERT_THAT(filter.systemCompilerMacros, ASSERT_THAT(filter.systemCompilerMacros,
ElementsAre(CompilerMacro{"ER", "2", 2}, CompilerMacro{"SE", "4", 4})); ElementsAre(CompilerMacro{"ER", "2", 2},
CompilerMacro{"SE", "4", 4},
CompilerMacro{"LIU"}));
} }
TEST_F(UsedMacroFilter, ProjectCompileMacros) TEST_F(UsedMacroFilter, ProjectCompileMacros)
{ {
ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros);
filter.filter(compileMacros);
ASSERT_THAT(filter.projectCompilerMacros, ASSERT_THAT(filter.projectCompilerMacros,
ElementsAre(CompilerMacro{"WU", "5", 5}, CompilerMacro{"SAN", "3", 3})); ElementsAre(CompilerMacro{"QI"},
CompilerMacro{"WU", "5", 5},
CompilerMacro{"SAN", "3", 3}));
} }
} // namespace } // namespace