1 //===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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/ArgumentsAdjusters.h"
17 #include "clang/Tooling/CompilationDatabase.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/TargetRegistry.h"
23 #include "llvm/Support/TargetSelect.h"
24 #include "gtest/gtest.h"
25 #include <algorithm>
26 #include <string>
27 #include <vector>
28 
29 namespace clang {
30 namespace tooling {
31 
32 namespace {
33 /// Takes an ast consumer and returns it from CreateASTConsumer. This only
34 /// works with single translation unit compilations.
35 class TestAction : public clang::ASTFrontendAction {
36 public:
37   /// Takes ownership of TestConsumer.
38   explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer)
39       : TestConsumer(std::move(TestConsumer)) {}
40 
41 protected:
42   std::unique_ptr<clang::ASTConsumer>
43   CreateASTConsumer(clang::CompilerInstance &compiler,
44                     StringRef dummy) override {
45     /// TestConsumer will be deleted by the framework calling us.
46     return std::move(TestConsumer);
47   }
48 
49 private:
50   std::unique_ptr<clang::ASTConsumer> TestConsumer;
51 };
52 
53 class FindTopLevelDeclConsumer : public clang::ASTConsumer {
54  public:
55   explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
56       : FoundTopLevelDecl(FoundTopLevelDecl) {}
57   bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
58     *FoundTopLevelDecl = true;
59     return true;
60   }
61  private:
62   bool * const FoundTopLevelDecl;
63 };
64 } // end namespace
65 
66 TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
67   bool FoundTopLevelDecl = false;
68   EXPECT_TRUE(runToolOnCode(
69       std::make_unique<TestAction>(
70           std::make_unique<FindTopLevelDeclConsumer>(&FoundTopLevelDecl)),
71       ""));
72   EXPECT_FALSE(FoundTopLevelDecl);
73 }
74 
75 namespace {
76 class FindClassDeclXConsumer : public clang::ASTConsumer {
77  public:
78   FindClassDeclXConsumer(bool *FoundClassDeclX)
79       : FoundClassDeclX(FoundClassDeclX) {}
80   bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
81     if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
82             *GroupRef.begin())) {
83       if (Record->getName() == "X") {
84         *FoundClassDeclX = true;
85       }
86     }
87     return true;
88   }
89  private:
90   bool *FoundClassDeclX;
91 };
92 bool FindClassDeclX(ASTUnit *AST) {
93   for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
94                                      e = AST->top_level_end();
95        i != e; ++i) {
96     if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
97       if (Record->getName() == "X") {
98         return true;
99       }
100     }
101   }
102   return false;
103 }
104 
105 struct TestDiagnosticConsumer : public DiagnosticConsumer {
106   TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
107   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
108                         const Diagnostic &Info) override {
109     ++NumDiagnosticsSeen;
110   }
111   unsigned NumDiagnosticsSeen;
112 };
113 } // end namespace
114 
115 TEST(runToolOnCode, FindsClassDecl) {
116   bool FoundClassDeclX = false;
117   EXPECT_TRUE(runToolOnCode(
118       std::make_unique<TestAction>(
119           std::make_unique<FindClassDeclXConsumer>(&FoundClassDeclX)),
120       "class X;"));
121   EXPECT_TRUE(FoundClassDeclX);
122 
123   FoundClassDeclX = false;
124   EXPECT_TRUE(runToolOnCode(
125       std::make_unique<TestAction>(
126           std::make_unique<FindClassDeclXConsumer>(&FoundClassDeclX)),
127       "class Y;"));
128   EXPECT_FALSE(FoundClassDeclX);
129 }
130 
131 TEST(buildASTFromCode, FindsClassDecl) {
132   std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;");
133   ASSERT_TRUE(AST.get());
134   EXPECT_TRUE(FindClassDeclX(AST.get()));
135 
136   AST = buildASTFromCode("class Y;");
137   ASSERT_TRUE(AST.get());
138   EXPECT_FALSE(FindClassDeclX(AST.get()));
139 }
140 
141 TEST(buildASTFromCode, ReportsErrors) {
142   TestDiagnosticConsumer Consumer;
143   std::unique_ptr<ASTUnit> AST = buildASTFromCodeWithArgs(
144       "int x = \"A\";", {}, "input.cc", "clang-tool",
145       std::make_shared<PCHContainerOperations>(),
146       getClangStripDependencyFileAdjuster(), FileContentMappings(), &Consumer);
147   EXPECT_TRUE(AST.get());
148   EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
149 }
150 
151 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
152   std::unique_ptr<FrontendActionFactory> Factory(
153       newFrontendActionFactory<SyntaxOnlyAction>());
154   std::unique_ptr<FrontendAction> Action(Factory->create());
155   EXPECT_TRUE(Action.get() != nullptr);
156 }
157 
158 struct IndependentFrontendActionCreator {
159   std::unique_ptr<ASTConsumer> newASTConsumer() {
160     return std::make_unique<FindTopLevelDeclConsumer>(nullptr);
161   }
162 };
163 
164 TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
165   IndependentFrontendActionCreator Creator;
166   std::unique_ptr<FrontendActionFactory> Factory(
167       newFrontendActionFactory(&Creator));
168   std::unique_ptr<FrontendAction> Action(Factory->create());
169   EXPECT_TRUE(Action.get() != nullptr);
170 }
171 
172 TEST(ToolInvocation, TestMapVirtualFile) {
173   llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
174       new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
175   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
176       new llvm::vfs::InMemoryFileSystem);
177   OverlayFileSystem->pushOverlay(InMemoryFileSystem);
178   llvm::IntrusiveRefCntPtr<FileManager> Files(
179       new FileManager(FileSystemOptions(), OverlayFileSystem));
180   std::vector<std::string> Args;
181   Args.push_back("tool-executable");
182   Args.push_back("-Idef");
183   Args.push_back("-fsyntax-only");
184   Args.push_back("test.cpp");
185   clang::tooling::ToolInvocation Invocation(
186       Args, std::make_unique<SyntaxOnlyAction>(), Files.get());
187   InMemoryFileSystem->addFile(
188       "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n"));
189   InMemoryFileSystem->addFile("def/abc", 0,
190                               llvm::MemoryBuffer::getMemBuffer("\n"));
191   EXPECT_TRUE(Invocation.run());
192 }
193 
194 TEST(ToolInvocation, TestVirtualModulesCompilation) {
195   // FIXME: Currently, this only tests that we don't exit with an error if a
196   // mapped module.map is found on the include path. In the future, expand this
197   // test to run a full modules enabled compilation, so we make sure we can
198   // rerun modules compilations with a virtual file system.
199   llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
200       new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
201   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
202       new llvm::vfs::InMemoryFileSystem);
203   OverlayFileSystem->pushOverlay(InMemoryFileSystem);
204   llvm::IntrusiveRefCntPtr<FileManager> Files(
205       new FileManager(FileSystemOptions(), OverlayFileSystem));
206   std::vector<std::string> Args;
207   Args.push_back("tool-executable");
208   Args.push_back("-Idef");
209   Args.push_back("-fsyntax-only");
210   Args.push_back("test.cpp");
211   clang::tooling::ToolInvocation Invocation(
212       Args, std::make_unique<SyntaxOnlyAction>(), Files.get());
213   InMemoryFileSystem->addFile(
214       "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n"));
215   InMemoryFileSystem->addFile("def/abc", 0,
216                               llvm::MemoryBuffer::getMemBuffer("\n"));
217   // Add a module.map file in the include directory of our header, so we trigger
218   // the module.map header search logic.
219   InMemoryFileSystem->addFile("def/module.map", 0,
220                               llvm::MemoryBuffer::getMemBuffer("\n"));
221   EXPECT_TRUE(Invocation.run());
222 }
223 
224 struct VerifyEndCallback : public SourceFileCallbacks {
225   VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
226   bool handleBeginSource(CompilerInstance &CI) override {
227     ++BeginCalled;
228     return true;
229   }
230   void handleEndSource() override { ++EndCalled; }
231   std::unique_ptr<ASTConsumer> newASTConsumer() {
232     return std::make_unique<FindTopLevelDeclConsumer>(&Matched);
233   }
234   unsigned BeginCalled;
235   unsigned EndCalled;
236   bool Matched;
237 };
238 
239 #if !defined(_WIN32)
240 TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
241   VerifyEndCallback EndCallback;
242 
243   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
244   std::vector<std::string> Sources;
245   Sources.push_back("/a.cc");
246   Sources.push_back("/b.cc");
247   ClangTool Tool(Compilations, Sources);
248 
249   Tool.mapVirtualFile("/a.cc", "void a() {}");
250   Tool.mapVirtualFile("/b.cc", "void b() {}");
251 
252   std::unique_ptr<FrontendActionFactory> Action(
253       newFrontendActionFactory(&EndCallback, &EndCallback));
254   Tool.run(Action.get());
255 
256   EXPECT_TRUE(EndCallback.Matched);
257   EXPECT_EQ(2u, EndCallback.BeginCalled);
258   EXPECT_EQ(2u, EndCallback.EndCalled);
259 }
260 #endif
261 
262 struct SkipBodyConsumer : public clang::ASTConsumer {
263   /// Skip the 'skipMe' function.
264   bool shouldSkipFunctionBody(Decl *D) override {
265     NamedDecl *F = dyn_cast<NamedDecl>(D);
266     return F && F->getNameAsString() == "skipMe";
267   }
268 };
269 
270 struct SkipBodyAction : public clang::ASTFrontendAction {
271   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
272                                                  StringRef) override {
273     Compiler.getFrontendOpts().SkipFunctionBodies = true;
274     return std::make_unique<SkipBodyConsumer>();
275   }
276 };
277 
278 TEST(runToolOnCode, TestSkipFunctionBody) {
279   std::vector<std::string> Args = {"-std=c++11"};
280   std::vector<std::string> Args2 = {"-fno-delayed-template-parsing"};
281 
282   EXPECT_TRUE(runToolOnCode(std::make_unique<SkipBodyAction>(),
283                             "int skipMe() { an_error_here }"));
284   EXPECT_FALSE(runToolOnCode(std::make_unique<SkipBodyAction>(),
285                              "int skipMeNot() { an_error_here }"));
286 
287   // Test constructors with initializers
288   EXPECT_TRUE(runToolOnCodeWithArgs(
289       std::make_unique<SkipBodyAction>(),
290       "struct skipMe { skipMe() : an_error() { more error } };", Args));
291   EXPECT_TRUE(runToolOnCodeWithArgs(
292       std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
293                           "skipMe::skipMe() : an_error([](){;}) { more error }",
294       Args));
295   EXPECT_TRUE(runToolOnCodeWithArgs(
296       std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
297                           "skipMe::skipMe() : an_error{[](){;}} { more error }",
298       Args));
299   EXPECT_TRUE(runToolOnCodeWithArgs(
300       std::make_unique<SkipBodyAction>(),
301       "struct skipMe { skipMe(); };"
302       "skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }",
303       Args));
304   EXPECT_TRUE(runToolOnCodeWithArgs(
305       std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe() : bases()... { error } };",
306       Args));
307 
308   EXPECT_FALSE(runToolOnCodeWithArgs(
309       std::make_unique<SkipBodyAction>(), "struct skipMeNot { skipMeNot() : an_error() { } };",
310       Args));
311   EXPECT_FALSE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(),
312                                      "struct skipMeNot { skipMeNot(); };"
313                                      "skipMeNot::skipMeNot() : an_error() { }",
314                                      Args));
315 
316   // Try/catch
317   EXPECT_TRUE(runToolOnCode(
318       std::make_unique<SkipBodyAction>(),
319       "void skipMe() try { an_error() } catch(error) { error };"));
320   EXPECT_TRUE(runToolOnCode(
321       std::make_unique<SkipBodyAction>(),
322       "struct S { void skipMe() try { an_error() } catch(error) { error } };"));
323   EXPECT_TRUE(
324       runToolOnCode(std::make_unique<SkipBodyAction>(),
325                     "void skipMe() try { an_error() } catch(error) { error; }"
326                     "catch(error) { error } catch (error) { }"));
327   EXPECT_FALSE(runToolOnCode(
328       std::make_unique<SkipBodyAction>(),
329       "void skipMe() try something;")); // don't crash while parsing
330 
331   // Template
332   EXPECT_TRUE(runToolOnCode(
333       std::make_unique<SkipBodyAction>(), "template<typename T> int skipMe() { an_error_here }"
334                           "int x = skipMe<int>();"));
335   EXPECT_FALSE(runToolOnCodeWithArgs(
336       std::make_unique<SkipBodyAction>(),
337       "template<typename T> int skipMeNot() { an_error_here }", Args2));
338 }
339 
340 TEST(runToolOnCodeWithArgs, TestNoDepFile) {
341   llvm::SmallString<32> DepFilePath;
342   ASSERT_FALSE(llvm::sys::fs::getPotentiallyUniqueTempFileName("depfile", "d",
343                                                                DepFilePath));
344   std::vector<std::string> Args;
345   Args.push_back("-MMD");
346   Args.push_back("-MT");
347   Args.push_back(std::string(DepFilePath.str()));
348   Args.push_back("-MF");
349   Args.push_back(std::string(DepFilePath.str()));
350   EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args));
351   EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
352   EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
353 }
354 
355 struct CheckColoredDiagnosticsAction : public clang::ASTFrontendAction {
356   CheckColoredDiagnosticsAction(bool ShouldShowColor)
357       : ShouldShowColor(ShouldShowColor) {}
358   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
359                                                  StringRef) override {
360     if (Compiler.getDiagnosticOpts().ShowColors != ShouldShowColor)
361       Compiler.getDiagnostics().Report(
362           Compiler.getDiagnostics().getCustomDiagID(
363               DiagnosticsEngine::Fatal,
364               "getDiagnosticOpts().ShowColors != ShouldShowColor"));
365     return std::make_unique<ASTConsumer>();
366   }
367 
368 private:
369   bool ShouldShowColor = true;
370 };
371 
372 TEST(runToolOnCodeWithArgs, DiagnosticsColor) {
373   EXPECT_TRUE(runToolOnCodeWithArgs(
374       std::make_unique<CheckColoredDiagnosticsAction>(true), "",
375       {"-fcolor-diagnostics"}));
376   EXPECT_TRUE(runToolOnCodeWithArgs(
377       std::make_unique<CheckColoredDiagnosticsAction>(false), "",
378       {"-fno-color-diagnostics"}));
379   EXPECT_TRUE(runToolOnCodeWithArgs(
380       std::make_unique<CheckColoredDiagnosticsAction>(true), "",
381       {"-fno-color-diagnostics", "-fcolor-diagnostics"}));
382   EXPECT_TRUE(runToolOnCodeWithArgs(
383       std::make_unique<CheckColoredDiagnosticsAction>(false), "",
384       {"-fcolor-diagnostics", "-fno-color-diagnostics"}));
385   EXPECT_TRUE(runToolOnCodeWithArgs(
386       std::make_unique<CheckColoredDiagnosticsAction>(true), "",
387       {"-fno-color-diagnostics", "-fdiagnostics-color=always"}));
388 
389   // Check that this test would fail if ShowColors is not what it should.
390   EXPECT_FALSE(runToolOnCodeWithArgs(
391       std::make_unique<CheckColoredDiagnosticsAction>(false), "",
392       {"-fcolor-diagnostics"}));
393 }
394 
395 TEST(ClangToolTest, ArgumentAdjusters) {
396   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
397 
398   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
399   Tool.mapVirtualFile("/a.cc", "void a() {}");
400 
401   std::unique_ptr<FrontendActionFactory> Action(
402       newFrontendActionFactory<SyntaxOnlyAction>());
403 
404   bool Found = false;
405   bool Ran = false;
406   ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
407       [&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) {
408     Ran = true;
409     if (llvm::is_contained(Args, "-fsyntax-only"))
410       Found = true;
411     return Args;
412   };
413   Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
414   Tool.run(Action.get());
415   EXPECT_TRUE(Ran);
416   EXPECT_TRUE(Found);
417 
418   Ran = Found = false;
419   Tool.clearArgumentsAdjusters();
420   Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
421   Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
422   Tool.run(Action.get());
423   EXPECT_TRUE(Ran);
424   EXPECT_FALSE(Found);
425 }
426 
427 TEST(ClangToolTest, NoDoubleSyntaxOnly) {
428   FixedCompilationDatabase Compilations("/", {"-fsyntax-only"});
429 
430   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
431   Tool.mapVirtualFile("/a.cc", "void a() {}");
432 
433   std::unique_ptr<FrontendActionFactory> Action(
434       newFrontendActionFactory<SyntaxOnlyAction>());
435 
436   size_t SyntaxOnlyCount = 0;
437   ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
438       [&SyntaxOnlyCount](const CommandLineArguments &Args,
439                          StringRef /*unused*/) {
440         for (llvm::StringRef Arg : Args) {
441           if (Arg == "-fsyntax-only")
442             ++SyntaxOnlyCount;
443         }
444         return Args;
445       };
446 
447   Tool.clearArgumentsAdjusters();
448   Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
449   Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
450   Tool.run(Action.get());
451   EXPECT_EQ(SyntaxOnlyCount, 1U);
452 }
453 
454 TEST(ClangToolTest, NoOutputCommands) {
455   FixedCompilationDatabase Compilations("/", {"-save-temps", "-save-temps=cwd",
456                                               "--save-temps",
457                                               "--save-temps=somedir"});
458 
459   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
460   Tool.mapVirtualFile("/a.cc", "void a() {}");
461 
462   std::unique_ptr<FrontendActionFactory> Action(
463       newFrontendActionFactory<SyntaxOnlyAction>());
464 
465   const std::vector<llvm::StringRef> OutputCommands = {"-save-temps"};
466   bool Ran = false;
467   ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
468       [&OutputCommands, &Ran](const CommandLineArguments &Args,
469                               StringRef /*unused*/) {
470         for (llvm::StringRef Arg : Args) {
471           for (llvm::StringRef OutputCommand : OutputCommands)
472             EXPECT_FALSE(Arg.contains(OutputCommand));
473         }
474         Ran = true;
475         return Args;
476       };
477 
478   Tool.clearArgumentsAdjusters();
479   Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
480   Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
481   Tool.run(Action.get());
482   EXPECT_TRUE(Ran);
483 }
484 
485 TEST(ClangToolTest, BaseVirtualFileSystemUsage) {
486   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
487   llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
488       new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
489   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
490       new llvm::vfs::InMemoryFileSystem);
491   OverlayFileSystem->pushOverlay(InMemoryFileSystem);
492 
493   InMemoryFileSystem->addFile(
494       "a.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}"));
495 
496   ClangTool Tool(Compilations, std::vector<std::string>(1, "a.cpp"),
497                  std::make_shared<PCHContainerOperations>(), OverlayFileSystem);
498   std::unique_ptr<FrontendActionFactory> Action(
499       newFrontendActionFactory<SyntaxOnlyAction>());
500   EXPECT_EQ(0, Tool.run(Action.get()));
501 }
502 
503 // Check getClangStripDependencyFileAdjuster doesn't strip args after -MD/-MMD.
504 TEST(ClangToolTest, StripDependencyFileAdjuster) {
505   FixedCompilationDatabase Compilations("/", {"-MD", "-c", "-MMD", "-w"});
506 
507   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
508   Tool.mapVirtualFile("/a.cc", "void a() {}");
509 
510   std::unique_ptr<FrontendActionFactory> Action(
511       newFrontendActionFactory<SyntaxOnlyAction>());
512 
513   CommandLineArguments FinalArgs;
514   ArgumentsAdjuster CheckFlagsAdjuster =
515     [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
516       FinalArgs = Args;
517       return Args;
518     };
519   Tool.clearArgumentsAdjusters();
520   Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
521   Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
522   Tool.run(Action.get());
523 
524   auto HasFlag = [&FinalArgs](const std::string &Flag) {
525     return llvm::find(FinalArgs, Flag) != FinalArgs.end();
526   };
527   EXPECT_FALSE(HasFlag("-MD"));
528   EXPECT_FALSE(HasFlag("-MMD"));
529   EXPECT_TRUE(HasFlag("-c"));
530   EXPECT_TRUE(HasFlag("-w"));
531 }
532 
533 // Check getClangStripDependencyFileAdjuster strips /showIncludes and variants
534 TEST(ClangToolTest, StripDependencyFileAdjusterShowIncludes) {
535   FixedCompilationDatabase Compilations(
536       "/", {"/showIncludes", "/showIncludes:user", "-showIncludes",
537             "-showIncludes:user", "-c"});
538 
539   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
540   Tool.mapVirtualFile("/a.cc", "void a() {}");
541 
542   std::unique_ptr<FrontendActionFactory> Action(
543       newFrontendActionFactory<SyntaxOnlyAction>());
544 
545   CommandLineArguments FinalArgs;
546   ArgumentsAdjuster CheckFlagsAdjuster =
547       [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
548         FinalArgs = Args;
549         return Args;
550       };
551   Tool.clearArgumentsAdjusters();
552   Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
553   Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
554   Tool.run(Action.get());
555 
556   auto HasFlag = [&FinalArgs](const std::string &Flag) {
557     return llvm::find(FinalArgs, Flag) != FinalArgs.end();
558   };
559   EXPECT_FALSE(HasFlag("/showIncludes"));
560   EXPECT_FALSE(HasFlag("/showIncludes:user"));
561   EXPECT_FALSE(HasFlag("-showIncludes"));
562   EXPECT_FALSE(HasFlag("-showIncludes:user"));
563   EXPECT_TRUE(HasFlag("-c"));
564 }
565 
566 // Check getClangStripDependencyFileAdjuster doesn't strip args when using the
567 // MSVC cl.exe driver
568 TEST(ClangToolTest, StripDependencyFileAdjusterMsvc) {
569   FixedCompilationDatabase Compilations(
570       "/", {"--driver-mode=cl", "-MD", "-MDd", "-MT", "-O1", "-MTd", "-MP"});
571 
572   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
573   Tool.mapVirtualFile("/a.cc", "void a() {}");
574 
575   std::unique_ptr<FrontendActionFactory> Action(
576       newFrontendActionFactory<SyntaxOnlyAction>());
577 
578   CommandLineArguments FinalArgs;
579   ArgumentsAdjuster CheckFlagsAdjuster =
580       [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
581         FinalArgs = Args;
582         return Args;
583       };
584   Tool.clearArgumentsAdjusters();
585   Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
586   Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
587   Tool.run(Action.get());
588 
589   auto HasFlag = [&FinalArgs](const std::string &Flag) {
590     return llvm::find(FinalArgs, Flag) != FinalArgs.end();
591   };
592   EXPECT_TRUE(HasFlag("-MD"));
593   EXPECT_TRUE(HasFlag("-MDd"));
594   EXPECT_TRUE(HasFlag("-MT"));
595   EXPECT_TRUE(HasFlag("-O1"));
596   EXPECT_TRUE(HasFlag("-MTd"));
597   EXPECT_TRUE(HasFlag("-MP"));
598 }
599 
600 // Check getClangStripPluginsAdjuster strips plugin related args.
601 TEST(ClangToolTest, StripPluginsAdjuster) {
602   FixedCompilationDatabase Compilations(
603       "/", {"-Xclang", "-add-plugin", "-Xclang", "random-plugin"});
604 
605   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
606   Tool.mapVirtualFile("/a.cc", "void a() {}");
607 
608   std::unique_ptr<FrontendActionFactory> Action(
609       newFrontendActionFactory<SyntaxOnlyAction>());
610 
611   CommandLineArguments FinalArgs;
612   ArgumentsAdjuster CheckFlagsAdjuster =
613       [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
614         FinalArgs = Args;
615         return Args;
616       };
617   Tool.clearArgumentsAdjusters();
618   Tool.appendArgumentsAdjuster(getStripPluginsAdjuster());
619   Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
620   Tool.run(Action.get());
621 
622   auto HasFlag = [&FinalArgs](const std::string &Flag) {
623     return llvm::find(FinalArgs, Flag) != FinalArgs.end();
624   };
625   EXPECT_FALSE(HasFlag("-Xclang"));
626   EXPECT_FALSE(HasFlag("-add-plugin"));
627   EXPECT_FALSE(HasFlag("-random-plugin"));
628 }
629 
630 namespace {
631 /// Find a target name such that looking for it in TargetRegistry by that name
632 /// returns the same target. We expect that there is at least one target
633 /// configured with this property.
634 std::string getAnyTarget() {
635   llvm::InitializeAllTargets();
636   for (const auto &Target : llvm::TargetRegistry::targets()) {
637     std::string Error;
638     StringRef TargetName(Target.getName());
639     if (TargetName == "x86-64")
640       TargetName = "x86_64";
641     if (llvm::TargetRegistry::lookupTarget(std::string(TargetName), Error) ==
642         &Target) {
643       return std::string(TargetName);
644     }
645   }
646   return "";
647 }
648 }
649 
650 TEST(addTargetAndModeForProgramName, AddsTargetAndMode) {
651   std::string Target = getAnyTarget();
652   ASSERT_FALSE(Target.empty());
653 
654   std::vector<std::string> Args = {"clang", "-foo"};
655   addTargetAndModeForProgramName(Args, "");
656   EXPECT_EQ((std::vector<std::string>{"clang", "-foo"}), Args);
657   addTargetAndModeForProgramName(Args, Target + "-g++");
658   EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target,
659                                       "--driver-mode=g++", "-foo"}),
660             Args);
661 }
662 
663 TEST(addTargetAndModeForProgramName, PathIgnored) {
664   std::string Target = getAnyTarget();
665   ASSERT_FALSE(Target.empty());
666 
667   SmallString<32> ToolPath;
668   llvm::sys::path::append(ToolPath, "foo", "bar", Target + "-g++");
669 
670   std::vector<std::string> Args = {"clang", "-foo"};
671   addTargetAndModeForProgramName(Args, ToolPath);
672   EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target,
673                                       "--driver-mode=g++", "-foo"}),
674             Args);
675 }
676 
677 TEST(addTargetAndModeForProgramName, IgnoresExistingTarget) {
678   std::string Target = getAnyTarget();
679   ASSERT_FALSE(Target.empty());
680 
681   std::vector<std::string> Args = {"clang", "-foo", "-target", "something"};
682   addTargetAndModeForProgramName(Args, Target + "-g++");
683   EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo",
684                                       "-target", "something"}),
685             Args);
686 
687   std::vector<std::string> ArgsAlt = {"clang", "-foo", "--target=something"};
688   addTargetAndModeForProgramName(ArgsAlt, Target + "-g++");
689   EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo",
690                                       "--target=something"}),
691             ArgsAlt);
692 }
693 
694 TEST(addTargetAndModeForProgramName, IgnoresExistingMode) {
695   std::string Target = getAnyTarget();
696   ASSERT_FALSE(Target.empty());
697 
698   std::vector<std::string> Args = {"clang", "-foo", "--driver-mode=abc"};
699   addTargetAndModeForProgramName(Args, Target + "-g++");
700   EXPECT_EQ((std::vector<std::string>{"clang", "--target=" + Target, "-foo",
701                                       "--driver-mode=abc"}),
702             Args);
703 }
704 
705 #ifndef _WIN32
706 TEST(ClangToolTest, BuildASTs) {
707   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
708 
709   std::vector<std::string> Sources;
710   Sources.push_back("/a.cc");
711   Sources.push_back("/b.cc");
712   ClangTool Tool(Compilations, Sources);
713 
714   Tool.mapVirtualFile("/a.cc", "void a() {}");
715   Tool.mapVirtualFile("/b.cc", "void b() {}");
716 
717   std::vector<std::unique_ptr<ASTUnit>> ASTs;
718   EXPECT_EQ(0, Tool.buildASTs(ASTs));
719   EXPECT_EQ(2u, ASTs.size());
720 }
721 
722 TEST(ClangToolTest, InjectDiagnosticConsumer) {
723   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
724   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
725   Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
726   TestDiagnosticConsumer Consumer;
727   Tool.setDiagnosticConsumer(&Consumer);
728   std::unique_ptr<FrontendActionFactory> Action(
729       newFrontendActionFactory<SyntaxOnlyAction>());
730   Tool.run(Action.get());
731   EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
732 }
733 
734 TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
735   FixedCompilationDatabase Compilations("/", std::vector<std::string>());
736   ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
737   Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
738   TestDiagnosticConsumer Consumer;
739   Tool.setDiagnosticConsumer(&Consumer);
740   std::vector<std::unique_ptr<ASTUnit>> ASTs;
741   Tool.buildASTs(ASTs);
742   EXPECT_EQ(1u, ASTs.size());
743   EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
744 }
745 #endif
746 
747 TEST(runToolOnCode, TestResetDiagnostics) {
748   // This is a tool that resets the diagnostic during the compilation.
749   struct ResetDiagnosticAction : public clang::ASTFrontendAction {
750     std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
751                                                    StringRef) override {
752       struct Consumer : public clang::ASTConsumer {
753         bool HandleTopLevelDecl(clang::DeclGroupRef D) override {
754           auto &Diags = (*D.begin())->getASTContext().getDiagnostics();
755           // Ignore any error
756           Diags.Reset();
757           // Disable warnings because computing the CFG might crash.
758           Diags.setIgnoreAllWarnings(true);
759           return true;
760         }
761       };
762       return std::make_unique<Consumer>();
763     }
764   };
765 
766   // Should not crash
767   EXPECT_FALSE(
768       runToolOnCode(std::make_unique<ResetDiagnosticAction>(),
769                     "struct Foo { Foo(int); ~Foo(); struct Fwd _fwd; };"
770                     "void func() { long x; Foo f(x); }"));
771 }
772 
773 } // end namespace tooling
774 } // end namespace clang
775