blob: 9efa8c61db8596a989e46233acd9fae5973c65b9 [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(
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000121 CI.getPreprocessorOpts().ImplicitPCHInclude,
122 CI.getPreprocessorOpts().DisablePCHValidation);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000123 if (!CI.getASTContext().getExternalSource())
124 goto failure;
125 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000126
127 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
128 if (!CI.hasASTConsumer())
129 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000130 }
131
132 // Initialize builtin info as long as we aren't using an external AST
133 // source.
134 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
135 Preprocessor &PP = CI.getPreprocessor();
136 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
137 PP.getLangOptions().NoBuiltin);
138 }
139
140 return true;
141
142 // If we failed, reset state since the client will not end up calling the
143 // matching EndSourceFile().
144 failure:
145 if (isCurrentFileAST()) {
146 CI.takeASTContext();
147 CI.takePreprocessor();
148 CI.takeSourceManager();
149 CI.takeFileManager();
150 }
151
152 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000153 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000154 setCompilerInstance(0);
155 return false;
156}
157
158void FrontendAction::Execute() {
159 CompilerInstance &CI = getCompilerInstance();
160
161 // Initialize the main file entry. This needs to be delayed until after PCH
162 // has loaded.
163 if (isCurrentFileAST()) {
164 // Set the main file ID to an empty file.
165 //
166 // FIXME: We probably shouldn't need this, but for now this is the
167 // simplest way to reuse the logic in ParseAST.
168 const char *EmptyStr = "";
169 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000170 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000171 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
172 } else {
173 if (!CI.InitializeSourceManager(getCurrentFile()))
174 return;
175 }
176
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000177 if (CI.hasFrontendTimer()) {
178 llvm::TimeRegion Timer(CI.getFrontendTimer());
179 ExecuteAction();
180 }
181 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000182}
183
184void FrontendAction::EndSourceFile() {
185 CompilerInstance &CI = getCompilerInstance();
186
187 // Finalize the action.
188 EndSourceFileAction();
189
190 // Release the consumer and the AST, in that order since the consumer may
191 // perform actions in its destructor which require the context.
192 //
193 // FIXME: There is more per-file stuff we could just drop here?
194 if (CI.getFrontendOpts().DisableFree) {
195 CI.takeASTConsumer();
196 if (!isCurrentFileAST())
197 CI.takeASTContext();
198 } else {
199 CI.setASTConsumer(0);
200 if (!isCurrentFileAST())
201 CI.setASTContext(0);
202 }
203
Daniel Dunbardbd82092010-03-23 05:09:10 +0000204 // Inform the preprocessor we are done.
205 if (CI.hasPreprocessor())
206 CI.getPreprocessor().EndSourceFile();
207
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000208 if (CI.getFrontendOpts().ShowStats) {
209 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
210 CI.getPreprocessor().PrintStats();
211 CI.getPreprocessor().getIdentifierTable().PrintStats();
212 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
213 CI.getSourceManager().PrintStats();
214 llvm::errs() << "\n";
215 }
216
217 // Cleanup the output streams, and erase the output files if we encountered
218 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000219 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000220
221 // Inform the diagnostic client we are done with this source file.
222 CI.getDiagnosticClient().EndSourceFile();
223
224 if (isCurrentFileAST()) {
225 CI.takeASTContext();
226 CI.takePreprocessor();
227 CI.takeSourceManager();
228 CI.takeFileManager();
229 }
230
231 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000232 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000233}
234
235//===----------------------------------------------------------------------===//
236// Utility Actions
237//===----------------------------------------------------------------------===//
238
239void ASTFrontendAction::ExecuteAction() {
240 CompilerInstance &CI = getCompilerInstance();
241
242 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
243 // here so the source manager would be initialized.
244 if (hasCodeCompletionSupport() &&
245 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
246 CI.createCodeCompletionConsumer();
247
248 // Use a code completion consumer?
249 CodeCompleteConsumer *CompletionConsumer = 0;
250 if (CI.hasCodeCompletionConsumer())
251 CompletionConsumer = &CI.getCodeCompletionConsumer();
252
253 ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
254 CI.getFrontendOpts().ShowStats,
255 usesCompleteTranslationUnit(), CompletionConsumer);
256}
257
258ASTConsumer *
259PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
260 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000261 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000262}