From 0082a82fc62fef78b64558faf70a7691452bb1f3 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 30 Jan 2019 18:48:59 +0100 Subject: [PATCH] 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 --- src/libs/clangsupport/commandlinebuilder.h | 7 + src/libs/clangsupport/compilermacro.h | 28 +- .../clangpchmanagerbackend/source/pchtask.h | 9 +- .../source/pchtaskgenerator.cpp | 8 +- .../source/pchtasksmerger.cpp | 129 ++++++- .../source/pchtasksmerger.h | 14 +- .../source/usedmacrofilter.h | 92 +++-- .../source/usedmacro.h | 4 + .../unit/unittest/commandlinebuilder-test.cpp | 2 +- .../unit/unittest/gtest-creator-printing.cpp | 7 +- tests/unit/unittest/pchtaskgenerator-test.cpp | 2 - tests/unit/unittest/pchtasksmerger-test.cpp | 326 ++++++++++++++++-- tests/unit/unittest/usedmacrofilter-test.cpp | 37 +- 13 files changed, 544 insertions(+), 121 deletions(-) diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h index 6a9975a3ac9..df116197ab1 100644 --- a/src/libs/clangsupport/commandlinebuilder.h +++ b/src/libs/clangsupport/commandlinebuilder.h @@ -182,6 +182,13 @@ public: { CompilerMacros macros = compilerMacros; + macros.erase(std::remove_if(macros.begin(), + macros.end(), + [](const auto ¯o) { + return macro.type == CompilerMacroType::NotDefined; + }), + macros.end()); + std::sort(macros.begin(), macros.end(), [](const CompilerMacro &first, const CompilerMacro &second) { diff --git a/src/libs/clangsupport/compilermacro.h b/src/libs/clangsupport/compilermacro.h index ddba1a40762..798bab2ebd7 100644 --- a/src/libs/clangsupport/compilermacro.h +++ b/src/libs/clangsupport/compilermacro.h @@ -31,6 +31,8 @@ namespace ClangBackEnd { +enum class CompilerMacroType : unsigned char { Define, NotDefined }; + class CompilerMacro { public: @@ -40,39 +42,57 @@ public: : key(std::move(key)) , value(std::move(value)) , 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) { out << compilerMacro.key; out << compilerMacro.value; + out << compilerMacro.index; + out << static_cast(compilerMacro.type); return out; } friend QDataStream &operator>>(QDataStream &in, CompilerMacro &compilerMacro) { + unsigned char type; + in >> compilerMacro.key; in >> compilerMacro.value; + in >> compilerMacro.index; + in >> type; + + compilerMacro.type = static_cast(type); return in; } friend bool operator==(const CompilerMacro &first, const CompilerMacro &second) { - return first.key == second.key - && first.value == second.value; + return first.key == second.key && first.value == second.value && first.type == second.type; } 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: Utils::SmallString key; Utils::SmallString value; - int index = 0; + int index = -1; + CompilerMacroType type = CompilerMacroType::NotDefined; }; using CompilerMacros = std::vector; diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h index 46c3bf2503f..c94d7ac8164 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtask.h +++ b/src/tools/clangpchmanagerbackend/source/pchtask.h @@ -43,7 +43,7 @@ public: FilePathIds &&includes, FilePathIds &&allIncludes, CompilerMacros &&compilerMacros, - UsedMacros &&usedMacros, + Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths, @@ -54,7 +54,6 @@ public: , includes(includes) , allIncludes(allIncludes) , compilerMacros(compilerMacros) - , usedMacros(usedMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , toolChainArguments(std::move(toolChainArguments)) @@ -67,7 +66,7 @@ public: FilePathIds &&includes, FilePathIds &&allIncludes, CompilerMacros &&compilerMacros, - UsedMacros &&usedMacros, + Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, IncludeSearchPaths systemIncludeSearchPaths, IncludeSearchPaths projectIncludeSearchPaths, @@ -78,7 +77,6 @@ public: , includes(includes) , allIncludes(allIncludes) , compilerMacros(compilerMacros) - , usedMacros(usedMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) , toolChainArguments(std::move(toolChainArguments)) @@ -92,7 +90,6 @@ public: return first.systemPchPath == second.systemPchPath && first.projectPartIds == second.projectPartIds && first.includes == second.includes && first.compilerMacros == second.compilerMacros - && first.usedMacros == second.usedMacros && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths && first.toolChainArguments == second.toolChainArguments @@ -109,13 +106,13 @@ public: FilePathIds includes; FilePathIds allIncludes; CompilerMacros compilerMacros; - UsedMacros usedMacros; IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths; Utils::SmallStringVector toolChainArguments; Utils::Language language = Utils::Language::Cxx; Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98; Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None; + bool isMerged = false; }; class PchTaskSet diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp index 569e4a1d8a3..82584ad1dd8 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp @@ -42,9 +42,9 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, for (auto &projectPart : projectParts) { BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); - UsedMacroFilter filter{buildDependency.includes, buildDependency.usedMacros}; - - filter.filter(projectPart.compilerMacros); + UsedMacroFilter filter{buildDependency.includes, + buildDependency.usedMacros, + projectPart.compilerMacros}; pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(), std::move(filter.topSystemIncludes), @@ -53,7 +53,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, std::move(filter.systemUsedMacros), projectPart.toolChainArguments, projectPart.systemIncludeSearchPaths, - projectPart.projectIncludeSearchPaths, + {}, projectPart.language, projectPart.languageVersion, projectPart.languageExtension}, diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp index 9ace04e09de..636d9a32364 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp @@ -30,20 +30,10 @@ namespace ClangBackEnd { void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets, - Utils::SmallStringVector &&/*toolChainArguments*/) + Utils::SmallStringVector && /*toolChainArguments*/) { - PchTasks systemTasks; - systemTasks.reserve(taskSets.size()); - 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)); + mergeSystemTasks(taskSets); + addProjectTasksToQueue(taskSets); m_pchTaskQueue.processEntries(); } @@ -52,4 +42,117 @@ void PchTasksMerger::removePchTasks(const Utils::SmallStringVector &projectPartI m_pchTaskQueue.removePchTasks(projectPartIds); } +template>> +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 ¤tTask) { + 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 diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h index 9c777b8a7cb..26df2022b4d 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h @@ -32,7 +32,7 @@ namespace ClangBackEnd { class PchTaskQueueInterface; -class PchTasksMerger : public PchTasksMergerInterface +class PchTasksMerger final : public PchTasksMergerInterface { public: PchTasksMerger(PchTaskQueueInterface &pchTaskQueue) @@ -42,6 +42,18 @@ public: void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) 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: PchTaskQueueInterface &m_pchTaskQueue; }; diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index e7969c4ea1b..0b39ae1f4f2 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -32,6 +32,27 @@ namespace ClangBackEnd { +template +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 { public: @@ -41,11 +62,14 @@ public: FilePathIds system; }; - UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros) + UsedMacroFilter(const SourceEntries &includes, + const UsedMacros &usedMacros, + const CompilerMacros &compilerMacros) { filterIncludes(includes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); + filter(compilerMacros); } void filterIncludes(const SourceEntries &includes) @@ -98,7 +122,8 @@ private: 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 { @@ -113,52 +138,57 @@ private: } }; - UsedMacros filtertedMacros; + Utils::SmallStringVector filtertedMacros; filtertedMacros.reserve(usedMacros.size()); - std::set_intersection(usedMacros.begin(), - usedMacros.end(), - filePathId.begin(), - filePathId.end(), - std::back_inserter(filtertedMacros), - Compare{}); + set_greedy_intersection(usedMacros.begin(), + usedMacros.end(), + filePathId.begin(), + filePathId.end(), + std::back_inserter(filtertedMacros), + Compare{}); - std::sort(filtertedMacros.begin(), - filtertedMacros.end(), - [](const UsedMacro &first, const UsedMacro &second) { - return first.macroName < second.macroName; - }); + std::sort(filtertedMacros.begin(), filtertedMacros.end()); return filtertedMacros; } static CompilerMacros filtercompilerMacros(const CompilerMacros &indexedCompilerMacro, - const UsedMacros &usedMacros) + const Utils::SmallStringVector &usedMacros) { + CompilerMacros filtertedCompilerMacros; + filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size()); + struct Compare { - bool operator()(const UsedMacro &usedMacro, - const CompilerMacro &compileMacro) + bool operator()(const CompilerMacro &compilerMacro, Utils::SmallStringView usedMacro) { - return usedMacro.macroName < compileMacro.key; + return compilerMacro.key < usedMacro; } - bool operator()(const CompilerMacro &compileMacro, - const UsedMacro &usedMacro) + bool operator()(Utils::SmallStringView usedMacro, const CompilerMacro &compilerMacro) { - return compileMacro.key < usedMacro.macroName; + return usedMacro < compilerMacro.key; } }; - CompilerMacros filtertedCompilerMacros; - filtertedCompilerMacros.reserve(indexedCompilerMacro.size()); + set_greedy_intersection(indexedCompilerMacro.begin(), + indexedCompilerMacro.end(), + usedMacros.begin(), + usedMacros.end(), + std::back_inserter(filtertedCompilerMacros), + Compare{}); - std::set_intersection(indexedCompilerMacro.begin(), - indexedCompilerMacro.end(), - usedMacros.begin(), - usedMacros.end(), - std::back_inserter(filtertedCompilerMacros), - Compare{}); + auto split = filtertedCompilerMacros.end(); + + std::set_difference(usedMacros.begin(), + usedMacros.end(), + filtertedCompilerMacros.begin(), + filtertedCompilerMacros.end(), + std::back_inserter(filtertedCompilerMacros), + Compare{}); + + std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end()); return filtertedCompilerMacros; } @@ -169,8 +199,8 @@ public: FilePathIds systemIncludes; FilePathIds topProjectIncludes; FilePathIds topSystemIncludes; - UsedMacros projectUsedMacros; - UsedMacros systemUsedMacros; + Utils::SmallStringVector projectUsedMacros; + Utils::SmallStringVector systemUsedMacros; CompilerMacros projectCompilerMacros; CompilerMacros systemCompilerMacros; }; diff --git a/src/tools/clangrefactoringbackend/source/usedmacro.h b/src/tools/clangrefactoringbackend/source/usedmacro.h index a7312b63761..8fc992e39b1 100644 --- a/src/tools/clangrefactoringbackend/source/usedmacro.h +++ b/src/tools/clangrefactoringbackend/source/usedmacro.h @@ -62,6 +62,10 @@ public: { return !(first == second); } + + operator Utils::SmallStringView() const { return macroName; } + operator const Utils::SmallString &() const { return macroName; } + public: Utils::SmallString macroName; FilePathId filePathId; diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp index f51a4f6a714..c3b60df3694 100644 --- a/tests/unit/unittest/commandlinebuilder-test.cpp +++ b/tests/unit/unittest/commandlinebuilder-test.cpp @@ -511,7 +511,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath) TYPED_TEST(CommandLineBuilder, CompilerMacros) { - this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}}; + this->emptyProjectInfo.compilerMacros = {{"YI", "1", 2}, {"ER", "2", 1}, {"SAN"}}; Builder builder{this->emptyProjectInfo}; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 682d28740b0..3901cb0d305 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -1157,10 +1157,9 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes) std::ostream &operator<<(std::ostream &out, const PchTask &task) { return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros - << ", " << task.usedMacros << ", " << toText(task.language) << ", " - << task.systemIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " - << task.toolChainArguments << ", " << toText(task.languageVersion) << ", " - << toText(task.languageExtension) << ")"; + << toText(task.language) << ", " << task.systemIncludeSearchPaths << ", " + << task.projectIncludeSearchPaths << ", " << task.toolChainArguments << ", " + << toText(task.languageVersion) << ", " << toText(task.languageExtension) << ")"; } std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp index 0b2ec3968e3..a3ebb3c17be 100644 --- a/tests/unit/unittest/pchtaskgenerator-test.cpp +++ b/tests/unit/unittest/pchtaskgenerator-test.cpp @@ -99,7 +99,6 @@ TEST_F(PchTaskGenerator, AddProjectParts) Field(&PchTask::allIncludes, IsEmpty()), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), - Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})), Field(&PchTask::systemIncludeSearchPaths, ElementsAre( 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::compilerMacros, ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), - Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"YI", 1}, UsedMacro{"SAN", 3})), Field(&PchTask::systemIncludeSearchPaths, ElementsAre( IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp index f54e7aca582..e878438f339 100644 --- a/tests/unit/unittest/pchtasksmerger-test.cpp +++ b/tests/unit/unittest/pchtasksmerger-test.cpp @@ -31,11 +31,14 @@ namespace { +using ClangBackEnd::CompilerMacro; +using ClangBackEnd::CompilerMacros; using ClangBackEnd::IncludeSearchPath; using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::PchTask; using ClangBackEnd::PchTaskSet; - +using Merger = ClangBackEnd::PchTasksMerger; +using Id = ClangBackEnd::FilePathId; class PchTasksMerger : public testing::Test { protected: @@ -51,48 +54,58 @@ protected: ClangBackEnd::PchTasksMerger merger{mockPchTaskQueue}; PchTask systemTask1{"ProjectPart1", {1, 2}, - {1, 2}, + {1, 2, 3}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}, + {"YI", "LIANG"}, {"--yi"}, - {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, - IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, - IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, - {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, - IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; + {{"/system/path", 2, IncludeSearchPathType::System}, + {"/builtin/path2", 3, IncludeSearchPathType::BuiltIn}, + {"/framework/path", 1, IncludeSearchPathType::System}}, + {{"/to/path1", 1, IncludeSearchPathType::User}, + {"/to/path2", 2, IncludeSearchPathType::User}}}; PchTask projectTask1{"ProjectPart1", {11, 12}, {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}, + {"ER", "SAN"}, {"--yi"}, - {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, - IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, - IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, - {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, - IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; + {{"/system/path", 1, IncludeSearchPathType::System}, + {"/builtin/path", 2, IncludeSearchPathType::BuiltIn}}, + {{"/to/path1", 1, IncludeSearchPathType::User}, + {"/to/path2", 2, IncludeSearchPathType::User}}}; PchTask systemTask2{"ProjectPart2", - {1, 2}, - {1, 2}, - {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}, + {11, 12}, + {11, 12, 13}, + {{"SE", "4", 4}, {"WU", "5", 5}}, + {"ER", "SAN"}, {"--yi"}, - {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, - IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, - IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, - {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, - IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; + {{"/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}}}; PchTask projectTask2{"ProjectPart2", {11, 12}, {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}, + {"ER", "SAN"}, {"--yi"}, - {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, - IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, - IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, - {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, - IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; + {{"/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}}}; + 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"}; }; @@ -103,21 +116,33 @@ TEST_F(PchTasksMerger, AddProjectTasks) EXPECT_CALL(mockPchTaskQueue, addProjectPchTasks(ElementsAre(projectTask1, projectTask2))); EXPECT_CALL(mockPchTaskQueue, processEntries()); - merger.mergeTasks( - {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}}, - std::move(toolChainArguments)); + merger.mergeTasks({{clone(systemTask1), clone(projectTask1)}, + {clone(systemTask1), clone(projectTask2)}}, + std::move(toolChainArguments)); } TEST_F(PchTasksMerger, AddSystemTasks) { InSequence s; - EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(systemTask1, systemTask2))); + EXPECT_CALL(mockPchTaskQueue, addSystemPchTasks(ElementsAre(_, systemTask3))); EXPECT_CALL(mockPchTaskQueue, processEntries()); - merger.mergeTasks( - {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}}, - std::move(toolChainArguments)); + merger.mergeTasks({{clone(systemTask1), clone(projectTask1)}, + {clone(systemTask2), clone(projectTask2)}, + {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) @@ -126,4 +151,233 @@ TEST_F(PchTasksMerger, RemoveTasks) 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 diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index bc5b79cccf5..b02cd7e5e02 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -46,7 +46,7 @@ protected: {3, SourceType::ProjectInclude, 0}, {4, SourceType::TopSystemInclude, 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}, {"ER", "2", 2}, {"SAN", "3", 3}, @@ -57,36 +57,35 @@ protected: TEST_F(UsedMacroFilter, SystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4})); } TEST_F(UsedMacroFilter, ProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); } TEST_F(UsedMacroFilter, TopSystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); } TEST_F(UsedMacroFilter, TopProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); } - TEST_F(UsedMacroFilter, AllIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); ASSERT_THAT(filter.allIncludes, ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); @@ -94,36 +93,36 @@ TEST_F(UsedMacroFilter, AllIncludes) 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) { - 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) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); - - filter.filter(compileMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); 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) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); - - filter.filter(compileMacros); + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); 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