ToolingTest.cpp 24 KB

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