blob: 68c4bf25c914a14c6972c973dc179c072fe17471 [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
Eric Liue25f3672018-01-05 10:32:16 +000010#include "clang/Tooling/Execution.h"
Eric Liu826b7832017-10-26 10:38:14 +000011#include "clang/AST/ASTConsumer.h"
12#include "clang/AST/DeclCXX.h"
13#include "clang/AST/RecursiveASTVisitor.h"
14#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/FrontendAction.h"
16#include "clang/Frontend/FrontendActions.h"
Eric Liue25f3672018-01-05 10:32:16 +000017#include "clang/Tooling/AllTUsExecution.h"
Eric Liu826b7832017-10-26 10:38:14 +000018#include "clang/Tooling/CompilationDatabase.h"
Eric Liu826b7832017-10-26 10:38:14 +000019#include "clang/Tooling/StandaloneExecution.h"
20#include "clang/Tooling/ToolExecutorPluginRegistry.h"
21#include "clang/Tooling/Tooling.h"
Eric Liue25f3672018-01-05 10:32:16 +000022#include "gmock/gmock.h"
Eric Liu826b7832017-10-26 10:38:14 +000023#include "gtest/gtest.h"
24#include <algorithm>
25#include <string>
26
27namespace clang {
28namespace tooling {
29
30namespace {
31
32// This traverses the AST and outputs function name as key and "1" as value for
33// each function declaration.
34class ASTConsumerWithResult
35 : public ASTConsumer,
36 public RecursiveASTVisitor<ASTConsumerWithResult> {
37public:
38 using ASTVisitor = RecursiveASTVisitor<ASTConsumerWithResult>;
39
40 explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) {
41 assert(Context != nullptr);
42 }
43
44 void HandleTranslationUnit(clang::ASTContext &Context) override {
45 TraverseDecl(Context.getTranslationUnitDecl());
46 }
47
48 bool TraverseFunctionDecl(clang::FunctionDecl *Decl) {
49 Context->reportResult(Decl->getNameAsString(), "1");
50 return ASTVisitor::TraverseFunctionDecl(Decl);
51 }
52
53private:
54 ExecutionContext *const Context;
55};
56
57class ReportResultAction : public ASTFrontendAction {
58public:
59 explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {
60 assert(Context != nullptr);
61 }
62
63protected:
64 std::unique_ptr<clang::ASTConsumer>
65 CreateASTConsumer(clang::CompilerInstance &compiler,
66 StringRef /* dummy */) override {
67 std::unique_ptr<clang::ASTConsumer> ast_consumer{
68 new ASTConsumerWithResult(Context)};
69 return ast_consumer;
70 }
71
72private:
73 ExecutionContext *const Context;
74};
75
76class ReportResultActionFactory : public FrontendActionFactory {
77public:
78 ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}
79 FrontendAction *create() override { return new ReportResultAction(Context); }
80
81private:
82 ExecutionContext *const Context;
83};
84
85} // namespace
86
87class TestToolExecutor : public ToolExecutor {
88public:
89 static const char *ExecutorName;
90
91 TestToolExecutor(CommonOptionsParser Options)
92 : OptionsParser(std::move(Options)) {}
93
94 StringRef getExecutorName() const override { return ExecutorName; }
95
96 llvm::Error
97 execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,
98 ArgumentsAdjuster>>) override {
99 return llvm::Error::success();
100 }
101
102 ExecutionContext *getExecutionContext() override { return nullptr; };
103
104 ToolResults *getToolResults() override { return nullptr; }
105
106 llvm::ArrayRef<std::string> getSourcePaths() const {
107 return OptionsParser.getSourcePathList();
108 }
109
110 void mapVirtualFile(StringRef FilePath, StringRef Content) override {
111 VFS[FilePath] = Content;
112 }
113
114private:
115 CommonOptionsParser OptionsParser;
116 std::string SourcePaths;
117 std::map<std::string, std::string> VFS;
118};
119
120const char *TestToolExecutor::ExecutorName = "test-executor";
121
122class TestToolExecutorPlugin : public ToolExecutorPlugin {
123public:
124 llvm::Expected<std::unique_ptr<ToolExecutor>>
125 create(CommonOptionsParser &OptionsParser) override {
126 return llvm::make_unique<TestToolExecutor>(std::move(OptionsParser));
127 }
128};
129
Eric Liu826b7832017-10-26 10:38:14 +0000130static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin>
131 X("test-executor", "Plugin for TestToolExecutor.");
132
133llvm::cl::OptionCategory TestCategory("execution-test options");
134
135TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) {
136 std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"};
137 int argc = argv.size();
Eric Liu190afe92017-11-06 09:29:09 +0000138 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
139 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000140 ASSERT_FALSE((bool)Executor);
141 llvm::consumeError(Executor.takeError());
142}
143
144TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) {
145 llvm::cl::opt<std::string> BeforeReset(
146 "before_reset", llvm::cl::desc("Defined before reset."),
147 llvm::cl::init(""));
148
149 llvm::cl::ResetAllOptionOccurrences();
150
151 std::vector<const char *> argv = {"prog", "--before_reset=set", "f"};
152 int argc = argv.size();
Eric Liu190afe92017-11-06 09:29:09 +0000153 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
154 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000155 ASSERT_TRUE((bool)Executor);
156 EXPECT_EQ(BeforeReset, "set");
157 BeforeReset.removeArgument();
158}
159
160TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) {
161 std::vector<const char *> argv = {"prog", "standalone.cpp"};
162 int argc = argv.size();
Eric Liu190afe92017-11-06 09:29:09 +0000163 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
164 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000165 ASSERT_TRUE((bool)Executor);
166 EXPECT_EQ(Executor->get()->getExecutorName(),
167 StandaloneToolExecutor::ExecutorName);
168}
169
170TEST(CreateToolExecutorTest, CreateTestToolExecutor) {
171 std::vector<const char *> argv = {"prog", "test.cpp",
172 "--executor=test-executor"};
173 int argc = argv.size();
Eric Liu190afe92017-11-06 09:29:09 +0000174 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
175 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000176 ASSERT_TRUE((bool)Executor);
177 EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);
178}
179
180TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {
Eric Liu83454aa2017-10-26 13:09:50 +0000181 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000182 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000183 std::vector<std::string>(1, "a.cc"));
184 Executor.mapVirtualFile("a.cc", "int x = 0;");
Eric Liu826b7832017-10-26 10:38:14 +0000185
186 auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),
187 getClangSyntaxOnlyAdjuster());
188 ASSERT_TRUE(!Err);
189}
190
191TEST(StandaloneToolTest, SimpleAction) {
Eric Liu83454aa2017-10-26 13:09:50 +0000192 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000193 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000194 std::vector<std::string>(1, "a.cc"));
195 Executor.mapVirtualFile("a.cc", "int x = 0;");
Eric Liu826b7832017-10-26 10:38:14 +0000196
197 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
198 new ReportResultActionFactory(Executor.getExecutionContext())));
199 ASSERT_TRUE(!Err);
200 auto KVs = Executor.getToolResults()->AllKVResults();
201 ASSERT_EQ(KVs.size(), 0u);
202}
203
204TEST(StandaloneToolTest, SimpleActionWithResult) {
Eric Liu83454aa2017-10-26 13:09:50 +0000205 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000206 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000207 std::vector<std::string>(1, "a.cc"));
208 Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}");
Eric Liu826b7832017-10-26 10:38:14 +0000209
210 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
211 new ReportResultActionFactory(Executor.getExecutionContext())));
212 ASSERT_TRUE(!Err);
213 auto KVs = Executor.getToolResults()->AllKVResults();
214 ASSERT_EQ(KVs.size(), 1u);
215 EXPECT_EQ("f", KVs[0].first);
216 EXPECT_EQ("1", KVs[0].second);
217
218 Executor.getToolResults()->forEachResult(
219 [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); });
220}
221
Eric Liue25f3672018-01-05 10:32:16 +0000222class FixedCompilationDatabaseWithFiles : public CompilationDatabase {
223public:
224 FixedCompilationDatabaseWithFiles(Twine Directory,
225 ArrayRef<std::string> Files,
226 ArrayRef<std::string> CommandLine)
227 : FixedCompilations(Directory, CommandLine), Files(Files) {}
228
229 std::vector<CompileCommand>
230 getCompileCommands(StringRef FilePath) const override {
231 return FixedCompilations.getCompileCommands(FilePath);
232 }
233
234 std::vector<std::string> getAllFiles() const override { return Files; }
235
236private:
237 FixedCompilationDatabase FixedCompilations;
238 std::vector<std::string> Files;
239};
240
241MATCHER_P(Named, Name, "") { return arg.first == Name; }
242
243TEST(AllTUsToolTest, AFewFiles) {
244 FixedCompilationDatabaseWithFiles Compilations(".", {"a.cc", "b.cc", "c.cc"},
245 std::vector<std::string>());
246 AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
247 Executor.mapVirtualFile("a.cc", "void x() {}");
248 Executor.mapVirtualFile("b.cc", "void y() {}");
249 Executor.mapVirtualFile("c.cc", "void z() {}");
250
251 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
252 new ReportResultActionFactory(Executor.getExecutionContext())));
253 ASSERT_TRUE(!Err);
254 EXPECT_THAT(
255 Executor.getToolResults()->AllKVResults(),
256 ::testing::UnorderedElementsAre(Named("x"), Named("y"), Named("z")));
257}
258
259TEST(AllTUsToolTest, ManyFiles) {
260 unsigned NumFiles = 100;
261 std::vector<std::string> Files;
262 std::map<std::string, std::string> FileToContent;
263 std::vector<std::string> ExpectedSymbols;
264 for (unsigned i = 1; i <= NumFiles; ++i) {
265 std::string File = "f" + std::to_string(i) + ".cc";
266 std::string Symbol = "looong_function_name_" + std::to_string(i);
267 Files.push_back(File);
268 FileToContent[File] = "void " + Symbol + "() {}";
269 ExpectedSymbols.push_back(Symbol);
270 }
271 FixedCompilationDatabaseWithFiles Compilations(".", Files,
272 std::vector<std::string>());
273 AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
274 for (const auto &FileAndContent : FileToContent) {
275 Executor.mapVirtualFile(FileAndContent.first, FileAndContent.second);
276 }
277
278 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
279 new ReportResultActionFactory(Executor.getExecutionContext())));
280 ASSERT_TRUE(!Err);
281 std::vector<std::string> Results;
282 Executor.getToolResults()->forEachResult(
283 [&](StringRef Name, StringRef) { Results.push_back(Name); });
284 EXPECT_THAT(ExpectedSymbols, ::testing::UnorderedElementsAreArray(Results));
285}
286
Eric Liu826b7832017-10-26 10:38:14 +0000287} // end namespace tooling
288} // end namespace clang