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