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