blob: 429b00933325359f14e97ee1a9e9a5d0720f7fd0 [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"
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +000019#include "clang/Serialization/ASTDeserializationListener.h"
Daniel Dunbar4ee24092009-11-14 10:42:35 +000020#include "llvm/Support/MemoryBuffer.h"
21#include "llvm/Support/Timer.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/raw_ostream.h"
24using namespace clang;
25
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +000026namespace {
27
28/// \brief Dumps deserialized declarations.
29class DeserializedDeclsDumper : public ASTDeserializationListener {
30 ASTDeserializationListener *Previous;
31
32public:
33 DeserializedDeclsDumper(ASTDeserializationListener *Previous)
34 : Previous(Previous) { }
35
36 virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
37 llvm::outs() << "PCH DECL: " << D->getDeclKindName();
38 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
39 llvm::outs() << " - " << ND->getNameAsString();
40 llvm::outs() << "\n";
41
42 if (Previous)
43 Previous->DeclRead(ID, D);
44 }
45
46 virtual void SetReader(ASTReader *Reader) {}
47 virtual void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) {}
48 virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {}
49 virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {}
50 virtual void MacroDefinitionRead(serialization::MacroID,
51 MacroDefinition *MD) {}
52};
53
54} // end anonymous namespace
55
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +000056FrontendAction::FrontendAction() : Instance(0) {}
Daniel Dunbar4ee24092009-11-14 10:42:35 +000057
58FrontendAction::~FrontendAction() {}
59
Daniel Dunbar685ac662010-06-07 23:25:49 +000060void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
61 ASTUnit *AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000062 CurrentFile = Value;
Daniel Dunbar685ac662010-06-07 23:25:49 +000063 CurrentFileKind = Kind;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000064 CurrentASTUnit.reset(AST);
65}
66
67bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
68 llvm::StringRef Filename,
Daniel Dunbard3598a62010-06-07 23:23:06 +000069 InputKind InputKind) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000070 assert(!Instance && "Already processing a source file!");
71 assert(!Filename.empty() && "Unexpected empty filename!");
Daniel Dunbar685ac662010-06-07 23:25:49 +000072 setCurrentFile(Filename, InputKind);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000073 setCompilerInstance(&CI);
74
75 // AST files follow a very different path, since they share objects via the
76 // AST unit.
Daniel Dunbar20560482010-06-07 23:23:50 +000077 if (InputKind == IK_AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000078 assert(!usesPreprocessorOnly() &&
79 "Attempt to pass AST file to preprocessor only action!");
Daniel Dunbareb58d832010-06-07 23:24:43 +000080 assert(hasASTFileSupport() &&
81 "This action does not have AST file support!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +000082
Douglas Gregor28019772010-04-05 23:52:57 +000083 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
Daniel Dunbar4ee24092009-11-14 10:42:35 +000084 std::string Error;
Sebastian Redl3c7f4132010-08-18 23:57:06 +000085 ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
Daniel Dunbar5262fda2009-12-03 01:45:44 +000086 if (!AST)
Daniel Dunbar4ee24092009-11-14 10:42:35 +000087 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000088
Daniel Dunbar685ac662010-06-07 23:25:49 +000089 setCurrentFile(Filename, InputKind, AST);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000090
91 // Set the shared objects, these are reset when we finish processing the
92 // file, otherwise the CompilerInstance will happily destroy them.
93 CI.setFileManager(&AST->getFileManager());
94 CI.setSourceManager(&AST->getSourceManager());
95 CI.setPreprocessor(&AST->getPreprocessor());
96 CI.setASTContext(&AST->getASTContext());
97
98 // Initialize the action.
99 if (!BeginSourceFileAction(CI, Filename))
100 goto failure;
101
102 /// Create the AST consumer.
103 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
104 if (!CI.hasASTConsumer())
105 goto failure;
106
107 return true;
108 }
109
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000110 // Set up the file and source managers, if needed.
Daniel Dunbar20560482010-06-07 23:23:50 +0000111 if (!CI.hasFileManager())
112 CI.createFileManager();
113 if (!CI.hasSourceManager())
114 CI.createSourceManager();
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000115
116 // IR files bypass the rest of initialization.
117 if (InputKind == IK_LLVM_IR) {
118 assert(hasIRSupport() &&
119 "This action does not have IR file support!");
120
121 // Inform the diagnostic client we are processing a source file.
122 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
123
124 // Initialize the action.
125 if (!BeginSourceFileAction(CI, Filename))
126 goto failure;
127
128 return true;
129 }
130
131 // Set up the preprocessor.
Daniel Dunbar20560482010-06-07 23:23:50 +0000132 CI.createPreprocessor();
133
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000134 // Inform the diagnostic client we are processing a source file.
135 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
136 &CI.getPreprocessor());
137
138 // Initialize the action.
139 if (!BeginSourceFileAction(CI, Filename))
140 goto failure;
141
142 /// Create the AST context and consumer unless this is a preprocessor only
143 /// action.
144 if (!usesPreprocessorOnly()) {
145 CI.createASTContext();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000146
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000147 llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
148
149 /// Use PCH?
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000150 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000151 assert(hasPCHSupport() && "This action does not have PCH support!");
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000152 ASTDeserializationListener *DeserialListener
153 = CI.getInvocation().getFrontendOpts().ChainedPCH ?
154 Consumer->GetASTDeserializationListener() : 0;
155 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
156 DeserialListener = new DeserializedDeclsDumper(DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000157 CI.createPCHExternalASTSource(
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000158 CI.getPreprocessorOpts().ImplicitPCHInclude,
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000159 CI.getPreprocessorOpts().DisablePCHValidation,
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000160 DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000161 if (!CI.getASTContext().getExternalSource())
162 goto failure;
163 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000164
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000165 CI.setASTConsumer(Consumer.take());
Sebastian Redl77f46032010-07-09 21:00:24 +0000166 if (!CI.hasASTConsumer())
167 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000168 }
169
170 // Initialize builtin info as long as we aren't using an external AST
171 // source.
172 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
173 Preprocessor &PP = CI.getPreprocessor();
174 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
175 PP.getLangOptions().NoBuiltin);
176 }
177
178 return true;
179
180 // If we failed, reset state since the client will not end up calling the
181 // matching EndSourceFile().
182 failure:
183 if (isCurrentFileAST()) {
184 CI.takeASTContext();
185 CI.takePreprocessor();
186 CI.takeSourceManager();
187 CI.takeFileManager();
188 }
189
190 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000191 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000192 setCompilerInstance(0);
193 return false;
194}
195
196void FrontendAction::Execute() {
197 CompilerInstance &CI = getCompilerInstance();
198
199 // Initialize the main file entry. This needs to be delayed until after PCH
200 // has loaded.
201 if (isCurrentFileAST()) {
202 // Set the main file ID to an empty file.
203 //
204 // FIXME: We probably shouldn't need this, but for now this is the
205 // simplest way to reuse the logic in ParseAST.
206 const char *EmptyStr = "";
207 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000208 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000209 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
210 } else {
211 if (!CI.InitializeSourceManager(getCurrentFile()))
212 return;
213 }
214
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000215 if (CI.hasFrontendTimer()) {
216 llvm::TimeRegion Timer(CI.getFrontendTimer());
217 ExecuteAction();
218 }
219 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000220}
221
222void FrontendAction::EndSourceFile() {
223 CompilerInstance &CI = getCompilerInstance();
224
225 // Finalize the action.
226 EndSourceFileAction();
227
228 // Release the consumer and the AST, in that order since the consumer may
229 // perform actions in its destructor which require the context.
230 //
231 // FIXME: There is more per-file stuff we could just drop here?
232 if (CI.getFrontendOpts().DisableFree) {
233 CI.takeASTConsumer();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000234 if (!isCurrentFileAST()) {
235 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000236 CI.takeASTContext();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000237 }
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000238 } else {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000239 if (!isCurrentFileAST()) {
240 CI.setSema(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000241 CI.setASTContext(0);
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000242 }
243 CI.setASTConsumer(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000244 }
245
Daniel Dunbardbd82092010-03-23 05:09:10 +0000246 // Inform the preprocessor we are done.
247 if (CI.hasPreprocessor())
248 CI.getPreprocessor().EndSourceFile();
249
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000250 if (CI.getFrontendOpts().ShowStats) {
251 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
252 CI.getPreprocessor().PrintStats();
253 CI.getPreprocessor().getIdentifierTable().PrintStats();
254 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
255 CI.getSourceManager().PrintStats();
256 llvm::errs() << "\n";
257 }
258
259 // Cleanup the output streams, and erase the output files if we encountered
260 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000261 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000262
263 // Inform the diagnostic client we are done with this source file.
264 CI.getDiagnosticClient().EndSourceFile();
265
266 if (isCurrentFileAST()) {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000267 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000268 CI.takeASTContext();
269 CI.takePreprocessor();
270 CI.takeSourceManager();
271 CI.takeFileManager();
272 }
273
274 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000275 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000276}
277
278//===----------------------------------------------------------------------===//
279// Utility Actions
280//===----------------------------------------------------------------------===//
281
282void ASTFrontendAction::ExecuteAction() {
283 CompilerInstance &CI = getCompilerInstance();
284
285 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
286 // here so the source manager would be initialized.
287 if (hasCodeCompletionSupport() &&
288 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
289 CI.createCodeCompletionConsumer();
290
291 // Use a code completion consumer?
292 CodeCompleteConsumer *CompletionConsumer = 0;
293 if (CI.hasCodeCompletionConsumer())
294 CompletionConsumer = &CI.getCodeCompletionConsumer();
295
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000296 if (!CI.hasSema())
297 CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
298
299 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000300}
301
302ASTConsumer *
303PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
304 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000305 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000306}