blob: 302616b8426ab86edce3ee5947aa13d8946734f0 [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"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000020#include "gtest/gtest.h"
Alexander Kornienko55f2ca92012-06-01 14:50:43 +000021#include <string>
Manuel Klimek47c245a2012-04-04 12:07:46 +000022
23namespace clang {
24namespace tooling {
25
26namespace {
27/// Takes an ast consumer and returns it from CreateASTConsumer. This only
28/// works with single translation unit compilations.
29class TestAction : public clang::ASTFrontendAction {
30 public:
31 /// Takes ownership of TestConsumer.
32 explicit TestAction(clang::ASTConsumer *TestConsumer)
33 : TestConsumer(TestConsumer) {}
34
35 protected:
36 virtual clang::ASTConsumer* CreateASTConsumer(
37 clang::CompilerInstance& compiler, StringRef dummy) {
38 /// TestConsumer will be deleted by the framework calling us.
39 return TestConsumer;
40 }
41
42 private:
43 clang::ASTConsumer * const TestConsumer;
44};
45
46class FindTopLevelDeclConsumer : public clang::ASTConsumer {
47 public:
48 explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
49 : FoundTopLevelDecl(FoundTopLevelDecl) {}
50 virtual bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
51 *FoundTopLevelDecl = true;
52 return true;
53 }
54 private:
55 bool * const FoundTopLevelDecl;
56};
57} // end namespace
58
Meador Inge5d3fb222012-06-16 03:34:49 +000059TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
Manuel Klimek47c245a2012-04-04 12:07:46 +000060 bool FoundTopLevelDecl = false;
61 EXPECT_TRUE(runToolOnCode(
62 new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
Meador Inge5d3fb222012-06-16 03:34:49 +000063 EXPECT_FALSE(FoundTopLevelDecl);
Manuel Klimek47c245a2012-04-04 12:07:46 +000064}
65
66namespace {
67class FindClassDeclXConsumer : public clang::ASTConsumer {
68 public:
69 FindClassDeclXConsumer(bool *FoundClassDeclX)
70 : FoundClassDeclX(FoundClassDeclX) {}
71 virtual bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
72 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
73 *GroupRef.begin())) {
74 if (Record->getName() == "X") {
75 *FoundClassDeclX = true;
76 }
77 }
78 return true;
79 }
80 private:
81 bool *FoundClassDeclX;
82};
Peter Collingbournec689ee72013-11-06 20:12:45 +000083bool FindClassDeclX(ASTUnit *AST) {
84 for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
85 e = AST->top_level_end();
86 i != e; ++i) {
87 if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
88 if (Record->getName() == "X") {
89 return true;
90 }
91 }
92 }
93 return false;
94}
Manuel Klimek47c245a2012-04-04 12:07:46 +000095} // end namespace
96
97TEST(runToolOnCode, FindsClassDecl) {
98 bool FoundClassDeclX = false;
99 EXPECT_TRUE(runToolOnCode(new TestAction(
100 new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
101 EXPECT_TRUE(FoundClassDeclX);
102
103 FoundClassDeclX = false;
104 EXPECT_TRUE(runToolOnCode(new TestAction(
105 new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
106 EXPECT_FALSE(FoundClassDeclX);
107}
108
Peter Collingbournec689ee72013-11-06 20:12:45 +0000109TEST(buildASTFromCode, FindsClassDecl) {
110 OwningPtr<ASTUnit> AST(buildASTFromCode("class X;"));
111 ASSERT_TRUE(AST.get());
112 EXPECT_TRUE(FindClassDeclX(AST.get()));
113
114 AST.reset(buildASTFromCode("class Y;"));
115 ASSERT_TRUE(AST.get());
116 EXPECT_FALSE(FindClassDeclX(AST.get()));
117}
118
Manuel Klimek47c245a2012-04-04 12:07:46 +0000119TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000120 OwningPtr<FrontendActionFactory> Factory(
121 newFrontendActionFactory<SyntaxOnlyAction>());
122 OwningPtr<FrontendAction> Action(Factory->create());
Manuel Klimek47c245a2012-04-04 12:07:46 +0000123 EXPECT_TRUE(Action.get() != NULL);
124}
125
126struct IndependentFrontendActionCreator {
Manuel Klimek5da9dcb2012-07-05 18:13:01 +0000127 ASTConsumer *newASTConsumer() {
128 return new FindTopLevelDeclConsumer(NULL);
129 }
Manuel Klimek47c245a2012-04-04 12:07:46 +0000130};
131
132TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
133 IndependentFrontendActionCreator Creator;
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000134 OwningPtr<FrontendActionFactory> Factory(
135 newFrontendActionFactory(&Creator));
136 OwningPtr<FrontendAction> Action(Factory->create());
Manuel Klimek47c245a2012-04-04 12:07:46 +0000137 EXPECT_TRUE(Action.get() != NULL);
138}
139
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000140TEST(ToolInvocation, TestMapVirtualFile) {
Peter Collingbournec689ee72013-11-06 20:12:45 +0000141 IntrusiveRefCntPtr<clang::FileManager> Files(
142 new clang::FileManager(clang::FileSystemOptions()));
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000143 std::vector<std::string> Args;
144 Args.push_back("tool-executable");
145 Args.push_back("-Idef");
146 Args.push_back("-fsyntax-only");
147 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000148 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
149 Files.getPtr());
Alexander Kornienko55f2ca92012-06-01 14:50:43 +0000150 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
151 Invocation.mapVirtualFile("def/abc", "\n");
152 EXPECT_TRUE(Invocation.run());
153}
154
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000155TEST(ToolInvocation, TestVirtualModulesCompilation) {
156 // FIXME: Currently, this only tests that we don't exit with an error if a
157 // mapped module.map is found on the include path. In the future, expand this
158 // test to run a full modules enabled compilation, so we make sure we can
159 // rerun modules compilations with a virtual file system.
Peter Collingbournec689ee72013-11-06 20:12:45 +0000160 IntrusiveRefCntPtr<clang::FileManager> Files(
161 new clang::FileManager(clang::FileSystemOptions()));
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000162 std::vector<std::string> Args;
163 Args.push_back("tool-executable");
164 Args.push_back("-Idef");
165 Args.push_back("-fsyntax-only");
166 Args.push_back("test.cpp");
Peter Collingbournec689ee72013-11-06 20:12:45 +0000167 clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
168 Files.getPtr());
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000169 Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
170 Invocation.mapVirtualFile("def/abc", "\n");
171 // Add a module.map file in the include directory of our header, so we trigger
172 // the module.map header search logic.
173 Invocation.mapVirtualFile("def/module.map", "\n");
174 EXPECT_TRUE(Invocation.run());
175}
176
Edwin Vane20c6f542013-05-29 16:01:10 +0000177struct VerifyEndCallback : public SourceFileCallbacks {
178 VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
Edwin Vane3a331f32013-05-30 13:59:44 +0000179 virtual bool handleBeginSource(CompilerInstance &CI,
Craig Toppera798a9d2014-03-02 09:32:10 +0000180 StringRef Filename) override {
Edwin Vane20c6f542013-05-29 16:01:10 +0000181 ++BeginCalled;
182 return true;
183 }
Edwin Vane3a331f32013-05-30 13:59:44 +0000184 virtual void handleEndSource() {
Edwin Vane20c6f542013-05-29 16:01:10 +0000185 ++EndCalled;
Manuel Klimek8246d872012-10-25 08:49:11 +0000186 }
187 ASTConsumer *newASTConsumer() {
188 return new FindTopLevelDeclConsumer(&Matched);
189 }
Edwin Vane20c6f542013-05-29 16:01:10 +0000190 unsigned BeginCalled;
191 unsigned EndCalled;
Manuel Klimek8246d872012-10-25 08:49:11 +0000192 bool Matched;
193};
194
NAKAMURA Takumi95fd41a2012-10-25 09:38:41 +0000195#if !defined(_WIN32)
Edwin Vane20c6f542013-05-29 16:01:10 +0000196TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
Manuel Klimek8246d872012-10-25 08:49:11 +0000197 VerifyEndCallback EndCallback;
198
199 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
200 std::vector<std::string> Sources;
201 Sources.push_back("/a.cc");
202 Sources.push_back("/b.cc");
203 ClangTool Tool(Compilations, Sources);
204
205 Tool.mapVirtualFile("/a.cc", "void a() {}");
206 Tool.mapVirtualFile("/b.cc", "void b() {}");
207
208 Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
209
210 EXPECT_TRUE(EndCallback.Matched);
Edwin Vane20c6f542013-05-29 16:01:10 +0000211 EXPECT_EQ(2u, EndCallback.BeginCalled);
212 EXPECT_EQ(2u, EndCallback.EndCalled);
Manuel Klimek8246d872012-10-25 08:49:11 +0000213}
NAKAMURA Takumi95fd41a2012-10-25 09:38:41 +0000214#endif
Manuel Klimek8246d872012-10-25 08:49:11 +0000215
Richard Smith9219d1b2012-11-27 21:31:01 +0000216struct SkipBodyConsumer : public clang::ASTConsumer {
217 /// Skip the 'skipMe' function.
218 virtual bool shouldSkipFunctionBody(Decl *D) {
219 FunctionDecl *F = dyn_cast<FunctionDecl>(D);
220 return F && F->getNameAsString() == "skipMe";
221 }
222};
223
224struct SkipBodyAction : public clang::ASTFrontendAction {
225 virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
226 StringRef) {
227 Compiler.getFrontendOpts().SkipFunctionBodies = true;
228 return new SkipBodyConsumer;
229 }
230};
231
Hal Finkel1d3e3d72013-01-28 04:37:38 +0000232TEST(runToolOnCode, TestSkipFunctionBody) {
Richard Smith9219d1b2012-11-27 21:31:01 +0000233 EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
234 "int skipMe() { an_error_here }"));
235 EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
236 "int skipMeNot() { an_error_here }"));
237}
238
Peter Collingbournec0423b32014-03-02 23:37:26 +0000239TEST(runToolOnCodeWithArgs, TestNoDepFile) {
240 llvm::SmallString<32> DepFilePath;
241 ASSERT_FALSE(
242 llvm::sys::fs::createTemporaryFile("depfile", "d", DepFilePath));
Peter Collingbournef9372542014-03-03 08:13:06 +0000243 std::vector<std::string> Args;
244 Args.push_back("-MMD");
245 Args.push_back("-MT");
246 Args.push_back(DepFilePath.str());
247 Args.push_back("-MF");
248 Args.push_back(DepFilePath.str());
Peter Collingbourne2bbb0292014-03-03 07:49:35 +0000249 EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args));
Peter Collingbournec0423b32014-03-02 23:37:26 +0000250 EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
251 EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
252}
253
Manuel Klimekd91ac932013-06-04 14:44:44 +0000254struct CheckSyntaxOnlyAdjuster: public ArgumentsAdjuster {
255 bool &Found;
256 bool &Ran;
257
258 CheckSyntaxOnlyAdjuster(bool &Found, bool &Ran) : Found(Found), Ran(Ran) { }
259
260 virtual CommandLineArguments
Craig Toppera798a9d2014-03-02 09:32:10 +0000261 Adjust(const CommandLineArguments &Args) override {
Manuel Klimekd91ac932013-06-04 14:44:44 +0000262 Ran = true;
263 for (unsigned I = 0, E = Args.size(); I != E; ++I) {
264 if (Args[I] == "-fsyntax-only") {
265 Found = true;
266 break;
267 }
268 }
269 return Args;
270 }
271};
272
273TEST(ClangToolTest, ArgumentAdjusters) {
274 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
275
276 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
277 Tool.mapVirtualFile("/a.cc", "void a() {}");
278
279 bool Found = false;
280 bool Ran = false;
281 Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
282 Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
283 EXPECT_TRUE(Ran);
284 EXPECT_TRUE(Found);
285
286 Ran = Found = false;
287 Tool.clearArgumentsAdjusters();
288 Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
289 Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
290 Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
291 EXPECT_TRUE(Ran);
292 EXPECT_FALSE(Found);
293}
294
Peter Collingbourne671a1e42013-11-06 23:02:51 +0000295#ifndef _WIN32
Peter Collingbournec689ee72013-11-06 20:12:45 +0000296TEST(ClangToolTest, BuildASTs) {
297 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
298
299 std::vector<std::string> Sources;
300 Sources.push_back("/a.cc");
301 Sources.push_back("/b.cc");
302 ClangTool Tool(Compilations, Sources);
303
304 Tool.mapVirtualFile("/a.cc", "void a() {}");
305 Tool.mapVirtualFile("/b.cc", "void b() {}");
306
307 std::vector<ASTUnit *> ASTs;
308 EXPECT_EQ(0, Tool.buildASTs(ASTs));
309 EXPECT_EQ(2u, ASTs.size());
310
311 llvm::DeleteContainerPointers(ASTs);
312}
313
Manuel Klimek64083012013-11-07 23:18:05 +0000314struct TestDiagnosticConsumer : public DiagnosticConsumer {
315 TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
316 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
317 const Diagnostic &Info) {
318 ++NumDiagnosticsSeen;
319 }
320 unsigned NumDiagnosticsSeen;
321};
322
323TEST(ClangToolTest, InjectDiagnosticConsumer) {
324 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
325 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
326 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
327 TestDiagnosticConsumer Consumer;
328 Tool.setDiagnosticConsumer(&Consumer);
329 Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
330 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
331}
332
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000333TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
334 FixedCompilationDatabase Compilations("/", std::vector<std::string>());
335 ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
336 Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
337 TestDiagnosticConsumer Consumer;
338 Tool.setDiagnosticConsumer(&Consumer);
339 std::vector<ASTUnit*> ASTs;
340 Tool.buildASTs(ASTs);
341 EXPECT_EQ(1u, ASTs.size());
342 EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
343}
NAKAMURA Takumid3b07c62013-11-13 00:18:50 +0000344#endif
Manuel Klimek31cd3fc2013-11-12 17:53:18 +0000345
Manuel Klimek47c245a2012-04-04 12:07:46 +0000346} // end namespace tooling
347} // end namespace clang