blob: b244c5ce0225a2ad7c4c148c2c6d4d7d9590effb [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"
Sebastian Redlffaab3e2010-07-30 00:29:29 +000011#include "clang/AST/ASTConsumer.h"
Daniel Dunbar4ee24092009-11-14 10:42:35 +000012#include "clang/AST/ASTContext.h"
13#include "clang/Lex/HeaderSearch.h"
14#include "clang/Lex/Preprocessor.h"
15#include "clang/Frontend/ASTUnit.h"
16#include "clang/Frontend/CompilerInstance.h"
17#include "clang/Frontend/FrontendDiagnostic.h"
John McCall19510852010-08-20 18:27:03 +000018#include "clang/Parse/ParseAST.h"
Daniel Dunbar4ee24092009-11-14 10:42:35 +000019#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/Timer.h"
21#include "llvm/Support/ErrorHandling.h"
22#include "llvm/Support/raw_ostream.h"
23using namespace clang;
24
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +000025FrontendAction::FrontendAction() : Instance(0) {}
Daniel Dunbar4ee24092009-11-14 10:42:35 +000026
27FrontendAction::~FrontendAction() {}
28
Daniel Dunbar685ac662010-06-07 23:25:49 +000029void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
30 ASTUnit *AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000031 CurrentFile = Value;
Daniel Dunbar685ac662010-06-07 23:25:49 +000032 CurrentFileKind = Kind;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000033 CurrentASTUnit.reset(AST);
34}
35
36bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
37 llvm::StringRef Filename,
Daniel Dunbard3598a62010-06-07 23:23:06 +000038 InputKind InputKind) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000039 assert(!Instance && "Already processing a source file!");
40 assert(!Filename.empty() && "Unexpected empty filename!");
Daniel Dunbar685ac662010-06-07 23:25:49 +000041 setCurrentFile(Filename, InputKind);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000042 setCompilerInstance(&CI);
43
44 // AST files follow a very different path, since they share objects via the
45 // AST unit.
Daniel Dunbar20560482010-06-07 23:23:50 +000046 if (InputKind == IK_AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000047 assert(!usesPreprocessorOnly() &&
48 "Attempt to pass AST file to preprocessor only action!");
Daniel Dunbareb58d832010-06-07 23:24:43 +000049 assert(hasASTFileSupport() &&
50 "This action does not have AST file support!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +000051
Douglas Gregor28019772010-04-05 23:52:57 +000052 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
Daniel Dunbar4ee24092009-11-14 10:42:35 +000053 std::string Error;
Sebastian Redl3c7f4132010-08-18 23:57:06 +000054 ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
Daniel Dunbar5262fda2009-12-03 01:45:44 +000055 if (!AST)
Daniel Dunbar4ee24092009-11-14 10:42:35 +000056 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000057
Daniel Dunbar685ac662010-06-07 23:25:49 +000058 setCurrentFile(Filename, InputKind, AST);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000059
60 // Set the shared objects, these are reset when we finish processing the
61 // file, otherwise the CompilerInstance will happily destroy them.
62 CI.setFileManager(&AST->getFileManager());
63 CI.setSourceManager(&AST->getSourceManager());
64 CI.setPreprocessor(&AST->getPreprocessor());
65 CI.setASTContext(&AST->getASTContext());
66
67 // Initialize the action.
68 if (!BeginSourceFileAction(CI, Filename))
69 goto failure;
70
71 /// Create the AST consumer.
72 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
73 if (!CI.hasASTConsumer())
74 goto failure;
75
76 return true;
77 }
78
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +000079 // Set up the file and source managers, if needed.
Daniel Dunbar20560482010-06-07 23:23:50 +000080 if (!CI.hasFileManager())
81 CI.createFileManager();
82 if (!CI.hasSourceManager())
83 CI.createSourceManager();
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +000084
85 // IR files bypass the rest of initialization.
86 if (InputKind == IK_LLVM_IR) {
87 assert(hasIRSupport() &&
88 "This action does not have IR file support!");
89
90 // Inform the diagnostic client we are processing a source file.
91 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
92
93 // Initialize the action.
94 if (!BeginSourceFileAction(CI, Filename))
95 goto failure;
96
97 return true;
98 }
99
100 // Set up the preprocessor.
Daniel Dunbar20560482010-06-07 23:23:50 +0000101 CI.createPreprocessor();
102
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000103 // Inform the diagnostic client we are processing a source file.
104 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
105 &CI.getPreprocessor());
106
107 // Initialize the action.
108 if (!BeginSourceFileAction(CI, Filename))
109 goto failure;
110
111 /// Create the AST context and consumer unless this is a preprocessor only
112 /// action.
113 if (!usesPreprocessorOnly()) {
114 CI.createASTContext();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000115
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000116 llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
117
118 /// Use PCH?
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000119 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000120 assert(hasPCHSupport() && "This action does not have PCH support!");
121 CI.createPCHExternalASTSource(
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000122 CI.getPreprocessorOpts().ImplicitPCHInclude,
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000123 CI.getPreprocessorOpts().DisablePCHValidation,
124 CI.getInvocation().getFrontendOpts().ChainedPCH?
Sebastian Redl571db7f2010-08-18 23:56:56 +0000125 Consumer->GetASTDeserializationListener() : 0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000126 if (!CI.getASTContext().getExternalSource())
127 goto failure;
128 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000129
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000130 CI.setASTConsumer(Consumer.take());
Sebastian Redl77f46032010-07-09 21:00:24 +0000131 if (!CI.hasASTConsumer())
132 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000133 }
134
135 // Initialize builtin info as long as we aren't using an external AST
136 // source.
137 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
138 Preprocessor &PP = CI.getPreprocessor();
139 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
140 PP.getLangOptions().NoBuiltin);
141 }
142
143 return true;
144
145 // If we failed, reset state since the client will not end up calling the
146 // matching EndSourceFile().
147 failure:
148 if (isCurrentFileAST()) {
149 CI.takeASTContext();
150 CI.takePreprocessor();
151 CI.takeSourceManager();
152 CI.takeFileManager();
153 }
154
155 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000156 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000157 setCompilerInstance(0);
158 return false;
159}
160
161void FrontendAction::Execute() {
162 CompilerInstance &CI = getCompilerInstance();
163
164 // Initialize the main file entry. This needs to be delayed until after PCH
165 // has loaded.
166 if (isCurrentFileAST()) {
167 // Set the main file ID to an empty file.
168 //
169 // FIXME: We probably shouldn't need this, but for now this is the
170 // simplest way to reuse the logic in ParseAST.
171 const char *EmptyStr = "";
172 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000173 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000174 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
175 } else {
176 if (!CI.InitializeSourceManager(getCurrentFile()))
177 return;
178 }
179
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000180 if (CI.hasFrontendTimer()) {
181 llvm::TimeRegion Timer(CI.getFrontendTimer());
182 ExecuteAction();
183 }
184 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000185}
186
187void FrontendAction::EndSourceFile() {
188 CompilerInstance &CI = getCompilerInstance();
189
190 // Finalize the action.
191 EndSourceFileAction();
192
193 // Release the consumer and the AST, in that order since the consumer may
194 // perform actions in its destructor which require the context.
195 //
196 // FIXME: There is more per-file stuff we could just drop here?
197 if (CI.getFrontendOpts().DisableFree) {
198 CI.takeASTConsumer();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000199 if (!isCurrentFileAST()) {
200 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000201 CI.takeASTContext();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000202 }
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000203 } else {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000204 if (!isCurrentFileAST()) {
205 CI.setSema(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000206 CI.setASTContext(0);
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000207 }
208 CI.setASTConsumer(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000209 }
210
Daniel Dunbardbd82092010-03-23 05:09:10 +0000211 // Inform the preprocessor we are done.
212 if (CI.hasPreprocessor())
213 CI.getPreprocessor().EndSourceFile();
214
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000215 if (CI.getFrontendOpts().ShowStats) {
216 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
217 CI.getPreprocessor().PrintStats();
218 CI.getPreprocessor().getIdentifierTable().PrintStats();
219 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
220 CI.getSourceManager().PrintStats();
221 llvm::errs() << "\n";
222 }
223
224 // Cleanup the output streams, and erase the output files if we encountered
225 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000226 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000227
228 // Inform the diagnostic client we are done with this source file.
229 CI.getDiagnosticClient().EndSourceFile();
230
231 if (isCurrentFileAST()) {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000232 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000233 CI.takeASTContext();
234 CI.takePreprocessor();
235 CI.takeSourceManager();
236 CI.takeFileManager();
237 }
238
239 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000240 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000241}
242
243//===----------------------------------------------------------------------===//
244// Utility Actions
245//===----------------------------------------------------------------------===//
246
247void ASTFrontendAction::ExecuteAction() {
248 CompilerInstance &CI = getCompilerInstance();
249
250 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
251 // here so the source manager would be initialized.
252 if (hasCodeCompletionSupport() &&
253 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
254 CI.createCodeCompletionConsumer();
255
256 // Use a code completion consumer?
257 CodeCompleteConsumer *CompletionConsumer = 0;
258 if (CI.hasCodeCompletionConsumer())
259 CompletionConsumer = &CI.getCodeCompletionConsumer();
260
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000261 if (!CI.hasSema())
262 CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
263
264 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000265}
266
267ASTConsumer *
268PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
269 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000270 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000271}