blob: 4b14ebb2c300dcae6cb7a777e5b9c76cd473417c [file] [log] [blame]
Manuel Klimek47c245a2012-04-04 12:07:46 +00001//===- unittest/Tooling/ToolingTest.cpp - Tooling unit 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/DeclGroup.h"
Peter Collingbournec689ee72013-11-06 20:12:45 +000013#include "clang/Frontend/ASTUnit.h"
Richard Smith9219d1b2012-11-27 21:31:01 +000014#include "clang/Frontend/CompilerInstance.h"
Manuel Klimek47c245a2012-04-04 12:07:46 +000015#include "clang/Frontend/FrontendAction.h"
16#include "clang/Frontend/FrontendActions.h"
17#include "clang/Tooling/CompilationDatabase.h"
18#include "clang/Tooling/Tooling.h"
Peter Collingbournec689ee72013-11-06 20:12:45 +000019#include "llvm/ADT/STLExtras.h"
Alp Toker1d257e12014-06-04 03:28:55 +000020#include "llvm/Config/llvm-config.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000021#include "gtest/gtest.h"
Alexander Kornienko74e1c462014-12-03 17:53:02 +000022#include <algorithm>
Alexander Kornienko55f2ca92012-06-01 14:50:43 +000023#include <string>
Manuel Klimek47c245a2012-04-04 12:07:46 +000024
25namespace clang {
26namespace tooling {
27
28namespace {
29/// Takes an ast consumer and returns it from CreateASTConsumer. This only
30/// works with single translation unit compilations.
31class TestAction : public clang::ASTFrontendAction {
David Blaikie6beb6aa2014-08-10 19:56:51 +000032public:
Manuel Klimek47c245a2012-04-04 12:07:46 +000033 /// Takes ownership of TestConsumer.
David Blaikie6beb6aa2014-08-10 19:56:51 +000034 explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer)
35 : TestConsumer(std::move(TestConsumer)) {}
Manuel Klimek47c245a2012-04-04 12:07:46 +000036
David Blaikie6beb6aa2014-08-10 19:56:51 +000037protected:
Alexander Kornienko34eb2072015-04-11 02:00:23 +000038 std::unique_ptr<clang::ASTConsumer>
39 CreateASTConsumer(clang::CompilerInstance &compiler,
40 StringRef dummy) override {
Manuel Klimek47c245a2012-04-04 12:07:46 +000041 /// TestConsumer will be deleted by the framework calling us.
David Blaikie6beb6aa2014-08-10 19:56:51 +000042 return std::move(TestConsumer);
Manuel Klimek47c245a2012-04-04 12:07:46 +000043 }
44
David Blaikie6beb6aa2014-08-10 19:56:51 +000045private:
46 std::unique_ptr<clang::ASTConsumer> TestConsumer;
Manuel Klimek47c245a2012-04-04 12:07:46 +000047};
48
49class FindTopLevelDeclConsumer : public clang::ASTConsumer {
50 public:
51 explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
52 : FoundTopLevelDecl(FoundTopLevelDecl) {}
Alexander Kornienko34eb2072015-04-11 02:00:23 +000053 bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
Manuel Klimek47c245a2012-04-04 12:07:46 +000054 *FoundTopLevelDecl = true;
55 return true;
56 }
57 private:
58 bool * const FoundTopLevelDecl;
59};
60} // end namespace
61
Meador Inge5d3fb222012-06-16 03:34:49 +000062TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
Manuel Klimek47c245a2012-04-04 12:07:46 +000063 bool FoundTopLevelDecl = false;
David Blaikie6beb6aa2014-08-10 19:56:51 +000064 EXPECT_TRUE(
65 runToolOnCode(new TestAction(llvm::make_unique<FindTopLevelDeclConsumer>(
66 &FoundTopLevelDecl)),
67 ""));
Meador Inge5d3fb222012-06-16 03:34:49 +000068 EXPECT_FALSE(FoundTopLevelDecl);
Manuel Klimek47c245a2012-04-04 12:07:46 +000069}
70
71namespace {
72class FindClassDeclXConsumer : public clang::ASTConsumer {
73 public:
74 FindClassDeclXConsumer(bool *FoundClassDeclX)
75 : FoundClassDeclX(FoundClassDeclX) {}
Alexander Kornienko34eb2072015-04-11 02:00:23 +000076 bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
Manuel Klimek47c245a2012-04-04 12:07:46 +000077 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
78 *GroupRef.begin())) {
79 if (Record->getName() == "X") {
80 *FoundClassDeclX = true;
81 }
82 }
83 return true;
84 }
85 private:
86 bool *FoundClassDeclX;
87};
Peter Collingbournec689ee72013-11-06 20:12:45 +000088bool FindClassDeclX(ASTUnit *AST) {
89 for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
90 e = AST->top_level_end();
91 i != e; ++i) {
92 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
93 if (Record->getName() == "X") {
94 return true;
95 }
96 }
97 }
98 return false;
99}
Manuel Klimek47c245a2012-04-04 12:07:46 +0000100} // end namespace
101
102TEST(runToolOnCode, FindsClassDecl) {
103 bool FoundClassDeclX = false;
David Blaikie6beb6aa2014-08-10 19:56:51 +0000104 EXPECT_TRUE(
105 runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
106 &FoundClassDeclX)),
107 "class X;"));
Manuel Klimek47c245a2012-04-04 12:07:46 +0000108 EXPECT_TRUE(FoundClassDeclX);
109
110 FoundClassDeclX = false;
David Blaikie6beb6aa2014-08-10 19:56:51 +0000111 EXPECT_TRUE(
112 runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
113 &FoundClassDeclX)),
114 "class Y;"));
Manuel Klimek47c245a2012-04-04 12:07:46 +0000115 EXPECT_FALSE(FoundClassDeclX);
116}
117
Peter Collingbournec689ee72013-11-06 20:12:45 +0000118TEST(buildASTFromCode, FindsClassDecl) {
David Blaikie103a2de2014-04-25 17:01:33 +0000119 std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000120 ASSERT_TRUE(AST.get());
121 EXPECT_TRUE(FindClassDeclX(AST.get()));
122
David Blaikie103a2de2014-04-25 17:01:33 +0000123 AST = buildASTFromCode("class Y;");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000124 ASSERT_TRUE(AST.get());
125 EXPECT_FALSE(FindClassDeclX(AST.get()));
126}
127
Manuel Klimek47c245a2012-04-04 12:07:46 +0000128TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000129 std::unique_ptr<FrontendActionFactory> Factory(
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000130 newFrontendActionFactory<SyntaxOnlyAction>());
Ahmed Charlesb8984322014-03-07 20:03:18 +0000131 std::unique_ptr<FrontendAction> Action(Factory->create());
Craig Topper416fa342014-06-08 08:38:12 +0000132 EXPECT_TRUE(Action.get() != nullptr);
Manuel Klimek47c245a2012-04-04 12:07:46 +0000133}
134
135struct IndependentFrontendActionCreator {
David Blaikie6beb6aa2014-08-10 19:56:51 +0000136 std::unique_ptr<ASTConsumer> newASTConsumer() {
137 return llvm::make_unique<FindTopLevelDeclConsumer>(nullptr);
Manuel Klimek5da9dcb2012-07-05 18:13:01 +0000138 }
Manuel Klimek47c245a2012-04-04 12:07:46 +0000139};
140
141TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
142 IndependentFrontendActionCreator Creator;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000143 std::unique_ptr<FrontendActionFactory> Factory(
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000144 newFrontendActionFactory(&Creator));
Ahmed Charlesb8984322014-03-07 20:03:18 +0000145 std::unique_ptr<FrontendAction> Action(Factory->create());
Craig Topper416fa342014-06-08 08:38:12 +0000146 EXPECT_TRUE(Action.get() != nullptr);
Manuel Klimek47c245a2012-04-04 12:07:46 +0000147}
148
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000149TEST(ToolInvocation, TestMapVirtualFile) {
Peter Collingbournec689ee72013-11-06 20:12:45 +0000150 IntrusiveRefCntPtr<clang::FileManager> Files(
151 new clang::FileManager(clang::FileSystemOptions()));
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000152 std::vector<std::string> Args;
153 Args.push_back("tool-executable");
154 Args.push_back("-Idef");
155 Args.push_back("-fsyntax-only");
156 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000157 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
Alp Tokerf994cef2014-07-05 03:08:06 +0000158 Files.get());
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000159 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
160 Invocation.mapVirtualFile("def/abc", "\n");
161 EXPECT_TRUE(Invocation.run());
162}
163
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000164TEST(ToolInvocation, TestVirtualModulesCompilation) {
165 // FIXME: Currently, this only tests that we don't exit with an error if a
166 // mapped module.map is found on the include path. In the future, expand this
167 // test to run a full modules enabled compilation, so we make sure we can
168 // rerun modules compilations with a virtual file system.
Peter Collingbournec689ee72013-11-06 20:12:45 +0000169 IntrusiveRefCntPtr<clang::FileManager> Files(
170 new clang::FileManager(clang::FileSystemOptions()));
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000171 std::vector<std::string> Args;
172 Args.push_back("tool-executable");
173 Args.push_back("-Idef");
174 Args.push_back("-fsyntax-only");
175 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000176 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
Alp Tokerf994cef2014-07-05 03:08:06 +0000177 Files.get());
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000178 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
179 Invocation.mapVirtualFile("def/abc", "\n");
180 // Add a module.map file in the include directory of our header, so we trigger
181 // the module.map header search logic.
182 Invocation.mapVirtualFile("def/module.map", "\n");
183 EXPECT_TRUE(Invocation.run());
184}
185
Edwin Vane20c6f542013-05-29 16:01:10 +0000186struct VerifyEndCallback : public SourceFileCallbacks {
187 VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000188 bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override {
Edwin Vane20c6f542013-05-29 16:01:10 +0000189 ++BeginCalled;
190 return true;
191 }
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000192 void handleEndSource() override { ++EndCalled; }
David Blaikie6beb6aa2014-08-10 19:56:51 +0000193 std::unique_ptr<ASTConsumer> newASTConsumer() {
194 return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched);
Manuel Klimek8246d872012-10-25 08:49:11 +0000195 }
Edwin Vane20c6f542013-05-29 16:01:10 +0000196 unsigned BeginCalled;
197 unsigned EndCalled;
Manuel Klimek8246d872012-10-25 08:49:11 +0000198 bool Matched;
199};
200
Hans Wennborg501eadb2014-03-12 16:07:46 +0000201#if !defined(LLVM_ON_WIN32)
Edwin Vane20c6f542013-05-29 16:01:10 +0000202TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
Manuel Klimek8246d872012-10-25 08:49:11 +0000203 VerifyEndCallback EndCallback;
204
205 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
206 std::vector<std::string> Sources;
207 Sources.push_back("/a.cc");
208 Sources.push_back("/b.cc");
209 ClangTool Tool(Compilations, Sources);
210
211 Tool.mapVirtualFile("/a.cc", "void a() {}");
212 Tool.mapVirtualFile("/b.cc", "void b() {}");
213
Nico Weber52fbbb12014-04-24 03:48:09 +0000214 std::unique_ptr<FrontendActionFactory> Action(
215 newFrontendActionFactory(&EndCallback, &EndCallback));
216 Tool.run(Action.get());
Manuel Klimek8246d872012-10-25 08:49:11 +0000217
218 EXPECT_TRUE(EndCallback.Matched);
Edwin Vane20c6f542013-05-29 16:01:10 +0000219 EXPECT_EQ(2u, EndCallback.BeginCalled);
220 EXPECT_EQ(2u, EndCallback.EndCalled);
Manuel Klimek8246d872012-10-25 08:49:11 +0000221}
NAKAMURA Takumi95fd41a2012-10-25 09:38:41 +0000222#endif
Manuel Klimek8246d872012-10-25 08:49:11 +0000223
Richard Smith9219d1b2012-11-27 21:31:01 +0000224struct SkipBodyConsumer : public clang::ASTConsumer {
225 /// Skip the 'skipMe' function.
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000226 bool shouldSkipFunctionBody(Decl *D) override {
Richard Smith9219d1b2012-11-27 21:31:01 +0000227 FunctionDecl *F = dyn_cast<FunctionDecl>(D);
228 return F && F->getNameAsString() == "skipMe";
229 }
230};
231
232struct SkipBodyAction : public clang::ASTFrontendAction {
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000233 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
234 StringRef) override {
Richard Smith9219d1b2012-11-27 21:31:01 +0000235 Compiler.getFrontendOpts().SkipFunctionBodies = true;
David Blaikie6beb6aa2014-08-10 19:56:51 +0000236 return llvm::make_unique<SkipBodyConsumer>();
Richard Smith9219d1b2012-11-27 21:31:01 +0000237 }
238};
239
Hal Finkel1d3e3d72013-01-28 04:37:38 +0000240TEST(runToolOnCode, TestSkipFunctionBody) {
Richard Smith9219d1b2012-11-27 21:31:01 +0000241 EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
242 "int skipMe() { an_error_here }"));
243 EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
244 "int skipMeNot() { an_error_here }"));
245}
246
Peter Collingbournec0423b32014-03-02 23:37:26 +0000247TEST(runToolOnCodeWithArgs, TestNoDepFile) {
248 llvm::SmallString<32> DepFilePath;
249 ASSERT_FALSE(
250 llvm::sys::fs::createTemporaryFile("depfile", "d", DepFilePath));
Peter Collingbournef9372542014-03-03 08:13:06 +0000251 std::vector<std::string> Args;
252 Args.push_back("-MMD");
253 Args.push_back("-MT");
254 Args.push_back(DepFilePath.str());
255 Args.push_back("-MF");
256 Args.push_back(DepFilePath.str());
Peter Collingbourne2bbb0292014-03-03 07:49:35 +0000257 EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args));
Peter Collingbournec0423b32014-03-02 23:37:26 +0000258 EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
259 EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
260}
261
Manuel Klimekd91ac932013-06-04 14:44:44 +0000262TEST(ClangToolTest, ArgumentAdjusters) {
263 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
264
265 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
266 Tool.mapVirtualFile("/a.cc", "void a() {}");
267
Nico Weber52fbbb12014-04-24 03:48:09 +0000268 std::unique_ptr<FrontendActionFactory> Action(
269 newFrontendActionFactory<SyntaxOnlyAction>());
270
Manuel Klimekd91ac932013-06-04 14:44:44 +0000271 bool Found = false;
272 bool Ran = false;
Alexander Kornienko74e1c462014-12-03 17:53:02 +0000273 ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
274 [&Found, &Ran](const CommandLineArguments &Args) {
275 Ran = true;
276 if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end())
277 Found = true;
278 return Args;
279 };
280 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
Nico Weber52fbbb12014-04-24 03:48:09 +0000281 Tool.run(Action.get());
Manuel Klimekd91ac932013-06-04 14:44:44 +0000282 EXPECT_TRUE(Ran);
283 EXPECT_TRUE(Found);
284
285 Ran = Found = false;
286 Tool.clearArgumentsAdjusters();
Alexander Kornienko74e1c462014-12-03 17:53:02 +0000287 Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
288 Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
Nico Weber52fbbb12014-04-24 03:48:09 +0000289 Tool.run(Action.get());
Manuel Klimekd91ac932013-06-04 14:44:44 +0000290 EXPECT_TRUE(Ran);
291 EXPECT_FALSE(Found);
292}
293
Hans Wennborg501eadb2014-03-12 16:07:46 +0000294#ifndef LLVM_ON_WIN32
Peter Collingbournec689ee72013-11-06 20:12:45 +0000295TEST(ClangToolTest, BuildASTs) {
296 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
297
298 std::vector<std::string> Sources;
299 Sources.push_back("/a.cc");
300 Sources.push_back("/b.cc");
301 ClangTool Tool(Compilations, Sources);
302
303 Tool.mapVirtualFile("/a.cc", "void a() {}");
304 Tool.mapVirtualFile("/b.cc", "void b() {}");
305
David Blaikie39808ff2014-04-25 14:49:37 +0000306 std::vector<std::unique_ptr<ASTUnit>> ASTs;
Peter Collingbournec689ee72013-11-06 20:12:45 +0000307 EXPECT_EQ(0, Tool.buildASTs(ASTs));
308 EXPECT_EQ(2u, ASTs.size());
Peter Collingbournec689ee72013-11-06 20:12:45 +0000309}
310
Manuel Klimek64083012013-11-07 23:18:05 +0000311struct TestDiagnosticConsumer : public DiagnosticConsumer {
312 TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000313 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
314 const Diagnostic &Info) override {
Manuel Klimek64083012013-11-07 23:18:05 +0000315 ++NumDiagnosticsSeen;
316 }
317 unsigned NumDiagnosticsSeen;
318};
319
320TEST(ClangToolTest, InjectDiagnosticConsumer) {
321 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
322 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
323 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
324 TestDiagnosticConsumer Consumer;
325 Tool.setDiagnosticConsumer(&Consumer);
Nico Weber52fbbb12014-04-24 03:48:09 +0000326 std::unique_ptr<FrontendActionFactory> Action(
327 newFrontendActionFactory<SyntaxOnlyAction>());
328 Tool.run(Action.get());
Manuel Klimek64083012013-11-07 23:18:05 +0000329 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
330}
331
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000332TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
333 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
334 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
335 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
336 TestDiagnosticConsumer Consumer;
337 Tool.setDiagnosticConsumer(&Consumer);
David Blaikie39808ff2014-04-25 14:49:37 +0000338 std::vector<std::unique_ptr<ASTUnit>> ASTs;
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000339 Tool.buildASTs(ASTs);
340 EXPECT_EQ(1u, ASTs.size());
341 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
342}
NAKAMURA Takumid3b07c62013-11-13 00:18:50 +0000343#endif
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000344
Manuel Klimek47c245a2012-04-04 12:07:46 +0000345} // end namespace tooling
346} // end namespace clang