blob: 785ec7c2bc67234e1ddd45a723087e448b4b8408 [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) {
Eric Liu2a27ebe2018-01-26 11:10:32 +000049 Context->reportResult(Decl->getNameAsString(),
50 Context->getRevision() + ":" + Context->getCorpus() +
51 ":" + Context->getCurrentCompilationUnit() +
52 "/1");
Eric Liu826b7832017-10-26 10:38:14 +000053 return ASTVisitor::TraverseFunctionDecl(Decl);
54 }
55
56private:
57 ExecutionContext *const Context;
58};
59
60class ReportResultAction : public ASTFrontendAction {
61public:
62 explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {
63 assert(Context != nullptr);
64 }
65
66protected:
67 std::unique_ptr<clang::ASTConsumer>
68 CreateASTConsumer(clang::CompilerInstance &compiler,
69 StringRef /* dummy */) override {
70 std::unique_ptr<clang::ASTConsumer> ast_consumer{
71 new ASTConsumerWithResult(Context)};
72 return ast_consumer;
73 }
74
75private:
76 ExecutionContext *const Context;
77};
78
79class ReportResultActionFactory : public FrontendActionFactory {
80public:
81 ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}
Roman Lebedev497fd982018-02-27 15:54:55 +000082 FrontendAction *create() override { return new ReportResultAction(Context); }
Eric Liu826b7832017-10-26 10:38:14 +000083
84private:
85 ExecutionContext *const Context;
86};
87
88} // namespace
89
90class TestToolExecutor : public ToolExecutor {
91public:
92 static const char *ExecutorName;
93
94 TestToolExecutor(CommonOptionsParser Options)
95 : OptionsParser(std::move(Options)) {}
96
97 StringRef getExecutorName() const override { return ExecutorName; }
98
Ilya Biryukovdbdd8e52018-08-24 09:03:29 +000099 bool isSingleProcess() const override { return true; }
100
Eric Liu826b7832017-10-26 10:38:14 +0000101 llvm::Error
102 execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,
103 ArgumentsAdjuster>>) override {
104 return llvm::Error::success();
105 }
106
107 ExecutionContext *getExecutionContext() override { return nullptr; };
108
109 ToolResults *getToolResults() override { return nullptr; }
110
111 llvm::ArrayRef<std::string> getSourcePaths() const {
112 return OptionsParser.getSourcePathList();
113 }
114
115 void mapVirtualFile(StringRef FilePath, StringRef Content) override {
116 VFS[FilePath] = Content;
117 }
118
119private:
120 CommonOptionsParser OptionsParser;
121 std::string SourcePaths;
122 std::map<std::string, std::string> VFS;
123};
124
125const char *TestToolExecutor::ExecutorName = "test-executor";
126
127class TestToolExecutorPlugin : public ToolExecutorPlugin {
128public:
129 llvm::Expected<std::unique_ptr<ToolExecutor>>
130 create(CommonOptionsParser &OptionsParser) override {
131 return llvm::make_unique<TestToolExecutor>(std::move(OptionsParser));
132 }
133};
134
Eric Liu826b7832017-10-26 10:38:14 +0000135static 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();
Eric Liu190afe92017-11-06 09:29:09 +0000143 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
144 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000145 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();
Eric Liu190afe92017-11-06 09:29:09 +0000158 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
159 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000160 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();
Eric Liu190afe92017-11-06 09:29:09 +0000168 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
169 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000170 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();
Eric Liu190afe92017-11-06 09:29:09 +0000179 auto Executor = internal::createExecutorFromCommandLineArgsImpl(
180 argc, &argv[0], TestCategory);
Eric Liu826b7832017-10-26 10:38:14 +0000181 ASSERT_TRUE((bool)Executor);
182 EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);
183}
184
185TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {
Eric Liu83454aa2017-10-26 13:09:50 +0000186 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000187 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000188 std::vector<std::string>(1, "a.cc"));
189 Executor.mapVirtualFile("a.cc", "int x = 0;");
Eric Liu826b7832017-10-26 10:38:14 +0000190
191 auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),
192 getClangSyntaxOnlyAdjuster());
193 ASSERT_TRUE(!Err);
194}
195
196TEST(StandaloneToolTest, SimpleAction) {
Eric Liu83454aa2017-10-26 13:09:50 +0000197 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000198 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000199 std::vector<std::string>(1, "a.cc"));
200 Executor.mapVirtualFile("a.cc", "int x = 0;");
Eric Liu826b7832017-10-26 10:38:14 +0000201
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) {
Eric Liu83454aa2017-10-26 13:09:50 +0000210 FixedCompilationDatabase Compilations(".", std::vector<std::string>());
Eric Liu826b7832017-10-26 10:38:14 +0000211 StandaloneToolExecutor Executor(Compilations,
Eric Liu83454aa2017-10-26 13:09:50 +0000212 std::vector<std::string>(1, "a.cc"));
213 Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}");
Eric Liu826b7832017-10-26 10:38:14 +0000214
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);
Eric Liu2a27ebe2018-01-26 11:10:32 +0000221 // Currently the standlone executor returns empty corpus, revision, and
222 // compilation unit.
223 EXPECT_EQ("::/1", KVs[0].second);
Eric Liu826b7832017-10-26 10:38:14 +0000224
225 Executor.getToolResults()->forEachResult(
Eric Liu2a27ebe2018-01-26 11:10:32 +0000226 [](StringRef, StringRef Value) { EXPECT_EQ("::/1", Value); });
Eric Liu826b7832017-10-26 10:38:14 +0000227}
228
Eric Liue25f3672018-01-05 10:32:16 +0000229class FixedCompilationDatabaseWithFiles : public CompilationDatabase {
230public:
231 FixedCompilationDatabaseWithFiles(Twine Directory,
232 ArrayRef<std::string> Files,
233 ArrayRef<std::string> CommandLine)
234 : FixedCompilations(Directory, CommandLine), Files(Files) {}
235
236 std::vector<CompileCommand>
237 getCompileCommands(StringRef FilePath) const override {
238 return FixedCompilations.getCompileCommands(FilePath);
239 }
240
241 std::vector<std::string> getAllFiles() const override { return Files; }
242
243private:
244 FixedCompilationDatabase FixedCompilations;
245 std::vector<std::string> Files;
246};
247
248MATCHER_P(Named, Name, "") { return arg.first == Name; }
249
250TEST(AllTUsToolTest, AFewFiles) {
Haojian Wucd5e59f2018-11-05 13:42:05 +0000251 FixedCompilationDatabaseWithFiles Compilations(
252 ".", {"a.cc", "b.cc", "c.cc", "ignore.cc"}, std::vector<std::string>());
Eric Liue25f3672018-01-05 10:32:16 +0000253 AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
Haojian Wucd5e59f2018-11-05 13:42:05 +0000254 Filter.setValue("[a-c].cc");
Eric Liue25f3672018-01-05 10:32:16 +0000255 Executor.mapVirtualFile("a.cc", "void x() {}");
256 Executor.mapVirtualFile("b.cc", "void y() {}");
257 Executor.mapVirtualFile("c.cc", "void z() {}");
Haojian Wucd5e59f2018-11-05 13:42:05 +0000258 Executor.mapVirtualFile("ignore.cc", "void d() {}");
Eric Liue25f3672018-01-05 10:32:16 +0000259
260 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
261 new ReportResultActionFactory(Executor.getExecutionContext())));
262 ASSERT_TRUE(!Err);
263 EXPECT_THAT(
264 Executor.getToolResults()->AllKVResults(),
265 ::testing::UnorderedElementsAre(Named("x"), Named("y"), Named("z")));
Haojian Wucd5e59f2018-11-05 13:42:05 +0000266 Filter.setValue(".*"); // reset to default value.
Eric Liue25f3672018-01-05 10:32:16 +0000267}
268
269TEST(AllTUsToolTest, ManyFiles) {
270 unsigned NumFiles = 100;
271 std::vector<std::string> Files;
272 std::map<std::string, std::string> FileToContent;
273 std::vector<std::string> ExpectedSymbols;
274 for (unsigned i = 1; i <= NumFiles; ++i) {
275 std::string File = "f" + std::to_string(i) + ".cc";
276 std::string Symbol = "looong_function_name_" + std::to_string(i);
277 Files.push_back(File);
278 FileToContent[File] = "void " + Symbol + "() {}";
279 ExpectedSymbols.push_back(Symbol);
280 }
281 FixedCompilationDatabaseWithFiles Compilations(".", Files,
282 std::vector<std::string>());
283 AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);
284 for (const auto &FileAndContent : FileToContent) {
285 Executor.mapVirtualFile(FileAndContent.first, FileAndContent.second);
286 }
287
288 auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(
289 new ReportResultActionFactory(Executor.getExecutionContext())));
290 ASSERT_TRUE(!Err);
291 std::vector<std::string> Results;
292 Executor.getToolResults()->forEachResult(
293 [&](StringRef Name, StringRef) { Results.push_back(Name); });
294 EXPECT_THAT(ExpectedSymbols, ::testing::UnorderedElementsAreArray(Results));
295}
296
Eric Liu826b7832017-10-26 10:38:14 +0000297} // end namespace tooling
298} // end namespace clang