FrontendAction.cpp revision fae3b2f4743dad616623c4df2fdb0f5128bd36d9
1//===--- 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 24FrontendAction::FrontendAction() : Instance(0) {} 25 26FrontendAction::~FrontendAction() {} 27 28void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, 29 ASTUnit *AST) { 30 CurrentFile = Value; 31 CurrentFileKind = Kind; 32 CurrentASTUnit.reset(AST); 33} 34 35bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 36 llvm::StringRef Filename, 37 InputKind InputKind) { 38 assert(!Instance && "Already processing a source file!"); 39 assert(!Filename.empty() && "Unexpected empty filename!"); 40 setCurrentFile(Filename, InputKind); 41 setCompilerInstance(&CI); 42 43 // AST files follow a very different path, since they share objects via the 44 // AST unit. 45 if (InputKind == IK_AST) { 46 assert(!usesPreprocessorOnly() && 47 "Attempt to pass AST file to preprocessor only action!"); 48 assert(hasASTFileSupport() && 49 "This action does not have AST file support!"); 50 51 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); 52 std::string Error; 53 ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, Diags); 54 if (!AST) 55 goto failure; 56 57 setCurrentFile(Filename, InputKind, AST); 58 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 78 // Set up the file and source managers, if needed. 79 if (!CI.hasFileManager()) 80 CI.createFileManager(); 81 if (!CI.hasSourceManager()) 82 CI.createSourceManager(); 83 84 // IR files bypass the rest of initialization. 85 if (InputKind == IK_LLVM_IR) { 86 assert(hasIRSupport() && 87 "This action does not have IR file support!"); 88 89 // Inform the diagnostic client we are processing a source file. 90 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); 91 92 // Initialize the action. 93 if (!BeginSourceFileAction(CI, Filename)) 94 goto failure; 95 96 return true; 97 } 98 99 // Set up the preprocessor. 100 CI.createPreprocessor(); 101 102 // Inform the diagnostic client we are processing a source file. 103 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 104 &CI.getPreprocessor()); 105 106 // Initialize the action. 107 if (!BeginSourceFileAction(CI, Filename)) 108 goto failure; 109 110 /// Create the AST context and consumer unless this is a preprocessor only 111 /// action. 112 if (!usesPreprocessorOnly()) { 113 CI.createASTContext(); 114 115 /// Use PCH? If so, we want the PCHReader active before the consumer 116 /// is created, because the consumer might be interested in the reader 117 /// (e.g. the PCH writer for chaining). 118 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { 119 assert(hasPCHSupport() && "This action does not have PCH support!"); 120 CI.createPCHExternalASTSource( 121 CI.getPreprocessorOpts().ImplicitPCHInclude, 122 CI.getPreprocessorOpts().DisablePCHValidation); 123 if (!CI.getASTContext().getExternalSource()) 124 goto failure; 125 } 126 127 CI.setASTConsumer(CreateASTConsumer(CI, Filename)); 128 if (!CI.hasASTConsumer()) 129 goto failure; 130 } 131 132 // Initialize builtin info as long as we aren't using an external AST 133 // source. 134 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { 135 Preprocessor &PP = CI.getPreprocessor(); 136 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), 137 PP.getLangOptions().NoBuiltin); 138 } 139 140 return true; 141 142 // If we failed, reset state since the client will not end up calling the 143 // matching EndSourceFile(). 144 failure: 145 if (isCurrentFileAST()) { 146 CI.takeASTContext(); 147 CI.takePreprocessor(); 148 CI.takeSourceManager(); 149 CI.takeFileManager(); 150 } 151 152 CI.getDiagnosticClient().EndSourceFile(); 153 setCurrentFile("", IK_None); 154 setCompilerInstance(0); 155 return false; 156} 157 158void FrontendAction::Execute() { 159 CompilerInstance &CI = getCompilerInstance(); 160 161 // Initialize the main file entry. This needs to be delayed until after PCH 162 // has loaded. 163 if (isCurrentFileAST()) { 164 // Set the main file ID to an empty file. 165 // 166 // FIXME: We probably shouldn't need this, but for now this is the 167 // simplest way to reuse the logic in ParseAST. 168 const char *EmptyStr = ""; 169 llvm::MemoryBuffer *SB = 170 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>"); 171 CI.getSourceManager().createMainFileIDForMemBuffer(SB); 172 } else { 173 if (!CI.InitializeSourceManager(getCurrentFile())) 174 return; 175 } 176 177 if (CI.hasFrontendTimer()) { 178 llvm::TimeRegion Timer(CI.getFrontendTimer()); 179 ExecuteAction(); 180 } 181 else ExecuteAction(); 182} 183 184void FrontendAction::EndSourceFile() { 185 CompilerInstance &CI = getCompilerInstance(); 186 187 // Finalize the action. 188 EndSourceFileAction(); 189 190 // Release the consumer and the AST, in that order since the consumer may 191 // perform actions in its destructor which require the context. 192 // 193 // FIXME: There is more per-file stuff we could just drop here? 194 if (CI.getFrontendOpts().DisableFree) { 195 CI.takeASTConsumer(); 196 if (!isCurrentFileAST()) 197 CI.takeASTContext(); 198 } else { 199 CI.setASTConsumer(0); 200 if (!isCurrentFileAST()) 201 CI.setASTContext(0); 202 } 203 204 // Inform the preprocessor we are done. 205 if (CI.hasPreprocessor()) 206 CI.getPreprocessor().EndSourceFile(); 207 208 if (CI.getFrontendOpts().ShowStats) { 209 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; 210 CI.getPreprocessor().PrintStats(); 211 CI.getPreprocessor().getIdentifierTable().PrintStats(); 212 CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); 213 CI.getSourceManager().PrintStats(); 214 llvm::errs() << "\n"; 215 } 216 217 // Cleanup the output streams, and erase the output files if we encountered 218 // an error. 219 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); 220 221 // Inform the diagnostic client we are done with this source file. 222 CI.getDiagnosticClient().EndSourceFile(); 223 224 if (isCurrentFileAST()) { 225 CI.takeASTContext(); 226 CI.takePreprocessor(); 227 CI.takeSourceManager(); 228 CI.takeFileManager(); 229 } 230 231 setCompilerInstance(0); 232 setCurrentFile("", IK_None); 233} 234 235//===----------------------------------------------------------------------===// 236// Utility Actions 237//===----------------------------------------------------------------------===// 238 239void ASTFrontendAction::ExecuteAction() { 240 CompilerInstance &CI = getCompilerInstance(); 241 242 // FIXME: Move the truncation aspect of this into Sema, we delayed this till 243 // here so the source manager would be initialized. 244 if (hasCodeCompletionSupport() && 245 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 246 CI.createCodeCompletionConsumer(); 247 248 // Use a code completion consumer? 249 CodeCompleteConsumer *CompletionConsumer = 0; 250 if (CI.hasCodeCompletionConsumer()) 251 CompletionConsumer = &CI.getCodeCompletionConsumer(); 252 253 ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), 254 CI.getFrontendOpts().ShowStats, 255 usesCompleteTranslationUnit(), CompletionConsumer); 256} 257 258ASTConsumer * 259PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, 260 llvm::StringRef InFile) { 261 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); 262} 263