ToolingTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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 "gtest/gtest.h"
  21. #include <algorithm>
  22. #include <string>
  23. namespace clang {
  24. namespace tooling {
  25. namespace {
  26. /// Takes an ast consumer and returns it from CreateASTConsumer. This only
  27. /// works with single translation unit compilations.
  28. class TestAction : public clang::ASTFrontendAction {
  29. public:
  30. /// Takes ownership of TestConsumer.
  31. explicit TestAction(std::unique_ptr<clang::ASTConsumer> TestConsumer)
  32. : TestConsumer(std::move(TestConsumer)) {}
  33. protected:
  34. std::unique_ptr<clang::ASTConsumer>
  35. CreateASTConsumer(clang::CompilerInstance &compiler,
  36. StringRef dummy) override {
  37. /// TestConsumer will be deleted by the framework calling us.
  38. return std::move(TestConsumer);
  39. }
  40. private:
  41. std::unique_ptr<clang::ASTConsumer> TestConsumer;
  42. };
  43. class FindTopLevelDeclConsumer : public clang::ASTConsumer {
  44. public:
  45. explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
  46. : FoundTopLevelDecl(FoundTopLevelDecl) {}
  47. bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
  48. *FoundTopLevelDecl = true;
  49. return true;
  50. }
  51. private:
  52. bool * const FoundTopLevelDecl;
  53. };
  54. } // end namespace
  55. TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
  56. bool FoundTopLevelDecl = false;
  57. EXPECT_TRUE(
  58. runToolOnCode(new TestAction(llvm::make_unique<FindTopLevelDeclConsumer>(
  59. &FoundTopLevelDecl)),
  60. ""));
  61. EXPECT_FALSE(FoundTopLevelDecl);
  62. }
  63. namespace {
  64. class FindClassDeclXConsumer : public clang::ASTConsumer {
  65. public:
  66. FindClassDeclXConsumer(bool *FoundClassDeclX)
  67. : FoundClassDeclX(FoundClassDeclX) {}
  68. bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
  69. if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
  70. *GroupRef.begin())) {
  71. if (Record->getName() == "X") {
  72. *FoundClassDeclX = true;
  73. }
  74. }
  75. return true;
  76. }
  77. private:
  78. bool *FoundClassDeclX;
  79. };
  80. bool FindClassDeclX(ASTUnit *AST) {
  81. for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
  82. e = AST->top_level_end();
  83. i != e; ++i) {
  84. if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
  85. if (Record->getName() == "X") {
  86. return true;
  87. }
  88. }
  89. }
  90. return false;
  91. }
  92. } // end namespace
  93. TEST(runToolOnCode, FindsClassDecl) {
  94. bool FoundClassDeclX = false;
  95. EXPECT_TRUE(
  96. runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
  97. &FoundClassDeclX)),
  98. "class X;"));
  99. EXPECT_TRUE(FoundClassDeclX);
  100. FoundClassDeclX = false;
  101. EXPECT_TRUE(
  102. runToolOnCode(new TestAction(llvm::make_unique<FindClassDeclXConsumer>(
  103. &FoundClassDeclX)),
  104. "class Y;"));
  105. EXPECT_FALSE(FoundClassDeclX);
  106. }
  107. TEST(buildASTFromCode, FindsClassDecl) {
  108. std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;");
  109. ASSERT_TRUE(AST.get());
  110. EXPECT_TRUE(FindClassDeclX(AST.get()));
  111. AST = buildASTFromCode("class Y;");
  112. ASSERT_TRUE(AST.get());
  113. EXPECT_FALSE(FindClassDeclX(AST.get()));
  114. }
  115. TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
  116. std::unique_ptr<FrontendActionFactory> Factory(
  117. newFrontendActionFactory<SyntaxOnlyAction>());
  118. std::unique_ptr<FrontendAction> Action(Factory->create());
  119. EXPECT_TRUE(Action.get() != nullptr);
  120. }
  121. struct IndependentFrontendActionCreator {
  122. std::unique_ptr<ASTConsumer> newASTConsumer() {
  123. return llvm::make_unique<FindTopLevelDeclConsumer>(nullptr);
  124. }
  125. };
  126. TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
  127. IndependentFrontendActionCreator Creator;
  128. std::unique_ptr<FrontendActionFactory> Factory(
  129. newFrontendActionFactory(&Creator));
  130. std::unique_ptr<FrontendAction> Action(Factory->create());
  131. EXPECT_TRUE(Action.get() != nullptr);
  132. }
  133. TEST(ToolInvocation, TestMapVirtualFile) {
  134. IntrusiveRefCntPtr<clang::FileManager> Files(
  135. new clang::FileManager(clang::FileSystemOptions()));
  136. std::vector<std::string> Args;
  137. Args.push_back("tool-executable");
  138. Args.push_back("-Idef");
  139. Args.push_back("-fsyntax-only");
  140. Args.push_back("test.cpp");
  141. clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
  142. Files.get());
  143. Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
  144. Invocation.mapVirtualFile("def/abc", "\n");
  145. EXPECT_TRUE(Invocation.run());
  146. }
  147. TEST(ToolInvocation, TestVirtualModulesCompilation) {
  148. // FIXME: Currently, this only tests that we don't exit with an error if a
  149. // mapped module.map is found on the include path. In the future, expand this
  150. // test to run a full modules enabled compilation, so we make sure we can
  151. // rerun modules compilations with a virtual file system.
  152. IntrusiveRefCntPtr<clang::FileManager> Files(
  153. new clang::FileManager(clang::FileSystemOptions()));
  154. std::vector<std::string> Args;
  155. Args.push_back("tool-executable");
  156. Args.push_back("-Idef");
  157. Args.push_back("-fsyntax-only");
  158. Args.push_back("test.cpp");
  159. clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
  160. Files.get());
  161. Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
  162. Invocation.mapVirtualFile("def/abc", "\n");
  163. // Add a module.map file in the include directory of our header, so we trigger
  164. // the module.map header search logic.
  165. Invocation.mapVirtualFile("def/module.map", "\n");
  166. EXPECT_TRUE(Invocation.run());
  167. }
  168. struct VerifyEndCallback : public SourceFileCallbacks {
  169. VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
  170. bool handleBeginSource(CompilerInstance &CI, StringRef Filename) override {
  171. ++BeginCalled;
  172. return true;
  173. }
  174. void handleEndSource() override { ++EndCalled; }
  175. std::unique_ptr<ASTConsumer> newASTConsumer() {
  176. return llvm::make_unique<FindTopLevelDeclConsumer>(&Matched);
  177. }
  178. unsigned BeginCalled;
  179. unsigned EndCalled;
  180. bool Matched;
  181. };
  182. #if !defined(LLVM_ON_WIN32)
  183. TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
  184. VerifyEndCallback EndCallback;
  185. FixedCompilationDatabase Compilations("/", std::vector<std::string>());
  186. std::vector<std::string> Sources;
  187. Sources.push_back("/a.cc");
  188. Sources.push_back("/b.cc");
  189. ClangTool Tool(Compilations, Sources);
  190. Tool.mapVirtualFile("/a.cc", "void a() {}");
  191. Tool.mapVirtualFile("/b.cc", "void b() {}");
  192. std::unique_ptr<FrontendActionFactory> Action(
  193. newFrontendActionFactory(&EndCallback, &EndCallback));
  194. Tool.run(Action.get());
  195. EXPECT_TRUE(EndCallback.Matched);
  196. EXPECT_EQ(2u, EndCallback.BeginCalled);
  197. EXPECT_EQ(2u, EndCallback.EndCalled);
  198. }
  199. #endif
  200. struct SkipBodyConsumer : public clang::ASTConsumer {
  201. /// Skip the 'skipMe' function.
  202. bool shouldSkipFunctionBody(Decl *D) override {
  203. FunctionDecl *F = dyn_cast<FunctionDecl>(D);
  204. return F && F->getNameAsString() == "skipMe";
  205. }
  206. };
  207. struct SkipBodyAction : public clang::ASTFrontendAction {
  208. std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
  209. StringRef) override {
  210. Compiler.getFrontendOpts().SkipFunctionBodies = true;
  211. return llvm::make_unique<SkipBodyConsumer>();
  212. }
  213. };
  214. TEST(runToolOnCode, TestSkipFunctionBody) {
  215. EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
  216. "int skipMe() { an_error_here }"));
  217. EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
  218. "int skipMeNot() { an_error_here }"));
  219. }
  220. TEST(runToolOnCodeWithArgs, TestNoDepFile) {
  221. llvm::SmallString<32> DepFilePath;
  222. ASSERT_FALSE(
  223. llvm::sys::fs::createTemporaryFile("depfile", "d", DepFilePath));
  224. std::vector<std::string> Args;
  225. Args.push_back("-MMD");
  226. Args.push_back("-MT");
  227. Args.push_back(DepFilePath.str());
  228. Args.push_back("-MF");
  229. Args.push_back(DepFilePath.str());
  230. EXPECT_TRUE(runToolOnCodeWithArgs(new SkipBodyAction, "", Args));
  231. EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
  232. EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
  233. }
  234. TEST(ClangToolTest, ArgumentAdjusters) {
  235. FixedCompilationDatabase Compilations("/", std::vector<std::string>());
  236. ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
  237. Tool.mapVirtualFile("/a.cc", "void a() {}");
  238. std::unique_ptr<FrontendActionFactory> Action(
  239. newFrontendActionFactory<SyntaxOnlyAction>());
  240. bool Found = false;
  241. bool Ran = false;
  242. ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
  243. [&Found, &Ran](const CommandLineArguments &Args) {
  244. Ran = true;
  245. if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end())
  246. Found = true;
  247. return Args;
  248. };
  249. Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
  250. Tool.run(Action.get());
  251. EXPECT_TRUE(Ran);
  252. EXPECT_TRUE(Found);
  253. Ran = Found = false;
  254. Tool.clearArgumentsAdjusters();
  255. Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
  256. Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
  257. Tool.run(Action.get());
  258. EXPECT_TRUE(Ran);
  259. EXPECT_FALSE(Found);
  260. }
  261. #ifndef LLVM_ON_WIN32
  262. TEST(ClangToolTest, BuildASTs) {
  263. FixedCompilationDatabase Compilations("/", std::vector<std::string>());
  264. std::vector<std::string> Sources;
  265. Sources.push_back("/a.cc");
  266. Sources.push_back("/b.cc");
  267. ClangTool Tool(Compilations, Sources);
  268. Tool.mapVirtualFile("/a.cc", "void a() {}");
  269. Tool.mapVirtualFile("/b.cc", "void b() {}");
  270. std::vector<std::unique_ptr<ASTUnit>> ASTs;
  271. EXPECT_EQ(0, Tool.buildASTs(ASTs));
  272. EXPECT_EQ(2u, ASTs.size());
  273. }
  274. struct TestDiagnosticConsumer : public DiagnosticConsumer {
  275. TestDiagnosticConsumer() : NumDiagnosticsSeen(0) {}
  276. void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
  277. const Diagnostic &Info) override {
  278. ++NumDiagnosticsSeen;
  279. }
  280. unsigned NumDiagnosticsSeen;
  281. };
  282. TEST(ClangToolTest, InjectDiagnosticConsumer) {
  283. FixedCompilationDatabase Compilations("/", std::vector<std::string>());
  284. ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
  285. Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
  286. TestDiagnosticConsumer Consumer;
  287. Tool.setDiagnosticConsumer(&Consumer);
  288. std::unique_ptr<FrontendActionFactory> Action(
  289. newFrontendActionFactory<SyntaxOnlyAction>());
  290. Tool.run(Action.get());
  291. EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
  292. }
  293. TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
  294. FixedCompilationDatabase Compilations("/", std::vector<std::string>());
  295. ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
  296. Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
  297. TestDiagnosticConsumer Consumer;
  298. Tool.setDiagnosticConsumer(&Consumer);
  299. std::vector<std::unique_ptr<ASTUnit>> ASTs;
  300. Tool.buildASTs(ASTs);
  301. EXPECT_EQ(1u, ASTs.size());
  302. EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
  303. }
  304. #endif
  305. } // end namespace tooling
  306. } // end namespace clang