1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/AST/ASTConsumer.h" |
10 | #include "clang/AST/DeclCXX.h" |
11 | #include "clang/AST/DeclGroup.h" |
12 | #include "clang/Frontend/ASTUnit.h" |
13 | #include "clang/Frontend/CompilerInstance.h" |
14 | #include "clang/Frontend/FrontendAction.h" |
15 | #include "clang/Frontend/FrontendActions.h" |
16 | #include "clang/Tooling/CompilationDatabase.h" |
17 | #include "clang/Tooling/Tooling.h" |
18 | #include "llvm/ADT/STLExtras.h" |
19 | #include "llvm/Support/Path.h" |
20 | #include "llvm/Support/TargetRegistry.h" |
21 | #include "llvm/Support/TargetSelect.h" |
22 | #include "gtest/gtest.h" |
23 | #include <algorithm> |
24 | #include <string> |
25 | |
26 | namespace clang { |
27 | namespace tooling { |
28 | |
29 | namespace { |
30 | |
31 | |
32 | class TestAction : public clang::ASTFrontendAction { |
33 | public: |
34 | |
35 | explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer) |
36 | : TestConsumer(std::move(TestConsumer)) {} |
37 | |
38 | protected: |
39 | std::unique_ptr<clang::ASTConsumer> |
40 | CreateASTConsumer(clang::CompilerInstance &compiler, |
41 | StringRef dummy) override { |
42 | |
43 | return std::move(TestConsumer); |
44 | } |
45 | |
46 | private: |
47 | std::unique_ptr<clang::ASTConsumer> TestConsumer; |
48 | }; |
49 | |
50 | class FindTopLevelDeclConsumer : public clang::ASTConsumer { |
51 | public: |
52 | explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl) |
53 | : FoundTopLevelDecl(FoundTopLevelDecl) {} |
54 | bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override { |
55 | *FoundTopLevelDecl = true; |
56 | return true; |
57 | } |
58 | private: |
59 | bool * const FoundTopLevelDecl; |
60 | }; |
61 | } |
62 | |
63 | TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) { |
64 | bool FoundTopLevelDecl = false; |
65 | EXPECT_TRUE( |
66 | runToolOnCode(new TestAction(llvm::make_unique<FindTopLevelDeclConsumer>( |
67 | &FoundTopLevelDecl)), |
68 | "")); |
69 | EXPECT_FALSE(FoundTopLevelDecl); |
70 | } |
71 | |
72 | namespace { |
73 | class FindClassDeclXConsumer : public clang::ASTConsumer { |
74 | public: |
75 | FindClassDeclXConsumer(bool *FoundClassDeclX) |
76 | : FoundClassDeclX(FoundClassDeclX) {} |
77 | bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override { |
78 | if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>( |
79 | *GroupRef.begin())) { |
80 | if (Record->getName() == "X") { |
81 | *FoundClassDeclX = true; |
82 | } |
83 | } |
84 | return true; |
85 | } |
86 | private: |
87 | bool *FoundClassDeclX; |
88 | }; |
89 | bool FindClassDeclX(ASTUnit *AST) { |
90 | for (std::vector<Decl *>::iterator i = AST->top_level_begin(), |
91 | e = AST->top_level_end(); |
92 | i != e; ++i) { |
93 | if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) { |
94 | if (Record->getName() == "X") { |
95 | return true; |
96 | } |
97 | } |
98 | } |
99 | return false; |
100 | } |
101 | } |
102 | |
103 | TEST(runToolOnCode, FindsClassDecl) { |
104 | bool FoundClassDeclX = false; |
105 | EXPECT_TRUE( |
106 | runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>( |
107 | &FoundClassDeclX)), |
108 | "class X;")); |
109 | EXPECT_TRUE(FoundClassDeclX); |
110 | |
111 | FoundClassDeclX = false; |
112 | EXPECT_TRUE( |
113 | runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>( |
114 | &FoundClassDeclX)), |
115 | "class Y;")); |
116 | EXPECT_FALSE(FoundClassDeclX); |
117 | } |
118 | |
119 | TEST(buildASTFromCode, FindsClassDecl) { |
120 | std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;"); |
121 | ASSERT_TRUE(AST.get()); |
122 | EXPECT_TRUE(FindClassDeclX(AST.get())); |
123 | |
124 | AST = buildASTFromCode("class Y;"); |
125 | ASSERT_TRUE(AST.get()); |
126 | EXPECT_FALSE(FindClassDeclX(AST.get())); |
127 | } |
128 | |
129 | TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) { |
130 | std::unique_ptr<FrontendActionFactory> Factory( |
131 | newFrontendActionFactory<SyntaxOnlyAction>()); |
132 | std::unique_ptr<FrontendAction> Action(Factory->create()); |
133 | EXPECT_TRUE(Action.get() != nullptr); |
134 | } |
135 | |
136 | struct IndependentFrontendActionCreator { |
137 | std::unique_ptr<ASTConsumer> newASTConsumer() { |
138 | return llvm::make_unique<FindTopLevelDeclConsumer>(nullptr); |
139 | } |
140 | }; |
141 | |
142 | TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) { |
143 | IndependentFrontendActionCreator Creator; |
144 | std::unique_ptr<FrontendActionFactory> Factory( |
145 | newFrontendActionFactory(&Creator)); |
146 | std::unique_ptr<FrontendAction> Action(Factory->create()); |
147 | EXPECT_TRUE(Action.get() != nullptr); |
148 | } |
149 | |
150 | TEST(ToolInvocation, TestMapVirtualFile) { |
151 | llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( |
152 | new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); |
153 | llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
154 | new llvm::vfs::InMemoryFileSystem); |
155 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); |
156 | llvm::IntrusiveRefCntPtr<FileManager> Files( |
157 | new FileManager(FileSystemOptions(), OverlayFileSystem)); |
158 | std::vector<std::string> Args; |
159 | Args.push_back("tool-executable"); |
160 | Args.push_back("-Idef"); |
161 | Args.push_back("-fsyntax-only"); |
162 | Args.push_back("test.cpp"); |
163 | clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, |
164 | Files.get()); |
165 | InMemoryFileSystem->addFile( |
166 | "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); |
167 | InMemoryFileSystem->addFile("def/abc", 0, |
168 | llvm::MemoryBuffer::getMemBuffer("\n")); |
169 | EXPECT_TRUE(Invocation.run()); |
170 | } |
171 | |
172 | TEST(ToolInvocation, TestVirtualModulesCompilation) { |
173 | |
174 | |
175 | |
176 | |
177 | llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( |
178 | new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); |
179 | llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
180 | new llvm::vfs::InMemoryFileSystem); |
181 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); |
182 | llvm::IntrusiveRefCntPtr<FileManager> Files( |
183 | new FileManager(FileSystemOptions(), OverlayFileSystem)); |
184 | std::vector<std::string> Args; |
185 | Args.push_back("tool-executable"); |
186 | Args.push_back("-Idef"); |
187 | Args.push_back("-fsyntax-only"); |
188 | Args.push_back("test.cpp"); |
189 | clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, |
190 | Files.get()); |
191 | InMemoryFileSystem->addFile( |
192 | "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n")); |
193 | InMemoryFileSystem->addFile("def/abc", 0, |
194 | llvm::MemoryBuffer::getMemBuffer("\n")); |
195 | |
196 | |
197 | InMemoryFileSystem->addFile("def/module.map", 0, |
198 | llvm::MemoryBuffer::getMemBuffer("\n")); |
199 | EXPECT_TRUE(Invocation.run()); |
200 | } |
201 | |
202 | struct VerifyEndCallback : public SourceFileCallbacks { |
203 | VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {} |
204 | bool handleBeginSource(CompilerInstance &CI) override { |
205 | ++BeginCalled; |
206 | return true; |
207 | } |
208 | void handleEndSource() override { ++EndCalled; } |
209 | std::unique_ptr<ASTConsumer> newASTConsumer() { |
210 | return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched); |
211 | } |
212 | unsigned BeginCalled; |
213 | unsigned EndCalled; |
214 | bool Matched; |
215 | }; |
216 | |
217 | #if !defined(_WIN32) |
218 | TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) { |
219 | VerifyEndCallback EndCallback; |
220 | |
221 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
222 | std::vector<std::string> Sources; |
223 | Sources.push_back("/a.cc"); |
224 | Sources.push_back("/b.cc"); |
225 | ClangTool Tool(Compilations, Sources); |
226 | |
227 | Tool.mapVirtualFile("/a.cc", "void a() {}"); |
228 | Tool.mapVirtualFile("/b.cc", "void b() {}"); |
229 | |
230 | std::unique_ptr<FrontendActionFactory> Action( |
231 | newFrontendActionFactory(&EndCallback, &EndCallback)); |
232 | Tool.run(Action.get()); |
233 | |
234 | EXPECT_TRUE(EndCallback.Matched); |
235 | EXPECT_EQ(2u, EndCallback.BeginCalled); |
236 | EXPECT_EQ(2u, EndCallback.EndCalled); |
237 | } |
238 | #endif |
239 | |
240 | struct SkipBodyConsumer : public clang::ASTConsumer { |
241 | |
242 | bool shouldSkipFunctionBody(Decl *D) override { |
243 | NamedDecl *F = dyn_cast<NamedDecl>(D); |
244 | return F && F->getNameAsString() == "skipMe"; |
245 | } |
246 | }; |
247 | |
248 | struct SkipBodyAction : public clang::ASTFrontendAction { |
249 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
250 | StringRef) override { |
251 | Compiler.getFrontendOpts().SkipFunctionBodies = true; |
252 | return llvm::make_unique<SkipBodyConsumer>(); |
253 | } |
254 | }; |
255 | |
256 | TEST(runToolOnCode, TestSkipFunctionBody) { |
257 | std::vector<std::string> Args = {"-std=c++11"}; |
258 | std::vector<std::string> Args2 = {"-fno-delayed-template-parsing"}; |
259 | |
260 | EXPECT_TRUE(runToolOnCode(new SkipBodyAction, |
261 | "int skipMe() { an_error_here }")); |
262 | EXPECT_FALSE(runToolOnCode(new SkipBodyAction, |
263 | "int skipMeNot() { an_error_here }")); |
264 | |
265 | |
266 | EXPECT_TRUE(runToolOnCodeWithArgs( |
267 | new SkipBodyAction, |
268 | "struct skipMe { skipMe() : an_error() { more error } };", Args)); |
269 | EXPECT_TRUE(runToolOnCodeWithArgs( |
270 | new SkipBodyAction, "struct skipMe { skipMe(); };" |
271 | "skipMe::skipMe() : an_error([](){;}) { more error }", |
272 | Args)); |
273 | EXPECT_TRUE(runToolOnCodeWithArgs( |
274 | new SkipBodyAction, "struct skipMe { skipMe(); };" |
275 | "skipMe::skipMe() : an_error{[](){;}} { more error }", |
276 | Args)); |
277 | EXPECT_TRUE(runToolOnCodeWithArgs( |
278 | new SkipBodyAction, |
279 | "struct skipMe { skipMe(); };" |
280 | "skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }", |
281 | Args)); |
282 | EXPECT_TRUE(runToolOnCodeWithArgs( |
283 | new SkipBodyAction, "struct skipMe { skipMe() : bases()... { error } };", |
284 | Args)); |
285 | |
286 | EXPECT_FALSE(runToolOnCodeWithArgs( |
287 | new SkipBodyAction, "struct skipMeNot { skipMeNot() : an_error() { } };", |
288 | Args)); |
289 | EXPECT_FALSE(runToolOnCodeWithArgs(new SkipBodyAction, |
290 | "struct skipMeNot { skipMeNot(); };" |
291 | "skipMeNot::skipMeNot() : an_error() { }", |
292 | Args)); |
293 | |
294 | |
295 | EXPECT_TRUE(runToolOnCode( |
296 | new SkipBodyAction, |
297 | "void skipMe() try { an_error() } catch(error) { error };")); |
298 | EXPECT_TRUE(runToolOnCode( |
299 | new SkipBodyAction, |
300 | "struct S { void skipMe() try { an_error() } catch(error) { error } };")); |
301 | EXPECT_TRUE( |
302 | runToolOnCode(new SkipBodyAction, |
303 | "void skipMe() try { an_error() } catch(error) { error; }" |
304 | "catch(error) { error } catch (error) { }")); |
305 | EXPECT_FALSE(runToolOnCode( |
306 | new SkipBodyAction, |
307 | "void skipMe() try something;")); |
308 | |
309 | |
310 | EXPECT_TRUE(runToolOnCode( |
311 | new SkipBodyAction, "template<typename T> int skipMe() { an_error_here }" |
312 | "int x = skipMe<int>();")); |
313 | EXPECT_FALSE(runToolOnCodeWithArgs( |
314 | new SkipBodyAction, |
315 | "template<typename T> int skipMeNot() { an_error_here }", Args2)); |
316 | } |
317 | |
318 | TEST(runToolOnCodeWithArgs, TestNoDepFile) { |
319 | llvm::SmallString<32> DepFilePath; |
320 | ASSERT_FALSE(llvm::sys::fs::getPotentiallyUniqueTempFileName("depfile", "d", |
321 | DepFilePath)); |
322 | std::vector<std::string> Args; |
323 | Args.push_back("-MMD"); |
324 | Args.push_back("-MT"); |
325 | Args.push_back(DepFilePath.str()); |
326 | Args.push_back("-MF"); |
327 | Args.push_back(DepFilePath.str()); |
328 | EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args)); |
329 | EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str())); |
330 | EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str())); |
331 | } |
332 | |
333 | struct CheckColoredDiagnosticsAction : public clang::ASTFrontendAction { |
334 | CheckColoredDiagnosticsAction(bool ShouldShowColor) |
335 | : ShouldShowColor(ShouldShowColor) {} |
336 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
337 | StringRef) override { |
338 | if (Compiler.getDiagnosticOpts().ShowColors != ShouldShowColor) |
339 | Compiler.getDiagnostics().Report( |
340 | Compiler.getDiagnostics().getCustomDiagID( |
341 | DiagnosticsEngine::Fatal, |
342 | "getDiagnosticOpts().ShowColors != ShouldShowColor")); |
343 | return llvm::make_unique<ASTConsumer>(); |
344 | } |
345 | |
346 | private: |
347 | bool ShouldShowColor = true; |
348 | }; |
349 | |
350 | TEST(runToolOnCodeWithArgs, DiagnosticsColor) { |
351 | |
352 | EXPECT_TRUE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(true), "", |
353 | {"-fcolor-diagnostics"})); |
354 | EXPECT_TRUE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false), |
355 | "", {"-fno-color-diagnostics"})); |
356 | EXPECT_TRUE( |
357 | runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(true), "", |
358 | {"-fno-color-diagnostics", "-fcolor-diagnostics"})); |
359 | EXPECT_TRUE( |
360 | runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false), "", |
361 | {"-fcolor-diagnostics", "-fno-color-diagnostics"})); |
362 | EXPECT_TRUE(runToolOnCodeWithArgs( |
363 | new CheckColoredDiagnosticsAction(true), "", |
364 | {"-fno-color-diagnostics", "-fdiagnostics-color=always"})); |
365 | |
366 | |
367 | EXPECT_FALSE(runToolOnCodeWithArgs(new CheckColoredDiagnosticsAction(false), |
368 | "", {"-fcolor-diagnostics"})); |
369 | } |
370 | |
371 | TEST(ClangToolTest, ArgumentAdjusters) { |
372 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
373 | |
374 | ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); |
375 | Tool.mapVirtualFile("/a.cc", "void a() {}"); |
376 | |
377 | std::unique_ptr<FrontendActionFactory> Action( |
378 | newFrontendActionFactory<SyntaxOnlyAction>()); |
379 | |
380 | bool Found = false; |
381 | bool Ran = false; |
382 | ArgumentsAdjuster CheckSyntaxOnlyAdjuster = |
383 | [&Found, &Ran](const CommandLineArguments &Args, StringRef ) { |
384 | Ran = true; |
385 | if (llvm::is_contained(Args, "-fsyntax-only")) |
386 | Found = true; |
387 | return Args; |
388 | }; |
389 | Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); |
390 | Tool.run(Action.get()); |
391 | EXPECT_TRUE(Ran); |
392 | EXPECT_TRUE(Found); |
393 | |
394 | Ran = Found = false; |
395 | Tool.clearArgumentsAdjusters(); |
396 | Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster); |
397 | Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); |
398 | Tool.run(Action.get()); |
399 | EXPECT_TRUE(Ran); |
400 | EXPECT_FALSE(Found); |
401 | } |
402 | |
403 | TEST(ClangToolTest, BaseVirtualFileSystemUsage) { |
404 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
405 | llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( |
406 | new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); |
407 | llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( |
408 | new llvm::vfs::InMemoryFileSystem); |
409 | OverlayFileSystem->pushOverlay(InMemoryFileSystem); |
410 | |
411 | InMemoryFileSystem->addFile( |
412 | "a.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}")); |
413 | |
414 | ClangTool Tool(Compilations, std::vector<std::string>(1, "a.cpp"), |
415 | std::make_shared<PCHContainerOperations>(), OverlayFileSystem); |
416 | std::unique_ptr<FrontendActionFactory> Action( |
417 | newFrontendActionFactory<SyntaxOnlyAction>()); |
418 | EXPECT_EQ(0, Tool.run(Action.get())); |
419 | } |
420 | |
421 | |
422 | TEST(ClangToolTest, StripDependencyFileAdjuster) { |
423 | FixedCompilationDatabase Compilations("/", {"-MD", "-c", "-MMD", "-w"}); |
424 | |
425 | ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); |
426 | Tool.mapVirtualFile("/a.cc", "void a() {}"); |
427 | |
428 | std::unique_ptr<FrontendActionFactory> Action( |
429 | newFrontendActionFactory<SyntaxOnlyAction>()); |
430 | |
431 | CommandLineArguments FinalArgs; |
432 | ArgumentsAdjuster CheckFlagsAdjuster = |
433 | [&FinalArgs](const CommandLineArguments &Args, StringRef ) { |
434 | FinalArgs = Args; |
435 | return Args; |
436 | }; |
437 | Tool.clearArgumentsAdjusters(); |
438 | Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); |
439 | Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); |
440 | Tool.run(Action.get()); |
441 | |
442 | auto HasFlag = [&FinalArgs](const std::string &Flag) { |
443 | return std::find(FinalArgs.begin(), FinalArgs.end(), Flag) != |
444 | FinalArgs.end(); |
445 | }; |
446 | EXPECT_FALSE(HasFlag("-MD")); |
447 | EXPECT_FALSE(HasFlag("-MMD")); |
448 | EXPECT_TRUE(HasFlag("-c")); |
449 | EXPECT_TRUE(HasFlag("-w")); |
450 | } |
451 | |
452 | |
453 | TEST(ClangToolTest, StripPluginsAdjuster) { |
454 | FixedCompilationDatabase Compilations( |
455 | "/", {"-Xclang", "-add-plugin", "-Xclang", "random-plugin"}); |
456 | |
457 | ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); |
458 | Tool.mapVirtualFile("/a.cc", "void a() {}"); |
459 | |
460 | std::unique_ptr<FrontendActionFactory> Action( |
461 | newFrontendActionFactory<SyntaxOnlyAction>()); |
462 | |
463 | CommandLineArguments FinalArgs; |
464 | ArgumentsAdjuster CheckFlagsAdjuster = |
465 | [&FinalArgs](const CommandLineArguments &Args, StringRef ) { |
466 | FinalArgs = Args; |
467 | return Args; |
468 | }; |
469 | Tool.clearArgumentsAdjusters(); |
470 | Tool.appendArgumentsAdjuster(getStripPluginsAdjuster()); |
471 | Tool.appendArgumentsAdjuster(CheckFlagsAdjuster); |
472 | Tool.run(Action.get()); |
473 | |
474 | auto HasFlag = [&FinalArgs](const std::string &Flag) { |
475 | return std::find(FinalArgs.begin(), FinalArgs.end(), Flag) != |
476 | FinalArgs.end(); |
477 | }; |
478 | EXPECT_FALSE(HasFlag("-Xclang")); |
479 | EXPECT_FALSE(HasFlag("-add-plugin")); |
480 | EXPECT_FALSE(HasFlag("-random-plugin")); |
481 | } |
482 | |
483 | namespace { |
484 | |
485 | |
486 | |
487 | std::string getAnyTarget() { |
488 | llvm::InitializeAllTargets(); |
489 | for (const auto &Target : llvm::TargetRegistry::targets()) { |
490 | std::string Error; |
491 | StringRef TargetName(Target.getName()); |
492 | if (TargetName == "x86-64") |
493 | TargetName = "x86_64"; |
494 | if (llvm::TargetRegistry::lookupTarget(TargetName, Error) == &Target) { |
495 | return TargetName; |
496 | } |
497 | } |
498 | return ""; |
499 | } |
500 | } |
501 | |
502 | TEST(addTargetAndModeForProgramName, AddsTargetAndMode) { |
503 | std::string Target = getAnyTarget(); |
504 | ASSERT_FALSE(Target.empty()); |
505 | |
506 | std::vector<std::string> Args = {"clang", "-foo"}; |
507 | addTargetAndModeForProgramName(Args, ""); |
508 | EXPECT_EQ((std::vector<std::string>{"clang", "-foo"}), Args); |
509 | addTargetAndModeForProgramName(Args, Target + "-g++"); |
510 | EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, |
511 | "--driver-mode=g++", "-foo"}), |
512 | Args); |
513 | } |
514 | |
515 | TEST(addTargetAndModeForProgramName, PathIgnored) { |
516 | std::string Target = getAnyTarget(); |
517 | ASSERT_FALSE(Target.empty()); |
518 | |
519 | SmallString<32> ToolPath; |
520 | llvm::sys::path::append(ToolPath, "foo", "bar", Target + "-g++"); |
521 | |
522 | std::vector<std::string> Args = {"clang", "-foo"}; |
523 | addTargetAndModeForProgramName(Args, ToolPath); |
524 | EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, |
525 | "--driver-mode=g++", "-foo"}), |
526 | Args); |
527 | } |
528 | |
529 | TEST(addTargetAndModeForProgramName, IgnoresExistingTarget) { |
530 | std::string Target = getAnyTarget(); |
531 | ASSERT_FALSE(Target.empty()); |
532 | |
533 | std::vector<std::string> Args = {"clang", "-foo", "-target", "something"}; |
534 | addTargetAndModeForProgramName(Args, Target + "-g++"); |
535 | EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", |
536 | "-target", "something"}), |
537 | Args); |
538 | |
539 | std::vector<std::string> ArgsAlt = {"clang", "-foo", "-target=something"}; |
540 | addTargetAndModeForProgramName(ArgsAlt, Target + "-g++"); |
541 | EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo", |
542 | "-target=something"}), |
543 | ArgsAlt); |
544 | } |
545 | |
546 | TEST(addTargetAndModeForProgramName, IgnoresExistingMode) { |
547 | std::string Target = getAnyTarget(); |
548 | ASSERT_FALSE(Target.empty()); |
549 | |
550 | std::vector<std::string> Args = {"clang", "-foo", "--driver-mode=abc"}; |
551 | addTargetAndModeForProgramName(Args, Target + "-g++"); |
552 | EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo", |
553 | "--driver-mode=abc"}), |
554 | Args); |
555 | |
556 | std::vector<std::string> ArgsAlt = {"clang", "-foo", "--driver-mode", "abc"}; |
557 | addTargetAndModeForProgramName(ArgsAlt, Target + "-g++"); |
558 | EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo", |
559 | "--driver-mode", "abc"}), |
560 | ArgsAlt); |
561 | } |
562 | |
563 | #ifndef _WIN32 |
564 | TEST(ClangToolTest, BuildASTs) { |
565 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
566 | |
567 | std::vector<std::string> Sources; |
568 | Sources.push_back("/a.cc"); |
569 | Sources.push_back("/b.cc"); |
570 | ClangTool Tool(Compilations, Sources); |
571 | |
572 | Tool.mapVirtualFile("/a.cc", "void a() {}"); |
573 | Tool.mapVirtualFile("/b.cc", "void b() {}"); |
574 | |
575 | std::vector<std::unique_ptr<ASTUnit>> ASTs; |
576 | EXPECT_EQ(0, Tool.buildASTs(ASTs)); |
577 | EXPECT_EQ(2u, ASTs.size()); |
578 | } |
579 | |
580 | struct TestDiagnosticConsumer : public DiagnosticConsumer { |
581 | TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {} |
582 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, |
583 | const Diagnostic &Info) override { |
584 | ++NumDiagnosticsSeen; |
585 | } |
586 | unsigned NumDiagnosticsSeen; |
587 | }; |
588 | |
589 | TEST(ClangToolTest, InjectDiagnosticConsumer) { |
590 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
591 | ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); |
592 | Tool.mapVirtualFile("/a.cc", "int x = undeclared;"); |
593 | TestDiagnosticConsumer Consumer; |
594 | Tool.setDiagnosticConsumer(&Consumer); |
595 | std::unique_ptr<FrontendActionFactory> Action( |
596 | newFrontendActionFactory<SyntaxOnlyAction>()); |
597 | Tool.run(Action.get()); |
598 | EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); |
599 | } |
600 | |
601 | TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) { |
602 | FixedCompilationDatabase Compilations("/", std::vector<std::string>()); |
603 | ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc")); |
604 | Tool.mapVirtualFile("/a.cc", "int x = undeclared;"); |
605 | TestDiagnosticConsumer Consumer; |
606 | Tool.setDiagnosticConsumer(&Consumer); |
607 | std::vector<std::unique_ptr<ASTUnit>> ASTs; |
608 | Tool.buildASTs(ASTs); |
609 | EXPECT_EQ(1u, ASTs.size()); |
610 | EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen); |
611 | } |
612 | #endif |
613 | |
614 | TEST(runToolOnCode, TestResetDiagnostics) { |
615 | |
616 | struct ResetDiagnosticAction : public clang::ASTFrontendAction { |
617 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
618 | StringRef) override { |
619 | struct Consumer : public clang::ASTConsumer { |
620 | bool HandleTopLevelDecl(clang::DeclGroupRef D) override { |
621 | auto &Diags = (*D.begin())->getASTContext().getDiagnostics(); |
622 | |
623 | Diags.Reset(); |
624 | |
625 | Diags.setIgnoreAllWarnings(true); |
626 | return true; |
627 | } |
628 | }; |
629 | return llvm::make_unique<Consumer>(); |
630 | } |
631 | }; |
632 | |
633 | |
634 | EXPECT_FALSE( |
635 | runToolOnCode(new ResetDiagnosticAction, |
636 | "struct Foo { Foo(int); ~Foo(); struct Fwd _fwd; };" |
637 | "void func() { long x; Foo f(x); }")); |
638 | } |
639 | |
640 | } |
641 | } |
642 | |