blob: 56676e1ef93e3b49ce3b7c38bf6607e7fedc45a0 [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 Dunbar20560482010-06-07 23:23:50 +000078 // Setup the file and source managers, if needed, and the preprocessor.
79 if (!CI.hasFileManager())
80 CI.createFileManager();
81 if (!CI.hasSourceManager())
82 CI.createSourceManager();
83 CI.createPreprocessor();
84
Daniel Dunbar4ee24092009-11-14 10:42:35 +000085 // Inform the diagnostic client we are processing a source file.
86 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
87 &CI.getPreprocessor());
88
89 // Initialize the action.
90 if (!BeginSourceFileAction(CI, Filename))
91 goto failure;
92
93 /// Create the AST context and consumer unless this is a preprocessor only
94 /// action.
95 if (!usesPreprocessorOnly()) {
96 CI.createASTContext();
97 CI.setASTConsumer(CreateASTConsumer(CI, Filename));
98 if (!CI.hasASTConsumer())
99 goto failure;
100
101 /// Use PCH?
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000102 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000103 assert(hasPCHSupport() && "This action does not have PCH support!");
104 CI.createPCHExternalASTSource(
Daniel Dunbar049d3a02009-11-17 05:52:41 +0000105 CI.getPreprocessorOpts().ImplicitPCHInclude);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000106 if (!CI.getASTContext().getExternalSource())
107 goto failure;
108 }
109 }
110
111 // Initialize builtin info as long as we aren't using an external AST
112 // source.
113 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
114 Preprocessor &PP = CI.getPreprocessor();
115 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
116 PP.getLangOptions().NoBuiltin);
117 }
118
119 return true;
120
121 // If we failed, reset state since the client will not end up calling the
122 // matching EndSourceFile().
123 failure:
124 if (isCurrentFileAST()) {
125 CI.takeASTContext();
126 CI.takePreprocessor();
127 CI.takeSourceManager();
128 CI.takeFileManager();
129 }
130
131 CI.getDiagnosticClient().EndSourceFile();
Daniel Dunbar685ac662010-06-07 23:25:49 +0000132 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000133 setCompilerInstance(0);
134 return false;
135}
136
137void FrontendAction::Execute() {
138 CompilerInstance &CI = getCompilerInstance();
139
140 // Initialize the main file entry. This needs to be delayed until after PCH
141 // has loaded.
142 if (isCurrentFileAST()) {
143 // Set the main file ID to an empty file.
144 //
145 // FIXME: We probably shouldn't need this, but for now this is the
146 // simplest way to reuse the logic in ParseAST.
147 const char *EmptyStr = "";
148 llvm::MemoryBuffer *SB =
Chris Lattnera0a270c2010-04-05 22:42:27 +0000149 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000150 CI.getSourceManager().createMainFileIDForMemBuffer(SB);
151 } else {
152 if (!CI.InitializeSourceManager(getCurrentFile()))
153 return;
154 }
155
Kovarththanan Rajaratnamf79bafa2009-11-29 09:57:35 +0000156 if (CI.hasFrontendTimer()) {
157 llvm::TimeRegion Timer(CI.getFrontendTimer());
158 ExecuteAction();
159 }
160 else ExecuteAction();
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000161}
162
163void FrontendAction::EndSourceFile() {
164 CompilerInstance &CI = getCompilerInstance();
165
166 // Finalize the action.
167 EndSourceFileAction();
168
169 // Release the consumer and the AST, in that order since the consumer may
170 // perform actions in its destructor which require the context.
171 //
172 // FIXME: There is more per-file stuff we could just drop here?
173 if (CI.getFrontendOpts().DisableFree) {
174 CI.takeASTConsumer();
175 if (!isCurrentFileAST())
176 CI.takeASTContext();
177 } else {
178 CI.setASTConsumer(0);
179 if (!isCurrentFileAST())
180 CI.setASTContext(0);
181 }
182
Daniel Dunbardbd82092010-03-23 05:09:10 +0000183 // Inform the preprocessor we are done.
184 if (CI.hasPreprocessor())
185 CI.getPreprocessor().EndSourceFile();
186
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000187 if (CI.getFrontendOpts().ShowStats) {
188 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
189 CI.getPreprocessor().PrintStats();
190 CI.getPreprocessor().getIdentifierTable().PrintStats();
191 CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
192 CI.getSourceManager().PrintStats();
193 llvm::errs() << "\n";
194 }
195
196 // Cleanup the output streams, and erase the output files if we encountered
197 // an error.
Kovarththanan Rajaratname51dd7b2010-03-06 12:07:48 +0000198 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000199
200 // Inform the diagnostic client we are done with this source file.
201 CI.getDiagnosticClient().EndSourceFile();
202
203 if (isCurrentFileAST()) {
204 CI.takeASTContext();
205 CI.takePreprocessor();
206 CI.takeSourceManager();
207 CI.takeFileManager();
208 }
209
210 setCompilerInstance(0);
Daniel Dunbar685ac662010-06-07 23:25:49 +0000211 setCurrentFile("", IK_None);
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000212}
213
214//===----------------------------------------------------------------------===//
215// Utility Actions
216//===----------------------------------------------------------------------===//
217
218void ASTFrontendAction::ExecuteAction() {
219 CompilerInstance &CI = getCompilerInstance();
220
221 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
222 // here so the source manager would be initialized.
223 if (hasCodeCompletionSupport() &&
224 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
225 CI.createCodeCompletionConsumer();
226
227 // Use a code completion consumer?
228 CodeCompleteConsumer *CompletionConsumer = 0;
229 if (CI.hasCodeCompletionConsumer())
230 CompletionConsumer = &CI.getCodeCompletionConsumer();
231
232 ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
233 CI.getFrontendOpts().ShowStats,
234 usesCompleteTranslationUnit(), CompletionConsumer);
235}
236
237ASTConsumer *
238PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
239 llvm::StringRef InFile) {
Jeffrey Yasskin9f61aa92009-12-12 05:05:38 +0000240 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
Daniel Dunbar4ee24092009-11-14 10:42:35 +0000241}