blob: 5581c4487ecca3d4c9f72815070359c4619216fd [file] [log] [blame]
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +00001//===- 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
Chandler Carruth320d9662012-12-04 09:45:34 +000010#include "clang/Frontend/FrontendAction.h"
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000011#include "clang/AST/ASTConsumer.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000012#include "clang/AST/ASTContext.h"
Chandler Carruthfa0b3bb2012-12-04 09:53:37 +000013#include "clang/AST/RecursiveASTVisitor.h"
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000014#include "clang/Frontend/CompilerInstance.h"
15#include "clang/Frontend/CompilerInvocation.h"
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +000016#include "clang/Lex/Preprocessor.h"
Reid Kleckner89bd8d62014-10-22 17:50:19 +000017#include "clang/Sema/Sema.h"
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000018#include "llvm/ADT/Triple.h"
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000019#include "llvm/Support/MemoryBuffer.h"
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000020#include "gtest/gtest.h"
21
22using namespace llvm;
23using namespace clang;
24
25namespace {
26
27class TestASTFrontendAction : public ASTFrontendAction {
28public:
Reid Kleckner89bd8d62014-10-22 17:50:19 +000029 TestASTFrontendAction(bool enableIncrementalProcessing = false,
30 bool actOnEndOfTranslationUnit = false)
31 : EnableIncrementalProcessing(enableIncrementalProcessing),
32 ActOnEndOfTranslationUnit(actOnEndOfTranslationUnit) { }
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +000033
34 bool EnableIncrementalProcessing;
Reid Kleckner89bd8d62014-10-22 17:50:19 +000035 bool ActOnEndOfTranslationUnit;
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000036 std::vector<std::string> decl_names;
37
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +000038 virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) {
39 if (EnableIncrementalProcessing)
40 ci.getPreprocessor().enableIncrementalProcessing();
41
42 return ASTFrontendAction::BeginSourceFileAction(ci, filename);
43 }
44
David Blaikie6beb6aa2014-08-10 19:56:51 +000045 virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
46 StringRef InFile) {
Reid Kleckner89bd8d62014-10-22 17:50:19 +000047 return llvm::make_unique<Visitor>(CI, ActOnEndOfTranslationUnit,
48 decl_names);
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000049 }
50
51private:
52 class Visitor : public ASTConsumer, public RecursiveASTVisitor<Visitor> {
53 public:
Reid Kleckner89bd8d62014-10-22 17:50:19 +000054 Visitor(CompilerInstance &CI, bool ActOnEndOfTranslationUnit,
55 std::vector<std::string> &decl_names) :
56 CI(CI), ActOnEndOfTranslationUnit(ActOnEndOfTranslationUnit),
57 decl_names_(decl_names) {}
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000058
59 virtual void HandleTranslationUnit(ASTContext &context) {
Reid Kleckner89bd8d62014-10-22 17:50:19 +000060 if (ActOnEndOfTranslationUnit) {
61 CI.getSema().ActOnEndOfTranslationUnit();
62 }
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000063 TraverseDecl(context.getTranslationUnitDecl());
64 }
65
66 virtual bool VisitNamedDecl(NamedDecl *Decl) {
67 decl_names_.push_back(Decl->getQualifiedNameAsString());
68 return true;
69 }
70
71 private:
Reid Kleckner89bd8d62014-10-22 17:50:19 +000072 CompilerInstance &CI;
73 bool ActOnEndOfTranslationUnit;
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000074 std::vector<std::string> &decl_names_;
75 };
76};
77
78TEST(ASTFrontendAction, Sanity) {
79 CompilerInvocation *invocation = new CompilerInvocation;
80 invocation->getPreprocessorOpts().addRemappedFile(
Rafael Espindolad87f8d72014-08-27 20:03:29 +000081 "test.cc",
82 MemoryBuffer::getMemBuffer("int main() { float x; }").release());
Douglas Gregord6a58282012-01-20 16:33:00 +000083 invocation->getFrontendOpts().Inputs.push_back(FrontendInputFile("test.cc",
84 IK_CXX));
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000085 invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
86 invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
87 CompilerInstance compiler;
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000088 compiler.setInvocation(invocation);
Sean Silvaf1b49e22013-01-20 01:58:28 +000089 compiler.createDiagnostics();
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000090
91 TestASTFrontendAction test_action;
92 ASSERT_TRUE(compiler.ExecuteAction(test_action));
Alp Toker56b5cc92013-12-15 10:36:26 +000093 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]);
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +000096}
97
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +000098TEST(ASTFrontendAction, IncrementalParsing) {
99 CompilerInvocation *invocation = new CompilerInvocation;
100 invocation->getPreprocessorOpts().addRemappedFile(
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000101 "test.cc",
102 MemoryBuffer::getMemBuffer("int main() { float x; }").release());
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +0000103 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));
Alp Toker56b5cc92013-12-15 10:36:26 +0000113 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]);
Argyrios Kyrtzidis336fcd92013-11-24 02:12:18 +0000116}
117
Reid Kleckner89bd8d62014-10-22 17:50:19 +0000118TEST(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
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000146struct TestPPCallbacks : public PPCallbacks {
147 TestPPCallbacks() : SeenEnd(false) {}
148
149 void EndOfMainFile() override { SeenEnd = true; }
150
151 bool SeenEnd;
152};
153
154class TestPPCallbacksFrontendAction : public PreprocessorFrontendAction {
Benjamin Kramera2406fa2014-09-10 09:35:49 +0000155 TestPPCallbacks *Callbacks;
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000156
157public:
Benjamin Kramera2406fa2014-09-10 09:35:49 +0000158 TestPPCallbacksFrontendAction(TestPPCallbacks *C)
159 : Callbacks(C), SeenEnd(false) {}
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000160
161 void ExecuteAction() override {
162 Preprocessor &PP = getCompilerInstance().getPreprocessor();
Benjamin Kramera2406fa2014-09-10 09:35:49 +0000163 PP.addPPCallbacks(std::unique_ptr<TestPPCallbacks>(Callbacks));
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000164 PP.EnterMainSourceFile();
165 }
166 void EndSourceFileAction() override { SeenEnd = Callbacks->SeenEnd; }
167
168 bool SeenEnd;
169};
170
171TEST(PreprocessorFrontendAction, EndSourceFile) {
172 CompilerInvocation *Invocation = new CompilerInvocation;
173 Invocation->getPreprocessorOpts().addRemappedFile(
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000174 "test.cc",
175 MemoryBuffer::getMemBuffer("int main() { float x; }").release());
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000176 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
Benjamin Kramera2406fa2014-09-10 09:35:49 +0000184 TestPPCallbacks *Callbacks = new TestPPCallbacks;
185 TestPPCallbacksFrontendAction TestAction(Callbacks);
Benjamin Kramer88d99e42014-08-07 20:51:16 +0000186 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
Jeffrey Yasskinc7da9932011-02-03 04:51:52 +0000193} // anonymous namespace