blob: 819aa52a508ebd1de4bac90aec26bc4101416e2e [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
Argyrios Kyrtzidis3e785932010-10-14 20:14:25 +000054 /// \brief Checks deserialized declarations and emits error if a name
55 /// matches one given in command-line using -error-on-deserialized-decl.
56 class DeserializedDeclsChecker : public ASTDeserializationListener {
57 ASTContext &Ctx;
58 std::set<std::string> NamesToCheck;
59 ASTDeserializationListener *Previous;
60
61 public:
62 DeserializedDeclsChecker(ASTContext &Ctx,
63 const std::set<std::string> &NamesToCheck,
64 ASTDeserializationListener *Previous)
65 : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
66
67 virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
68 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
69 if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
70 unsigned DiagID
71 = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error,
72 "%0 was deserialized");
73 Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
74 << ND->getNameAsString();
75 }
76
77 if (Previous)
78 Previous->DeclRead(ID, D);
79 }
80
81 virtual void SetReader(ASTReader *Reader) {}
82 virtual void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) {}
83 virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {}
84 virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {}
85 virtual void MacroDefinitionRead(serialization::MacroID,
86 MacroDefinition *MD) {}
87};
88
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +000089} // end anonymous namespace
90
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +000091FrontendAction::FrontendAction() : Instance(0) {}
Daniel Dunbar4ee24092009-11-14 10:42:35 +000092
93FrontendAction::~FrontendAction() {}
94
Daniel Dunbar685ac662010-06-07 23:25:49 +000095void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
96 ASTUnit *AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +000097 CurrentFile = Value;
Daniel Dunbar685ac662010-06-07 23:25:49 +000098 CurrentFileKind = Kind;
Daniel Dunbar4ee24092009-11-14 10:42:35 +000099 CurrentASTUnit.reset(AST);
100}
101
102bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
103 llvm::StringRef Filename,
Daniel Dunbard3598a62010-06-07 23:23:06 +0000104 InputKind InputKind) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000105 assert(!Instance && "Already processing a source file!");
106 assert(!Filename.empty() && "Unexpected empty filename!");
Daniel Dunbar685ac662010-06-07 23:25:49 +0000107 setCurrentFile(Filename, InputKind);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000108 setCompilerInstance(&CI);
109
110 // AST files follow a very different path, since they share objects via the
111 // AST unit.
Daniel Dunbar20560482010-06-07 23:23:50 +0000112 if (InputKind == IK_AST) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000113 assert(!usesPreprocessorOnly() &&
114 "Attempt to pass AST file to preprocessor only action!");
Daniel Dunbareb58d832010-06-07 23:24:43 +0000115 assert(hasASTFileSupport() &&
116 "This action does not have AST file support!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000117
Douglas Gregor28019772010-04-05 23:52:57 +0000118 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000119 std::string Error;
Sebastian Redl3c7f4132010-08-18 23:57:06 +0000120 ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
Daniel Dunbar5262fda2009-12-03 01:45:44 +0000121 if (!AST)
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000122 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000123
Daniel Dunbar685ac662010-06-07 23:25:49 +0000124 setCurrentFile(Filename, InputKind, AST);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000125
126 // Set the shared objects, these are reset when we finish processing the
127 // file, otherwise the CompilerInstance will happily destroy them.
128 CI.setFileManager(&AST->getFileManager());
129 CI.setSourceManager(&AST->getSourceManager());
130 CI.setPreprocessor(&AST->getPreprocessor());
131 CI.setASTContext(&AST->getASTContext());
132
133 // Initialize the action.
134 if (!BeginSourceFileAction(CI, Filename))
135 goto failure;
136
137 /// Create the AST consumer.
138 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
139 if (!CI.hasASTConsumer())
140 goto failure;
141
142 return true;
143 }
144
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000145 // Set up the file and source managers, if needed.
Daniel Dunbar20560482010-06-07 23:23:50 +0000146 if (!CI.hasFileManager())
147 CI.createFileManager();
148 if (!CI.hasSourceManager())
149 CI.createSourceManager();
Daniel Dunbarfaddc3e2010-06-07 23:26:47 +0000150
151 // IR files bypass the rest of initialization.
152 if (InputKind == IK_LLVM_IR) {
153 assert(hasIRSupport() &&
154 "This action does not have IR file support!");
155
156 // Inform the diagnostic client we are processing a source file.
157 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
158
159 // Initialize the action.
160 if (!BeginSourceFileAction(CI, Filename))
161 goto failure;
162
163 return true;
164 }
165
166 // Set up the preprocessor.
Daniel Dunbar20560482010-06-07 23:23:50 +0000167 CI.createPreprocessor();
168
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000169 // Inform the diagnostic client we are processing a source file.
170 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
171 &CI.getPreprocessor());
172
173 // Initialize the action.
174 if (!BeginSourceFileAction(CI, Filename))
175 goto failure;
176
177 /// Create the AST context and consumer unless this is a preprocessor only
178 /// action.
179 if (!usesPreprocessorOnly()) {
180 CI.createASTContext();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000181
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000182 llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
183
184 /// Use PCH?
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000185 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000186 assert(hasPCHSupport() && "This action does not have PCH support!");
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000187 ASTDeserializationListener *DeserialListener
188 = CI.getInvocation().getFrontendOpts().ChainedPCH ?
189 Consumer->GetASTDeserializationListener() : 0;
190 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
191 DeserialListener = new DeserializedDeclsDumper(DeserialListener);
Argyrios Kyrtzidis3e785932010-10-14 20:14:25 +0000192 if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
193 DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
194 CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
195 DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000196 CI.createPCHExternalASTSource(
Douglas Gregorfae3b2f2010-07-27 00:27:13 +0000197 CI.getPreprocessorOpts().ImplicitPCHInclude,
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000198 CI.getPreprocessorOpts().DisablePCHValidation,
Argyrios Kyrtzidisb9728582010-10-14 20:14:18 +0000199 DeserialListener);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000200 if (!CI.getASTContext().getExternalSource())
201 goto failure;
202 }
Sebastian Redl77f46032010-07-09 21:00:24 +0000203
Sebastian Redlffaab3e2010-07-30 00:29:29 +0000204 CI.setASTConsumer(Consumer.take());
Sebastian Redl77f46032010-07-09 21:00:24 +0000205 if (!CI.hasASTConsumer())
206 goto failure;
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000207 }
208
209 // Initialize builtin info as long as we aren't using an external AST
210 // source.
211 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
212 Preprocessor &PP = CI.getPreprocessor();
213 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
214 PP.getLangOptions().NoBuiltin);
215 }
216
217 return true;
218
219 // If we failed, reset state since the client will not end up calling the
220 // matching EndSourceFile().
221 failure:
222 if (isCurrentFileAST()) {
223 CI.takeASTContext();
224 CI.takePreprocessor();
225 CI.takeSourceManager();
226 CI.takeFileManager();
227 }
228
229 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000230 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000231 setCompilerInstance(0);
232 return false;
233}
234
235void FrontendAction::Execute() {
236 CompilerInstance &CI = getCompilerInstance();
237
238 // Initialize the main file entry. This needs to be delayed until after PCH
239 // has loaded.
240 if (isCurrentFileAST()) {
241 // Set the main file ID to an empty file.
242 //
243 // FIXME: We probably shouldn't need this, but for now this is the
244 // simplest way to reuse the logic in ParseAST.
245 const char *EmptyStr = "";
246 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000247 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000248 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
249 } else {
250 if (!CI.InitializeSourceManager(getCurrentFile()))
251 return;
252 }
253
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000254 if (CI.hasFrontendTimer()) {
255 llvm::TimeRegion Timer(CI.getFrontendTimer());
256 ExecuteAction();
257 }
258 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000259}
260
261void FrontendAction::EndSourceFile() {
262 CompilerInstance &CI = getCompilerInstance();
263
264 // Finalize the action.
265 EndSourceFileAction();
266
267 // Release the consumer and the AST, in that order since the consumer may
268 // perform actions in its destructor which require the context.
269 //
270 // FIXME: There is more per-file stuff we could just drop here?
271 if (CI.getFrontendOpts().DisableFree) {
272 CI.takeASTConsumer();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000273 if (!isCurrentFileAST()) {
274 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000275 CI.takeASTContext();
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000276 }
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000277 } else {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000278 if (!isCurrentFileAST()) {
279 CI.setSema(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000280 CI.setASTContext(0);
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000281 }
282 CI.setASTConsumer(0);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000283 }
284
Daniel Dunbardbd82092010-03-23 05:09:10 +0000285 // Inform the preprocessor we are done.
286 if (CI.hasPreprocessor())
287 CI.getPreprocessor().EndSourceFile();
288
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000289 if (CI.getFrontendOpts().ShowStats) {
290 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
291 CI.getPreprocessor().PrintStats();
292 CI.getPreprocessor().getIdentifierTable().PrintStats();
293 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
294 CI.getSourceManager().PrintStats();
295 llvm::errs() << "\n";
296 }
297
298 // Cleanup the output streams, and erase the output files if we encountered
299 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000300 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000301
302 // Inform the diagnostic client we are done with this source file.
303 CI.getDiagnosticClient().EndSourceFile();
304
305 if (isCurrentFileAST()) {
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000306 CI.takeSema();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000307 CI.takeASTContext();
308 CI.takePreprocessor();
309 CI.takeSourceManager();
310 CI.takeFileManager();
311 }
312
313 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000314 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000315}
316
317//===----------------------------------------------------------------------===//
318// Utility Actions
319//===----------------------------------------------------------------------===//
320
321void ASTFrontendAction::ExecuteAction() {
322 CompilerInstance &CI = getCompilerInstance();
323
324 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
325 // here so the source manager would be initialized.
326 if (hasCodeCompletionSupport() &&
327 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
328 CI.createCodeCompletionConsumer();
329
330 // Use a code completion consumer?
331 CodeCompleteConsumer *CompletionConsumer = 0;
332 if (CI.hasCodeCompletionConsumer())
333 CompletionConsumer = &CI.getCodeCompletionConsumer();
334
Douglas Gregorf18d0d82010-08-12 23:31:19 +0000335 if (!CI.hasSema())
336 CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
337
338 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000339}
340
341ASTConsumer *
342PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
343 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000344 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000345}