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