ExecutionTest.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //===- unittest/Tooling/ExecutionTest.cpp - Tool execution tests. --------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/AST/ASTConsumer.h"
  10. #include "clang/AST/DeclCXX.h"
  11. #include "clang/AST/RecursiveASTVisitor.h"
  12. #include "clang/Frontend/ASTUnit.h"
  13. #include "clang/Frontend/FrontendAction.h"
  14. #include "clang/Frontend/FrontendActions.h"
  15. #include "clang/Tooling/CompilationDatabase.h"
  16. #include "clang/Tooling/Execution.h"
  17. #include "clang/Tooling/StandaloneExecution.h"
  18. #include "clang/Tooling/ToolExecutorPluginRegistry.h"
  19. #include "clang/Tooling/Tooling.h"
  20. #include "gtest/gtest.h"
  21. #include <algorithm>
  22. #include <string>
  23. namespace clang {
  24. namespace tooling {
  25. namespace {
  26. // This traverses the AST and outputs function name as key and "1" as value for
  27. // each function declaration.
  28. class ASTConsumerWithResult
  29. : public ASTConsumer,
  30. public RecursiveASTVisitor<ASTConsumerWithResult> {
  31. public:
  32. using ASTVisitor = RecursiveASTVisitor<ASTConsumerWithResult>;
  33. explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) {
  34. assert(Context != nullptr);
  35. }
  36. void HandleTranslationUnit(clang::ASTContext &Context) override {
  37. TraverseDecl(Context.getTranslationUnitDecl());
  38. }
  39. bool TraverseFunctionDecl(clang::FunctionDecl *Decl) {
  40. Context->reportResult(Decl->getNameAsString(), "1");
  41. return ASTVisitor::TraverseFunctionDecl(Decl);
  42. }
  43. private:
  44. ExecutionContext *const Context;
  45. };
  46. class ReportResultAction : public ASTFrontendAction {
  47. public:
  48. explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {
  49. assert(Context != nullptr);
  50. }
  51. protected:
  52. std::unique_ptr<clang::ASTConsumer>
  53. CreateASTConsumer(clang::CompilerInstance &compiler,
  54. StringRef /* dummy */) override {
  55. std::unique_ptr<clang::ASTConsumer> ast_consumer{
  56. new ASTConsumerWithResult(Context)};
  57. return ast_consumer;
  58. }
  59. private:
  60. ExecutionContext *const Context;
  61. };
  62. class ReportResultActionFactory : public FrontendActionFactory {
  63. public:
  64. ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}
  65. FrontendAction *create() override { return new ReportResultAction(Context); }
  66. private:
  67. ExecutionContext *const Context;
  68. };
  69. } // namespace
  70. class TestToolExecutor : public ToolExecutor {
  71. public:
  72. static const char *ExecutorName;
  73. TestToolExecutor(CommonOptionsParser Options)
  74. : OptionsParser(std::move(Options)) {}
  75. StringRef getExecutorName() const override { return ExecutorName; }
  76. llvm::Error
  77. execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,
  78. ArgumentsAdjuster>>) override {
  79. return llvm::Error::success();
  80. }
  81. ExecutionContext *getExecutionContext() override { return nullptr; };
  82. ToolResults *getToolResults() override { return nullptr; }
  83. llvm::ArrayRef<std::string> getSourcePaths() const {
  84. return OptionsParser.getSourcePathList();
  85. }
  86. void mapVirtualFile(StringRef FilePath, StringRef Content) override {
  87. VFS[FilePath] = Content;
  88. }
  89. private:
  90. CommonOptionsParser OptionsParser;
  91. std::string SourcePaths;
  92. std::map<std::string, std::string> VFS;
  93. };
  94. const char *TestToolExecutor::ExecutorName = "test-executor";
  95. class TestToolExecutorPlugin : public ToolExecutorPlugin {
  96. public:
  97. llvm::Expected<std::unique_ptr<ToolExecutor>>
  98. create(CommonOptionsParser &OptionsParser) override {
  99. return llvm::make_unique<TestToolExecutor>(std::move(OptionsParser));
  100. }
  101. };
  102. // This anchor is used to force the linker to link in the generated object file
  103. // and thus register the plugin.
  104. extern volatile int ToolExecutorPluginAnchorSource;
  105. static int LLVM_ATTRIBUTE_UNUSED TestToolExecutorPluginAnchorDest =
  106. ToolExecutorPluginAnchorSource;
  107. static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin>
  108. X("test-executor", "Plugin for TestToolExecutor.");
  109. llvm::cl::OptionCategory TestCategory("execution-test options");
  110. TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) {
  111. std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"};
  112. int argc = argv.size();
  113. auto Executor =
  114. createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
  115. ASSERT_FALSE((bool)Executor);
  116. llvm::consumeError(Executor.takeError());
  117. }
  118. TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) {
  119. llvm::cl::opt<std::string> BeforeReset(
  120. "before_reset", llvm::cl::desc("Defined before reset."),
  121. llvm::cl::init(""));
  122. llvm::cl::ResetAllOptionOccurrences();
  123. std::vector<const char *> argv = {"prog", "--before_reset=set", "f"};
  124. int argc = argv.size();
  125. auto Executor =
  126. createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
  127. ASSERT_TRUE((bool)Executor);
  128. EXPECT_EQ(BeforeReset, "set");
  129. BeforeReset.removeArgument();
  130. }
  131. TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) {
  132. std::vector<const char *> argv = {"prog", "standalone.cpp"};
  133. int argc = argv.size();
  134. auto Executor =
  135. createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
  136. ASSERT_TRUE((bool)Executor);
  137. EXPECT_EQ(Executor->get()->getExecutorName(),
  138. StandaloneToolExecutor::ExecutorName);
  139. }
  140. TEST(CreateToolExecutorTest, CreateTestToolExecutor) {
  141. std::vector<const char *> argv = {"prog", "test.cpp",
  142. "--executor=test-executor"};
  143. int argc = argv.size();
  144. auto Executor =
  145. createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
  146. ASSERT_TRUE((bool)Executor);
  147. EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);
  148. }
  149. TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {
  150. FixedCompilationDatabase Compilations(".", std::vector<std::string>());
  151. StandaloneToolExecutor Executor(Compilations,
  152. std::vector<std::string>(1, "a.cc"));
  153. Executor.mapVirtualFile("a.cc", "int x = 0;");
  154. auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),
  155. getClangSyntaxOnlyAdjuster());
  156. ASSERT_TRUE(!Err);
  157. }
  158. TEST(StandaloneToolTest, SimpleAction) {
  159. FixedCompilationDatabase Compilations(".", std::vector<std::string>());
  160. StandaloneToolExecutor Executor(Compilations,
  161. std::vector<std::string>(1, "a.cc"));
  162. Executor.mapVirtualFile("a.cc", "int x = 0;");
  163. auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
  164. new ReportResultActionFactory(Executor.getExecutionContext())));
  165. ASSERT_TRUE(!Err);
  166. auto KVs = Executor.getToolResults()->AllKVResults();
  167. ASSERT_EQ(KVs.size(), 0u);
  168. }
  169. TEST(StandaloneToolTest, SimpleActionWithResult) {
  170. FixedCompilationDatabase Compilations(".", std::vector<std::string>());
  171. StandaloneToolExecutor Executor(Compilations,
  172. std::vector<std::string>(1, "a.cc"));
  173. Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}");
  174. auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
  175. new ReportResultActionFactory(Executor.getExecutionContext())));
  176. ASSERT_TRUE(!Err);
  177. auto KVs = Executor.getToolResults()->AllKVResults();
  178. ASSERT_EQ(KVs.size(), 1u);
  179. EXPECT_EQ("f", KVs[0].first);
  180. EXPECT_EQ("1", KVs[0].second);
  181. Executor.getToolResults()->forEachResult(
  182. [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); });
  183. }
  184. } // end namespace tooling
  185. } // end namespace clang