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