blob: 9aede044f6954fe931461ab896aa4b57df2b5200 [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 Kornienko55f2ca92012-06-01 14:50:43 +000022#include <string>
Manuel Klimek47c245a2012-04-04 12:07:46 +000023
24namespace clang {
25namespace tooling {
26
27namespace {
28/// Takes an ast consumer and returns it from CreateASTConsumer. This only
29/// works with single translation unit compilations.
30class TestAction : public clang::ASTFrontendAction {
David Blaikie62a56f32014-07-17 22:34:12 +000031 public:
Manuel Klimek47c245a2012-04-04 12:07:46 +000032 /// Takes ownership of TestConsumer.
David Blaikie62a56f32014-07-17 22:34:12 +000033 explicit TestAction(clang::ASTConsumer *TestConsumer)
34 : TestConsumer(TestConsumer) {}
Manuel Klimek47c245a2012-04-04 12:07:46 +000035
David Blaikie62a56f32014-07-17 22:34:12 +000036 protected:
37 virtual clang::ASTConsumer* CreateASTConsumer(
38 clang::CompilerInstance& compiler, StringRef dummy) {
Manuel Klimek47c245a2012-04-04 12:07:46 +000039 /// TestConsumer will be deleted by the framework calling us.
David Blaikie62a56f32014-07-17 22:34:12 +000040 return TestConsumer;
Manuel Klimek47c245a2012-04-04 12:07:46 +000041 }
42
David Blaikie62a56f32014-07-17 22:34:12 +000043 private:
44 clang::ASTConsumer * const TestConsumer;
Manuel Klimek47c245a2012-04-04 12:07:46 +000045};
46
47class FindTopLevelDeclConsumer : public clang::ASTConsumer {
48 public:
49 explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
50 : FoundTopLevelDecl(FoundTopLevelDecl) {}
51 virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
52 *FoundTopLevelDecl = true;
53 return true;
54 }
55 private:
56 bool * const FoundTopLevelDecl;
57};
58} // end namespace
59
Meador Inge5d3fb222012-06-16 03:34:49 +000060TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
Manuel Klimek47c245a2012-04-04 12:07:46 +000061 bool FoundTopLevelDecl = false;
David Blaikie62a56f32014-07-17 22:34:12 +000062 EXPECT_TRUE(runToolOnCode(
63 new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
Meador Inge5d3fb222012-06-16 03:34:49 +000064 EXPECT_FALSE(FoundTopLevelDecl);
Manuel Klimek47c245a2012-04-04 12:07:46 +000065}
66
67namespace {
68class FindClassDeclXConsumer : public clang::ASTConsumer {
69 public:
70 FindClassDeclXConsumer(bool *FoundClassDeclX)
71 : FoundClassDeclX(FoundClassDeclX) {}
72 virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
73 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
74 *GroupRef.begin())) {
75 if (Record->getName() == "X") {
76 *FoundClassDeclX = true;
77 }
78 }
79 return true;
80 }
81 private:
82 bool *FoundClassDeclX;
83};
Peter Collingbournec689ee72013-11-06 20:12:45 +000084bool FindClassDeclX(ASTUnit *AST) {
85 for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
86 e = AST->top_level_end();
87 i != e; ++i) {
88 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
89 if (Record->getName() == "X") {
90 return true;
91 }
92 }
93 }
94 return false;
95}
Manuel Klimek47c245a2012-04-04 12:07:46 +000096} // end namespace
97
98TEST(runToolOnCode, FindsClassDecl) {
99 bool FoundClassDeclX = false;
David Blaikie62a56f32014-07-17 22:34:12 +0000100 EXPECT_TRUE(runToolOnCode(new TestAction(
101 new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
Manuel Klimek47c245a2012-04-04 12:07:46 +0000102 EXPECT_TRUE(FoundClassDeclX);
103
104 FoundClassDeclX = false;
David Blaikie62a56f32014-07-17 22:34:12 +0000105 EXPECT_TRUE(runToolOnCode(new TestAction(
106 new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
Manuel Klimek47c245a2012-04-04 12:07:46 +0000107 EXPECT_FALSE(FoundClassDeclX);
108}
109
Peter Collingbournec689ee72013-11-06 20:12:45 +0000110TEST(buildASTFromCode, FindsClassDecl) {
David Blaikie103a2de2014-04-25 17:01:33 +0000111 std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000112 ASSERT_TRUE(AST.get());
113 EXPECT_TRUE(FindClassDeclX(AST.get()));
114
David Blaikie103a2de2014-04-25 17:01:33 +0000115 AST = buildASTFromCode("class Y;");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000116 ASSERT_TRUE(AST.get());
117 EXPECT_FALSE(FindClassDeclX(AST.get()));
118}
119
Manuel Klimek47c245a2012-04-04 12:07:46 +0000120TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000121 std::unique_ptr<FrontendActionFactory> Factory(
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000122 newFrontendActionFactory<SyntaxOnlyAction>());
Ahmed Charlesb8984322014-03-07 20:03:18 +0000123 std::unique_ptr<FrontendAction> Action(Factory->create());
Craig Topper416fa342014-06-08 08:38:12 +0000124 EXPECT_TRUE(Action.get() != nullptr);
Manuel Klimek47c245a2012-04-04 12:07:46 +0000125}
126
127struct IndependentFrontendActionCreator {
David Blaikie62a56f32014-07-17 22:34:12 +0000128 ASTConsumer *newASTConsumer() {
129 return new FindTopLevelDeclConsumer(nullptr);
Manuel Klimek5da9dcb2012-07-05 18:13:01 +0000130 }
Manuel Klimek47c245a2012-04-04 12:07:46 +0000131};
132
133TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
134 IndependentFrontendActionCreator Creator;
Ahmed Charlesb8984322014-03-07 20:03:18 +0000135 std::unique_ptr<FrontendActionFactory> Factory(
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000136 newFrontendActionFactory(&Creator));
Ahmed Charlesb8984322014-03-07 20:03:18 +0000137 std::unique_ptr<FrontendAction> Action(Factory->create());
Craig Topper416fa342014-06-08 08:38:12 +0000138 EXPECT_TRUE(Action.get() != nullptr);
Manuel Klimek47c245a2012-04-04 12:07:46 +0000139}
140
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000141TEST(ToolInvocation, TestMapVirtualFile) {
Peter Collingbournec689ee72013-11-06 20:12:45 +0000142 IntrusiveRefCntPtr<clang::FileManager> Files(
143 new clang::FileManager(clang::FileSystemOptions()));
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000144 std::vector<std::string> Args;
145 Args.push_back("tool-executable");
146 Args.push_back("-Idef");
147 Args.push_back("-fsyntax-only");
148 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000149 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
Alp Tokerf994cef2014-07-05 03:08:06 +0000150 Files.get());
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000151 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
152 Invocation.mapVirtualFile("def/abc", "\n");
153 EXPECT_TRUE(Invocation.run());
154}
155
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000156TEST(ToolInvocation, TestVirtualModulesCompilation) {
157 // FIXME: Currently, this only tests that we don't exit with an error if a
158 // mapped module.map is found on the include path. In the future, expand this
159 // test to run a full modules enabled compilation, so we make sure we can
160 // rerun modules compilations with a virtual file system.
Peter Collingbournec689ee72013-11-06 20:12:45 +0000161 IntrusiveRefCntPtr<clang::FileManager> Files(
162 new clang::FileManager(clang::FileSystemOptions()));
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000163 std::vector<std::string> Args;
164 Args.push_back("tool-executable");
165 Args.push_back("-Idef");
166 Args.push_back("-fsyntax-only");
167 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000168 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
Alp Tokerf994cef2014-07-05 03:08:06 +0000169 Files.get());
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000170 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
171 Invocation.mapVirtualFile("def/abc", "\n");
172 // Add a module.map file in the include directory of our header, so we trigger
173 // the module.map header search logic.
174 Invocation.mapVirtualFile("def/module.map", "\n");
175 EXPECT_TRUE(Invocation.run());
176}
177
Edwin Vane20c6f542013-05-29 16:01:10 +0000178struct VerifyEndCallback : public SourceFileCallbacks {
179 VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
Edwin Vane3a331f32013-05-30 13:59:44 +0000180 virtual bool handleBeginSource(CompilerInstance &CI,
Craig Toppera798a9d2014-03-02 09:32:10 +0000181 StringRef Filename) override {
Edwin Vane20c6f542013-05-29 16:01:10 +0000182 ++BeginCalled;
183 return true;
184 }
Edwin Vane3a331f32013-05-30 13:59:44 +0000185 virtual void handleEndSource() {
Edwin Vane20c6f542013-05-29 16:01:10 +0000186 ++EndCalled;
Manuel Klimek8246d872012-10-25 08:49:11 +0000187 }
David Blaikie62a56f32014-07-17 22:34:12 +0000188 ASTConsumer *newASTConsumer() {
189 return new FindTopLevelDeclConsumer(&Matched);
Manuel Klimek8246d872012-10-25 08:49:11 +0000190 }
Edwin Vane20c6f542013-05-29 16:01:10 +0000191 unsigned BeginCalled;
192 unsigned EndCalled;
Manuel Klimek8246d872012-10-25 08:49:11 +0000193 bool Matched;
194};
195
Hans Wennborg501eadb2014-03-12 16:07:46 +0000196#if !defined(LLVM_ON_WIN32)
Edwin Vane20c6f542013-05-29 16:01:10 +0000197TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
Manuel Klimek8246d872012-10-25 08:49:11 +0000198 VerifyEndCallback EndCallback;
199
200 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
201 std::vector<std::string> Sources;
202 Sources.push_back("/a.cc");
203 Sources.push_back("/b.cc");
204 ClangTool Tool(Compilations, Sources);
205
206 Tool.mapVirtualFile("/a.cc", "void a() {}");
207 Tool.mapVirtualFile("/b.cc", "void b() {}");
208
Nico Weber52fbbb12014-04-24 03:48:09 +0000209 std::unique_ptr<FrontendActionFactory> Action(
210 newFrontendActionFactory(&EndCallback, &EndCallback));
211 Tool.run(Action.get());
Manuel Klimek8246d872012-10-25 08:49:11 +0000212
213 EXPECT_TRUE(EndCallback.Matched);
Edwin Vane20c6f542013-05-29 16:01:10 +0000214 EXPECT_EQ(2u, EndCallback.BeginCalled);
215 EXPECT_EQ(2u, EndCallback.EndCalled);
Manuel Klimek8246d872012-10-25 08:49:11 +0000216}
NAKAMURA Takumi95fd41a2012-10-25 09:38:41 +0000217#endif
Manuel Klimek8246d872012-10-25 08:49:11 +0000218
Richard Smith9219d1b2012-11-27 21:31:01 +0000219struct SkipBodyConsumer : public clang::ASTConsumer {
220 /// Skip the 'skipMe' function.
221 virtual bool shouldSkipFunctionBody(Decl *D) {
222 FunctionDecl *F = dyn_cast<FunctionDecl>(D);
223 return F && F->getNameAsString() == "skipMe";
224 }
225};
226
227struct SkipBodyAction : public clang::ASTFrontendAction {
David Blaikie62a56f32014-07-17 22:34:12 +0000228 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
229 StringRef) {
Richard Smith9219d1b2012-11-27 21:31:01 +0000230 Compiler.getFrontendOpts().SkipFunctionBodies = true;
David Blaikie62a56f32014-07-17 22:34:12 +0000231 return new SkipBodyConsumer;
Richard Smith9219d1b2012-11-27 21:31:01 +0000232 }
233};
234
Hal Finkel1d3e3d72013-01-28 04:37:38 +0000235TEST(runToolOnCode, TestSkipFunctionBody) {
Richard Smith9219d1b2012-11-27 21:31:01 +0000236 EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
237 "int skipMe() { an_error_here }"));
238 EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
239 "int skipMeNot() { an_error_here }"));
240}
241
Peter Collingbournec0423b32014-03-02 23:37:26 +0000242TEST(runToolOnCodeWithArgs, TestNoDepFile) {
243 llvm::SmallString<32> DepFilePath;
244 ASSERT_FALSE(
245 llvm::sys::fs::createTemporaryFile("depfile", "d", DepFilePath));
Peter Collingbournef9372542014-03-03 08:13:06 +0000246 std::vector<std::string> Args;
247 Args.push_back("-MMD");
248 Args.push_back("-MT");
249 Args.push_back(DepFilePath.str());
250 Args.push_back("-MF");
251 Args.push_back(DepFilePath.str());
Peter Collingbourne2bbb0292014-03-03 07:49:35 +0000252 EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args));
Peter Collingbournec0423b32014-03-02 23:37:26 +0000253 EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
254 EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
255}
256
Manuel Klimekd91ac932013-06-04 14:44:44 +0000257struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
258 bool &Found;
259 bool &Ran;
260
261 CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
262
263 virtual CommandLineArguments
Craig Toppera798a9d2014-03-02 09:32:10 +0000264 Adjust(const CommandLineArguments &Args) override {
Manuel Klimekd91ac932013-06-04 14:44:44 +0000265 Ran = true;
266 for (unsigned I = 0, E = Args.size(); I != E; ++I) {
267 if (Args[I] == "-fsyntax-only") {
268 Found = true;
269 break;
270 }
271 }
272 return Args;
273 }
274};
275
276TEST(ClangToolTest, ArgumentAdjusters) {
277 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
278
279 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
280 Tool.mapVirtualFile("/a.cc", "void a() {}");
281
Nico Weber52fbbb12014-04-24 03:48:09 +0000282 std::unique_ptr<FrontendActionFactory> Action(
283 newFrontendActionFactory<SyntaxOnlyAction>());
284
Manuel Klimekd91ac932013-06-04 14:44:44 +0000285 bool Found = false;
286 bool Ran = false;
287 Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
Nico Weber52fbbb12014-04-24 03:48:09 +0000288 Tool.run(Action.get());
Manuel Klimekd91ac932013-06-04 14:44:44 +0000289 EXPECT_TRUE(Ran);
290 EXPECT_TRUE(Found);
291
292 Ran = Found = false;
293 Tool.clearArgumentsAdjusters();
294 Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
295 Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
Nico Weber52fbbb12014-04-24 03:48:09 +0000296 Tool.run(Action.get());
Manuel Klimekd91ac932013-06-04 14:44:44 +0000297 EXPECT_TRUE(Ran);
298 EXPECT_FALSE(Found);
299}
300
Hans Wennborg501eadb2014-03-12 16:07:46 +0000301#ifndef LLVM_ON_WIN32
Peter Collingbournec689ee72013-11-06 20:12:45 +0000302TEST(ClangToolTest, BuildASTs) {
303 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
304
305 std::vector<std::string> Sources;
306 Sources.push_back("/a.cc");
307 Sources.push_back("/b.cc");
308 ClangTool Tool(Compilations, Sources);
309
310 Tool.mapVirtualFile("/a.cc", "void a() {}");
311 Tool.mapVirtualFile("/b.cc", "void b() {}");
312
David Blaikie39808ff2014-04-25 14:49:37 +0000313 std::vector<std::unique_ptr<ASTUnit>> ASTs;
Peter Collingbournec689ee72013-11-06 20:12:45 +0000314 EXPECT_EQ(0, Tool.buildASTs(ASTs));
315 EXPECT_EQ(2u, ASTs.size());
Peter Collingbournec689ee72013-11-06 20:12:45 +0000316}
317
Manuel Klimek64083012013-11-07 23:18:05 +0000318struct TestDiagnosticConsumer : public DiagnosticConsumer {
319 TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
320 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
321 const Diagnostic &Info) {
322 ++NumDiagnosticsSeen;
323 }
324 unsigned NumDiagnosticsSeen;
325};
326
327TEST(ClangToolTest, InjectDiagnosticConsumer) {
328 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
329 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
330 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
331 TestDiagnosticConsumer Consumer;
332 Tool.setDiagnosticConsumer(&Consumer);
Nico Weber52fbbb12014-04-24 03:48:09 +0000333 std::unique_ptr<FrontendActionFactory> Action(
334 newFrontendActionFactory<SyntaxOnlyAction>());
335 Tool.run(Action.get());
Manuel Klimek64083012013-11-07 23:18:05 +0000336 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
337}
338
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000339TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
340 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
341 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
342 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
343 TestDiagnosticConsumer Consumer;
344 Tool.setDiagnosticConsumer(&Consumer);
David Blaikie39808ff2014-04-25 14:49:37 +0000345 std::vector<std::unique_ptr<ASTUnit>> ASTs;
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000346 Tool.buildASTs(ASTs);
347 EXPECT_EQ(1u, ASTs.size());
348 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
349}
NAKAMURA Takumid3b07c62013-11-13 00:18:50 +0000350#endif
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000351
Manuel Klimek47c245a2012-04-04 12:07:46 +0000352} // end namespace tooling
353} // end namespace clang