Add a tool executor that runs actions on all TUs in the compilation database.

Summary: Tool results are deduplicated by the result key.

Reviewers: hokein

Subscribers: klimek, mgorny, cfe-commits

Differential Revision: https://reviews.llvm.org/D41729

llvm-svn: 321864
diff --git a/clang/unittests/Tooling/ExecutionTest.cpp b/clang/unittests/Tooling/ExecutionTest.cpp
index b0c16d6..68c4bf2 100644
--- a/clang/unittests/Tooling/ExecutionTest.cpp
+++ b/clang/unittests/Tooling/ExecutionTest.cpp
@@ -7,17 +7,19 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Tooling/Execution.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/AllTUsExecution.h"
 #include "clang/Tooling/CompilationDatabase.h"
-#include "clang/Tooling/Execution.h"
 #include "clang/Tooling/StandaloneExecution.h"
 #include "clang/Tooling/ToolExecutorPluginRegistry.h"
 #include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <algorithm>
 #include <string>
@@ -217,5 +219,70 @@
       [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); });
 }
 
+class FixedCompilationDatabaseWithFiles : public CompilationDatabase {
+public:
+  FixedCompilationDatabaseWithFiles(Twine Directory,
+                                    ArrayRef<std::string> Files,
+                                    ArrayRef<std::string> CommandLine)
+      : FixedCompilations(Directory, CommandLine), Files(Files) {}
+
+  std::vector<CompileCommand>
+  getCompileCommands(StringRef FilePath) const override {
+    return FixedCompilations.getCompileCommands(FilePath);
+  }
+
+  std::vector<std::string> getAllFiles() const override { return Files; }
+
+private:
+  FixedCompilationDatabase FixedCompilations;
+  std::vector<std::string> Files;
+};
+
+MATCHER_P(Named, Name, "") { return arg.first == Name; }
+
+TEST(AllTUsToolTest, AFewFiles) {
+  FixedCompilationDatabaseWithFiles Compilations(".", {"a.cc", "b.cc", "c.cc"},
+                                                 std::vector<std::string>());
+  AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
+  Executor.mapVirtualFile("a.cc", "void x() {}");
+  Executor.mapVirtualFile("b.cc", "void y() {}");
+  Executor.mapVirtualFile("c.cc", "void z() {}");
+
+  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
+      new ReportResultActionFactory(Executor.getExecutionContext())));
+  ASSERT_TRUE(!Err);
+  EXPECT_THAT(
+      Executor.getToolResults()->AllKVResults(),
+      ::testing::UnorderedElementsAre(Named("x"), Named("y"), Named("z")));
+}
+
+TEST(AllTUsToolTest, ManyFiles) {
+  unsigned NumFiles = 100;
+  std::vector<std::string> Files;
+  std::map<std::string, std::string> FileToContent;
+  std::vector<std::string> ExpectedSymbols;
+  for (unsigned i = 1; i <= NumFiles; ++i) {
+    std::string File = "f" + std::to_string(i) + ".cc";
+    std::string Symbol = "looong_function_name_" + std::to_string(i);
+    Files.push_back(File);
+    FileToContent[File] = "void " + Symbol + "() {}";
+    ExpectedSymbols.push_back(Symbol);
+  }
+  FixedCompilationDatabaseWithFiles Compilations(".", Files,
+                                                 std::vector<std::string>());
+  AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
+  for (const auto &FileAndContent : FileToContent) {
+    Executor.mapVirtualFile(FileAndContent.first, FileAndContent.second);
+  }
+
+  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
+      new ReportResultActionFactory(Executor.getExecutionContext())));
+  ASSERT_TRUE(!Err);
+  std::vector<std::string> Results;
+  Executor.getToolResults()->forEachResult(
+      [&](StringRef Name, StringRef) { Results.push_back(Name); });
+  EXPECT_THAT(ExpectedSymbols, ::testing::UnorderedElementsAreArray(Results));
+}
+
 } // end namespace tooling
 } // end namespace clang