FrontendActionTest.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. //===- unittests/Frontend/FrontendActionTest.cpp - FrontendAction 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/Frontend/FrontendAction.h"
  10. #include "clang/AST/ASTConsumer.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/AST/RecursiveASTVisitor.h"
  13. #include "clang/Frontend/CompilerInstance.h"
  14. #include "clang/Frontend/CompilerInvocation.h"
  15. #include "clang/Lex/Preprocessor.h"
  16. #include "clang/Sema/Sema.h"
  17. #include "llvm/ADT/Triple.h"
  18. #include "llvm/Support/MemoryBuffer.h"
  19. #include "gtest/gtest.h"
  20. using namespace llvm;
  21. using namespace clang;
  22. namespace {
  23. class TestASTFrontendAction : public ASTFrontendAction {
  24. public:
  25. TestASTFrontendAction(bool enableIncrementalProcessing = false,
  26. bool actOnEndOfTranslationUnit = false)
  27. : EnableIncrementalProcessing(enableIncrementalProcessing),
  28. ActOnEndOfTranslationUnit(actOnEndOfTranslationUnit) { }
  29. bool EnableIncrementalProcessing;
  30. bool ActOnEndOfTranslationUnit;
  31. std::vector<std::string> decl_names;
  32. bool BeginSourceFileAction(CompilerInstance &ci,
  33. StringRef filename) override {
  34. if (EnableIncrementalProcessing)
  35. ci.getPreprocessor().enableIncrementalProcessing();
  36. return ASTFrontendAction::BeginSourceFileAction(ci, filename);
  37. }
  38. std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
  39. StringRef InFile) override {
  40. return llvm::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit,
  41. decl_names);
  42. }
  43. private:
  44. class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> {
  45. public:
  46. Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit,
  47. std::vector<std::string> &decl_names) :
  48. CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit),
  49. decl_names_(decl_names) {}
  50. void HandleTranslationUnit(ASTContext &context) override {
  51. if (ActOnEndOfTranslationUnit) {
  52. CI.getSema().ActOnEndOfTranslationUnit();
  53. }
  54. TraverseDecl(context.getTranslationUnitDecl());
  55. }
  56. virtual bool VisitNamedDecl(NamedDecl *Decl) {
  57. decl_names_.push_back(Decl->getQualifiedNameAsString());
  58. return true;
  59. }
  60. private:
  61. CompilerInstance &CI;
  62. bool ActOnEndOfTranslationUnit;
  63. std::vector<std::string> &decl_names_;
  64. };
  65. };
  66. TEST(ASTFrontendAction, Sanity) {
  67. CompilerInvocation *invocation = new CompilerInvocation;
  68. invocation->getPreprocessorOpts().addRemappedFile(
  69. "test.cc",
  70. MemoryBuffer::getMemBuffer("int main() { float x; }").release());
  71. invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
  72. IK_CXX));
  73. invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
  74. invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
  75. CompilerInstance compiler;
  76. compiler.setInvocation(invocation);
  77. compiler.createDiagnostics();
  78. TestASTFrontendAction test_action;
  79. ASSERT_TRUE(compiler.ExecuteAction(test_action));
  80. ASSERT_EQ(2U, test_action.decl_names.size());
  81. EXPECT_EQ("main", test_action.decl_names[0]);
  82. EXPECT_EQ("x", test_action.decl_names[1]);
  83. }
  84. TEST(ASTFrontendAction, IncrementalParsing) {
  85. CompilerInvocation *invocation = new CompilerInvocation;
  86. invocation->getPreprocessorOpts().addRemappedFile(
  87. "test.cc",
  88. MemoryBuffer::getMemBuffer("int main() { float x; }").release());
  89. invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
  90. IK_CXX));
  91. invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
  92. invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
  93. CompilerInstance compiler;
  94. compiler.setInvocation(invocation);
  95. compiler.createDiagnostics();
  96. TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true);
  97. ASSERT_TRUE(compiler.ExecuteAction(test_action));
  98. ASSERT_EQ(2U, test_action.decl_names.size());
  99. EXPECT_EQ("main", test_action.decl_names[0]);
  100. EXPECT_EQ("x", test_action.decl_names[1]);
  101. }
  102. TEST(ASTFrontendAction, LateTemplateIncrementalParsing) {
  103. CompilerInvocation *invocation = new CompilerInvocation;
  104. invocation->getLangOpts()->CPlusPlus = true;
  105. invocation->getLangOpts()->DelayedTemplateParsing = true;
  106. invocation->getPreprocessorOpts().addRemappedFile(
  107. "test.cc", MemoryBuffer::getMemBuffer(
  108. "template<typename T> struct A { A(T); T data; };\n"
  109. "template<typename T> struct B: public A<T> {\n"
  110. " B();\n"
  111. " B(B const& b): A<T>(b.data) {}\n"
  112. "};\n"
  113. "B<char> c() { return B<char>(); }\n").release());
  114. invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
  115. IK_CXX));
  116. invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
  117. invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
  118. CompilerInstance compiler;
  119. compiler.setInvocation(invocation);
  120. compiler.createDiagnostics();
  121. TestASTFrontendAction test_action(/*enableIncrementalProcessing=*/true,
  122. /*actOnEndOfTranslationUnit=*/true);
  123. ASSERT_TRUE(compiler.ExecuteAction(test_action));
  124. ASSERT_EQ(13U, test_action.decl_names.size());
  125. EXPECT_EQ("A", test_action.decl_names[0]);
  126. EXPECT_EQ("c", test_action.decl_names[12]);
  127. }
  128. struct TestPPCallbacks : public PPCallbacks {
  129. TestPPCallbacks() : SeenEnd(false) {}
  130. void EndOfMainFile() override { SeenEnd = true; }
  131. bool SeenEnd;
  132. };
  133. class TestPPCallbacksFrontendAction : public PreprocessorFrontendAction {
  134. TestPPCallbacks *Callbacks;
  135. public:
  136. TestPPCallbacksFrontendAction(TestPPCallbacks *C)
  137. : Callbacks(C), SeenEnd(false) {}
  138. void ExecuteAction() override {
  139. Preprocessor &PP = getCompilerInstance().getPreprocessor();
  140. PP.addPPCallbacks(std::unique_ptr<TestPPCallbacks>(Callbacks));
  141. PP.EnterMainSourceFile();
  142. }
  143. void EndSourceFileAction() override { SeenEnd = Callbacks->SeenEnd; }
  144. bool SeenEnd;
  145. };
  146. TEST(PreprocessorFrontendAction, EndSourceFile) {
  147. CompilerInvocation *Invocation = new CompilerInvocation;
  148. Invocation->getPreprocessorOpts().addRemappedFile(
  149. "test.cc",
  150. MemoryBuffer::getMemBuffer("int main() { float x; }").release());
  151. Invocation->getFrontendOpts().Inputs.push_back(
  152. FrontendInputFile("test.cc", IK_CXX));
  153. Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
  154. Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
  155. CompilerInstance Compiler;
  156. Compiler.setInvocation(Invocation);
  157. Compiler.createDiagnostics();
  158. TestPPCallbacks *Callbacks = new TestPPCallbacks;
  159. TestPPCallbacksFrontendAction TestAction(Callbacks);
  160. ASSERT_FALSE(Callbacks->SeenEnd);
  161. ASSERT_FALSE(TestAction.SeenEnd);
  162. ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
  163. // Check that EndOfMainFile was called before EndSourceFileAction.
  164. ASSERT_TRUE(TestAction.SeenEnd);
  165. }
  166. } // anonymous namespace