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