blob: dbbf69c8b12c4cba5afd29aa553cce6e5c3d5ede [file] [log] [blame]
Daniel Dunbar4ee24092009-11-14 10:42:35 +00001//===--- FrontendAction.cpp -----------------------------------------------===//
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/ASTContext.h"
12#include "clang/Lex/HeaderSearch.h"
13#include "clang/Lex/Preprocessor.h"
14#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/CompilerInstance.h"
16#include "clang/Frontend/FrontendDiagnostic.h"
17#include "clang/Sema/ParseAST.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include "llvm/Support/Timer.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/raw_ostream.h"
22using namespace clang;
23
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +000024FrontendAction::FrontendAction() : Instance(0) {}
Daniel Dunbar4ee24092009-11-14 10:42:35 +000025
26FrontendAction::~FrontendAction() {}
27
Daniel Dunbar685ac662010-06-07 23:25:49 +000028void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
29 ASTUnit *AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000030 CurrentFile = Value;
Daniel Dunbar685ac662010-06-07 23:25:49 +000031 CurrentFileKind = Kind;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000032 CurrentASTUnit.reset(AST);
33}
34
35bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
36 llvm::StringRef Filename,
Daniel Dunbard3598a62010-06-07 23:23:06 +000037 InputKind InputKind) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000038 assert(!Instance && "Already processing a source file!");
39 assert(!Filename.empty() && "Unexpected empty filename!");
Daniel Dunbar685ac662010-06-07 23:25:49 +000040 setCurrentFile(Filename, InputKind);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000041 setCompilerInstance(&CI);
42
43 // AST files follow a very different path, since they share objects via the
44 // AST unit.
Daniel Dunbar20560482010-06-07 23:23:50 +000045 if (InputKind == IK_AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000046 assert(!usesPreprocessorOnly() &&
47 "Attempt to pass AST file to preprocessor only action!");
Daniel Dunbareb58d832010-06-07 23:24:43 +000048 assert(hasASTFileSupport() &&
49 "This action does not have AST file support!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +000050
Douglas Gregor28019772010-04-05 23:52:57 +000051 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
Daniel Dunbar4ee24092009-11-14 10:42:35 +000052 std::string Error;
Douglas Gregor28019772010-04-05 23:52:57 +000053 ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, Diags);
Daniel Dunbar5262fda2009-12-03 01:45:44 +000054 if (!AST)
Daniel Dunbar4ee24092009-11-14 10:42:35 +000055 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000056
Daniel Dunbar685ac662010-06-07 23:25:49 +000057 setCurrentFile(Filename, InputKind, AST);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000058
59 // Set the shared objects, these are reset when we finish processing the
60 // file, otherwise the CompilerInstance will happily destroy them.
61 CI.setFileManager(&AST->getFileManager());
62 CI.setSourceManager(&AST->getSourceManager());
63 CI.setPreprocessor(&AST->getPreprocessor());
64 CI.setASTContext(&AST->getASTContext());
65
66 // Initialize the action.
67 if (!BeginSourceFileAction(CI, Filename))
68 goto failure;
69
70 /// Create the AST consumer.
71 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
72 if (!CI.hasASTConsumer())
73 goto failure;
74
75 return true;
76 }
77
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +000078 // Set up the file and source managers, if needed.
Daniel Dunbar20560482010-06-07 23:23:50 +000079 if (!CI.hasFileManager())
80 CI.createFileManager();
81 if (!CI.hasSourceManager())
82 CI.createSourceManager();
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +000083
84 // IR files bypass the rest of initialization.
85 if (InputKind == IK_LLVM_IR) {
86 assert(hasIRSupport() &&
87 "This action does not have IR file support!");
88
89 // Inform the diagnostic client we are processing a source file.
90 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
91
92 // Initialize the action.
93 if (!BeginSourceFileAction(CI, Filename))
94 goto failure;
95
96 return true;
97 }
98
99 // Set up the preprocessor.
Daniel Dunbar20560482010-06-07 23:23:50 +0000100 CI.createPreprocessor();
101
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000102 // Inform the diagnostic client we are processing a source file.
103 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
104 &CI.getPreprocessor());
105
106 // Initialize the action.
107 if (!BeginSourceFileAction(CI, Filename))
108 goto failure;
109
110 /// Create the AST context and consumer unless this is a preprocessor only
111 /// action.
112 if (!usesPreprocessorOnly()) {
113 CI.createASTContext();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000114
Sebastian Redl77f46032010-07-09 21:00:24 +0000115 /// Use PCH? If so, we want the PCHReader active before the consumer
116 /// is created, because the consumer might be interested in the reader
117 /// (e.g. the PCH writer for chaining).
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000118 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000119 assert(hasPCHSupport() && "This action does not have PCH support!");
120 CI.createPCHExternalASTSource(
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000121 CI.getPreprocessorOpts().ImplicitPCHInclude);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000122 if (!CI.getASTContext().getExternalSource())
123 goto failure;
124 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000125
126 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
127 if (!CI.hasASTConsumer())
128 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000129 }
130
131 // Initialize builtin info as long as we aren't using an external AST
132 // source.
133 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
134 Preprocessor &PP = CI.getPreprocessor();
135 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
136 PP.getLangOptions().NoBuiltin);
137 }
138
139 return true;
140
141 // If we failed, reset state since the client will not end up calling the
142 // matching EndSourceFile().
143 failure:
144 if (isCurrentFileAST()) {
145 CI.takeASTContext();
146 CI.takePreprocessor();
147 CI.takeSourceManager();
148 CI.takeFileManager();
149 }
150
151 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000152 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000153 setCompilerInstance(0);
154 return false;
155}
156
157void FrontendAction::Execute() {
158 CompilerInstance &CI = getCompilerInstance();
159
160 // Initialize the main file entry. This needs to be delayed until after PCH
161 // has loaded.
162 if (isCurrentFileAST()) {
163 // Set the main file ID to an empty file.
164 //
165 // FIXME: We probably shouldn't need this, but for now this is the
166 // simplest way to reuse the logic in ParseAST.
167 const char *EmptyStr = "";
168 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000169 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000170 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
171 } else {
172 if (!CI.InitializeSourceManager(getCurrentFile()))
173 return;
174 }
175
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000176 if (CI.hasFrontendTimer()) {
177 llvm::TimeRegion Timer(CI.getFrontendTimer());
178 ExecuteAction();
179 }
180 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000181}
182
183void FrontendAction::EndSourceFile() {
184 CompilerInstance &CI = getCompilerInstance();
185
186 // Finalize the action.
187 EndSourceFileAction();
188
189 // Release the consumer and the AST, in that order since the consumer may
190 // perform actions in its destructor which require the context.
191 //
192 // FIXME: There is more per-file stuff we could just drop here?
193 if (CI.getFrontendOpts().DisableFree) {
194 CI.takeASTConsumer();
195 if (!isCurrentFileAST())
196 CI.takeASTContext();
197 } else {
198 CI.setASTConsumer(0);
199 if (!isCurrentFileAST())
200 CI.setASTContext(0);
201 }
202
Daniel Dunbardbd82092010-03-23 05:09:10 +0000203 // Inform the preprocessor we are done.
204 if (CI.hasPreprocessor())
205 CI.getPreprocessor().EndSourceFile();
206
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000207 if (CI.getFrontendOpts().ShowStats) {
208 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
209 CI.getPreprocessor().PrintStats();
210 CI.getPreprocessor().getIdentifierTable().PrintStats();
211 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
212 CI.getSourceManager().PrintStats();
213 llvm::errs() << "\n";
214 }
215
216 // Cleanup the output streams, and erase the output files if we encountered
217 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000218 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000219
220 // Inform the diagnostic client we are done with this source file.
221 CI.getDiagnosticClient().EndSourceFile();
222
223 if (isCurrentFileAST()) {
224 CI.takeASTContext();
225 CI.takePreprocessor();
226 CI.takeSourceManager();
227 CI.takeFileManager();
228 }
229
230 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000231 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000232}
233
234//===----------------------------------------------------------------------===//
235// Utility Actions
236//===----------------------------------------------------------------------===//
237
238void ASTFrontendAction::ExecuteAction() {
239 CompilerInstance &CI = getCompilerInstance();
240
241 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
242 // here so the source manager would be initialized.
243 if (hasCodeCompletionSupport() &&
244 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
245 CI.createCodeCompletionConsumer();
246
247 // Use a code completion consumer?
248 CodeCompleteConsumer *CompletionConsumer = 0;
249 if (CI.hasCodeCompletionConsumer())
250 CompletionConsumer = &CI.getCodeCompletionConsumer();
251
252 ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
253 CI.getFrontendOpts().ShowStats,
254 usesCompleteTranslationUnit(), CompletionConsumer);
255}
256
257ASTConsumer *
258PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
259 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000260 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000261}