blob: 2e9d05f3cf889d10d75c86b45f7a5852a4d57ec9 [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 }
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +000045};
46
Argyrios Kyrtzidis3e785932010-10-14 20:14:25 +000047 /// \brief Checks deserialized declarations and emits error if a name
48 /// matches one given in command-line using -error-on-deserialized-decl.
49 class DeserializedDeclsChecker : public ASTDeserializationListener {
50 ASTContext &Ctx;
51 std::set<std::string> NamesToCheck;
52 ASTDeserializationListener *Previous;
53
54 public:
55 DeserializedDeclsChecker(ASTContext &Ctx,
56 const std::set<std::string> &NamesToCheck,
57 ASTDeserializationListener *Previous)
58 : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
59
60 virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
61 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
62 if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
63 unsigned DiagID
64 = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error,
65 "%0 was deserialized");
66 Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
67 << ND->getNameAsString();
68 }
69
70 if (Previous)
71 Previous->DeclRead(ID, D);
72 }
Argyrios Kyrtzidis3e785932010-10-14 20:14:25 +000073};
74
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +000075} // end anonymous namespace
76
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +000077FrontendAction::FrontendAction() : Instance(0) {}
Daniel Dunbar4ee24092009-11-14 10:42:35 +000078
79FrontendAction::~FrontendAction() {}
80
Daniel Dunbar685ac662010-06-07 23:25:49 +000081void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
82 ASTUnit *AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000083 CurrentFile = Value;
Daniel Dunbar685ac662010-06-07 23:25:49 +000084 CurrentFileKind = Kind;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000085 CurrentASTUnit.reset(AST);
86}
87
88bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
89 llvm::StringRef Filename,
Daniel Dunbard3598a62010-06-07 23:23:06 +000090 InputKind InputKind) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000091 assert(!Instance && "Already processing a source file!");
92 assert(!Filename.empty() && "Unexpected empty filename!");
Daniel Dunbar685ac662010-06-07 23:25:49 +000093 setCurrentFile(Filename, InputKind);
Daniel Dunbar4ee24092009-11-14 10:42:35 +000094 setCompilerInstance(&CI);
95
96 // AST files follow a very different path, since they share objects via the
97 // AST unit.
Daniel Dunbar20560482010-06-07 23:23:50 +000098 if (InputKind == IK_AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000099 assert(!usesPreprocessorOnly() &&
100 "Attempt to pass AST file to preprocessor only action!");
Daniel Dunbareb58d832010-06-07 23:24:43 +0000101 assert(hasASTFileSupport() &&
102 "This action does not have AST file support!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000103
Douglas Gregor28019772010-04-05 23:52:57 +0000104 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000105 std::string Error;
Argyrios Kyrtzidis389db162010-11-03 22:45:23 +0000106 ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
107 CI.getFileSystemOpts());
Daniel Dunbar5262fda2009-12-03 01:45:44 +0000108 if (!AST)
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000109 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000110
Daniel Dunbar685ac662010-06-07 23:25:49 +0000111 setCurrentFile(Filename, InputKind, AST);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000112
113 // Set the shared objects, these are reset when we finish processing the
114 // file, otherwise the CompilerInstance will happily destroy them.
115 CI.setFileManager(&AST->getFileManager());
116 CI.setSourceManager(&AST->getSourceManager());
117 CI.setPreprocessor(&AST->getPreprocessor());
118 CI.setASTContext(&AST->getASTContext());
119
120 // Initialize the action.
121 if (!BeginSourceFileAction(CI, Filename))
122 goto failure;
123
124 /// Create the AST consumer.
125 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
126 if (!CI.hasASTConsumer())
127 goto failure;
128
129 return true;
130 }
131
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000132 // Set up the file and source managers, if needed.
Daniel Dunbar20560482010-06-07 23:23:50 +0000133 if (!CI.hasFileManager())
134 CI.createFileManager();
135 if (!CI.hasSourceManager())
Argyrios Kyrtzidis389db162010-11-03 22:45:23 +0000136 CI.createSourceManager(CI.getFileManager(), CI.getFileSystemOpts());
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000137
138 // IR files bypass the rest of initialization.
139 if (InputKind == IK_LLVM_IR) {
140 assert(hasIRSupport() &&
141 "This action does not have IR file support!");
142
143 // Inform the diagnostic client we are processing a source file.
144 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
145
146 // Initialize the action.
147 if (!BeginSourceFileAction(CI, Filename))
148 goto failure;
149
150 return true;
151 }
152
153 // Set up the preprocessor.
Daniel Dunbar20560482010-06-07 23:23:50 +0000154 CI.createPreprocessor();
155
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000156 // Inform the diagnostic client we are processing a source file.
157 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
158 &CI.getPreprocessor());
159
160 // Initialize the action.
161 if (!BeginSourceFileAction(CI, Filename))
162 goto failure;
163
164 /// Create the AST context and consumer unless this is a preprocessor only
165 /// action.
166 if (!usesPreprocessorOnly()) {
167 CI.createASTContext();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000168
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000169 llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
Fariborz Jahaniand3057192010-10-29 19:49:13 +0000170 if (!Consumer)
171 goto failure;
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000172
Argyrios Kyrtzidis7b903402010-10-24 17:26:36 +0000173 CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
174
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000175 /// Use PCH?
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000176 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000177 assert(hasPCHSupport() && "This action does not have PCH support!");
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000178 ASTDeserializationListener *DeserialListener
179 = CI.getInvocation().getFrontendOpts().ChainedPCH ?
180 Consumer->GetASTDeserializationListener() : 0;
181 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
182 DeserialListener = new DeserializedDeclsDumper(DeserialListener);
Argyrios Kyrtzidis3e785932010-10-14 20:14:25 +0000183 if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
184 DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
185 CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
186 DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000187 CI.createPCHExternalASTSource(
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000188 CI.getPreprocessorOpts().ImplicitPCHInclude,
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000189 CI.getPreprocessorOpts().DisablePCHValidation,
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000190 DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000191 if (!CI.getASTContext().getExternalSource())
192 goto failure;
193 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000194
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000195 CI.setASTConsumer(Consumer.take());
Sebastian Redl77f46032010-07-09 21:00:24 +0000196 if (!CI.hasASTConsumer())
197 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000198 }
199
200 // Initialize builtin info as long as we aren't using an external AST
201 // source.
202 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
203 Preprocessor &PP = CI.getPreprocessor();
204 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
205 PP.getLangOptions().NoBuiltin);
206 }
207
208 return true;
209
210 // If we failed, reset state since the client will not end up calling the
211 // matching EndSourceFile().
212 failure:
213 if (isCurrentFileAST()) {
214 CI.takeASTContext();
215 CI.takePreprocessor();
216 CI.takeSourceManager();
217 CI.takeFileManager();
218 }
219
220 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000221 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000222 setCompilerInstance(0);
223 return false;
224}
225
226void FrontendAction::Execute() {
227 CompilerInstance &CI = getCompilerInstance();
228
229 // Initialize the main file entry. This needs to be delayed until after PCH
230 // has loaded.
231 if (isCurrentFileAST()) {
232 // Set the main file ID to an empty file.
233 //
234 // FIXME: We probably shouldn't need this, but for now this is the
235 // simplest way to reuse the logic in ParseAST.
236 const char *EmptyStr = "";
237 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000238 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000239 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
240 } else {
241 if (!CI.InitializeSourceManager(getCurrentFile()))
242 return;
243 }
244
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000245 if (CI.hasFrontendTimer()) {
246 llvm::TimeRegion Timer(CI.getFrontendTimer());
247 ExecuteAction();
248 }
249 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000250}
251
252void FrontendAction::EndSourceFile() {
253 CompilerInstance &CI = getCompilerInstance();
254
255 // Finalize the action.
256 EndSourceFileAction();
257
258 // Release the consumer and the AST, in that order since the consumer may
259 // perform actions in its destructor which require the context.
260 //
261 // FIXME: There is more per-file stuff we could just drop here?
262 if (CI.getFrontendOpts().DisableFree) {
263 CI.takeASTConsumer();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000264 if (!isCurrentFileAST()) {
265 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000266 CI.takeASTContext();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000267 }
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000268 } else {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000269 if (!isCurrentFileAST()) {
270 CI.setSema(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000271 CI.setASTContext(0);
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000272 }
273 CI.setASTConsumer(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000274 }
275
Daniel Dunbardbd82092010-03-23 05:09:10 +0000276 // Inform the preprocessor we are done.
277 if (CI.hasPreprocessor())
278 CI.getPreprocessor().EndSourceFile();
279
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000280 if (CI.getFrontendOpts().ShowStats) {
281 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
282 CI.getPreprocessor().PrintStats();
283 CI.getPreprocessor().getIdentifierTable().PrintStats();
284 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
285 CI.getSourceManager().PrintStats();
286 llvm::errs() << "\n";
287 }
288
289 // Cleanup the output streams, and erase the output files if we encountered
290 // an error.
Argyrios Kyrtzidisbe3aab62010-11-18 21:47:07 +0000291 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000292
293 // Inform the diagnostic client we are done with this source file.
294 CI.getDiagnosticClient().EndSourceFile();
295
296 if (isCurrentFileAST()) {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000297 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000298 CI.takeASTContext();
299 CI.takePreprocessor();
300 CI.takeSourceManager();
301 CI.takeFileManager();
302 }
303
304 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000305 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000306}
307
308//===----------------------------------------------------------------------===//
309// Utility Actions
310//===----------------------------------------------------------------------===//
311
312void ASTFrontendAction::ExecuteAction() {
313 CompilerInstance &CI = getCompilerInstance();
314
315 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
316 // here so the source manager would be initialized.
317 if (hasCodeCompletionSupport() &&
318 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
319 CI.createCodeCompletionConsumer();
320
321 // Use a code completion consumer?
322 CodeCompleteConsumer *CompletionConsumer = 0;
323 if (CI.hasCodeCompletionConsumer())
324 CompletionConsumer = &CI.getCodeCompletionConsumer();
325
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000326 if (!CI.hasSema())
327 CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
328
329 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000330}
331
332ASTConsumer *
333PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
334 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000335 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000336}