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