blob: da482b88f5b81062a130a42a095c587fae47fed0 [file] [log] [blame]
Eric Liu826b7832017-10-26 10:38:14 +00001//===- 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
25namespace clang {
26namespace tooling {
27
28namespace {
29
30// This traverses the AST and outputs function name as key and "1" as value for
31// each function declaration.
32class ASTConsumerWithResult
33 : public ASTConsumer,
34 public RecursiveASTVisitor<ASTConsumerWithResult> {
35public:
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
51private:
52 ExecutionContext *const Context;
53};
54
55class ReportResultAction : public ASTFrontendAction {
56public:
57 explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {
58 assert(Context != nullptr);
59 }
60
61protected:
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
70private:
71 ExecutionContext *const Context;
72};
73
74class ReportResultActionFactory : public FrontendActionFactory {
75public:
76 ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}
77 FrontendAction *create() override { return new ReportResultAction(Context); }
78
79private:
80 ExecutionContext *const Context;
81};
82
83} // namespace
84
85class TestToolExecutor : public ToolExecutor {
86public:
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
112private:
113 CommonOptionsParser OptionsParser;
114 std::string SourcePaths;
115 std::map<std::string, std::string> VFS;
116};
117
118const char *TestToolExecutor::ExecutorName = "test-executor";
119
120class TestToolExecutorPlugin : public ToolExecutorPlugin {
121public:
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// This anchor is used to force the linker to link in the generated object file
129// and thus register the plugin.
130extern volatile int ToolExecutorPluginAnchorSource;
131
132static int LLVM_ATTRIBUTE_UNUSED TestToolExecutorPluginAnchorDest =
133 ToolExecutorPluginAnchorSource;
134
135static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin>
136 X("test-executor", "Plugin for TestToolExecutor.");
137
138llvm::cl::OptionCategory TestCategory("execution-test options");
139
140TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) {
141 std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"};
142 int argc = argv.size();
143 auto Executor =
144 createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
145 ASSERT_FALSE((bool)Executor);
146 llvm::consumeError(Executor.takeError());
147}
148
149TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) {
150 llvm::cl::opt<std::string> BeforeReset(
151 "before_reset", llvm::cl::desc("Defined before reset."),
152 llvm::cl::init(""));
153
154 llvm::cl::ResetAllOptionOccurrences();
155
156 std::vector<const char *> argv = {"prog", "--before_reset=set", "f"};
157 int argc = argv.size();
158 auto Executor =
159 createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
160 ASSERT_TRUE((bool)Executor);
161 EXPECT_EQ(BeforeReset, "set");
162 BeforeReset.removeArgument();
163}
164
165TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) {
166 std::vector<const char *> argv = {"prog", "standalone.cpp"};
167 int argc = argv.size();
168 auto Executor =
169 createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
170 ASSERT_TRUE((bool)Executor);
171 EXPECT_EQ(Executor->get()->getExecutorName(),
172 StandaloneToolExecutor::ExecutorName);
173}
174
175TEST(CreateToolExecutorTest, CreateTestToolExecutor) {
176 std::vector<const char *> argv = {"prog", "test.cpp",
177 "--executor=test-executor"};
178 int argc = argv.size();
179 auto Executor =
180 createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory);
181 ASSERT_TRUE((bool)Executor);
182 EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);
183}
184
185TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {
186 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
187 StandaloneToolExecutor Executor(Compilations,
188 std::vector<std::string>(1, "/a.cc"));
189 Executor.mapVirtualFile("/a.cc", "int x = 0;");
190
191 auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),
192 getClangSyntaxOnlyAdjuster());
193 ASSERT_TRUE(!Err);
194}
195
196TEST(StandaloneToolTest, SimpleAction) {
197 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
198 StandaloneToolExecutor Executor(Compilations,
199 std::vector<std::string>(1, "/a.cc"));
200 Executor.mapVirtualFile("/a.cc", "int x = 0;");
201
202 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
203 new ReportResultActionFactory(Executor.getExecutionContext())));
204 ASSERT_TRUE(!Err);
205 auto KVs = Executor.getToolResults()->AllKVResults();
206 ASSERT_EQ(KVs.size(), 0u);
207}
208
209TEST(StandaloneToolTest, SimpleActionWithResult) {
210 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
211 StandaloneToolExecutor Executor(Compilations,
212 std::vector<std::string>(1, "/a.cc"));
213 Executor.mapVirtualFile("/a.cc", "int x = 0; void f() {}");
214
215 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
216 new ReportResultActionFactory(Executor.getExecutionContext())));
217 ASSERT_TRUE(!Err);
218 auto KVs = Executor.getToolResults()->AllKVResults();
219 ASSERT_EQ(KVs.size(), 1u);
220 EXPECT_EQ("f", KVs[0].first);
221 EXPECT_EQ("1", KVs[0].second);
222
223 Executor.getToolResults()->forEachResult(
224 [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); });
225}
226
227} // end namespace tooling
228} // end namespace clang