ToolingTest.cpp 22 KB

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