FrontendAction.cpp revision 2d602ab01fe1ee87df29961b7b1bde328c8ef6a0
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/Parse/ParseAST.h" 19#include "clang/Serialization/ASTDeserializationListener.h" 20#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 26namespace { 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 54 /// \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 89} // end anonymous namespace 90 91FrontendAction::FrontendAction() : Instance(0) {} 92 93FrontendAction::~FrontendAction() {} 94 95void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind, 96 ASTUnit *AST) { 97 CurrentFile = Value; 98 CurrentFileKind = Kind; 99 CurrentASTUnit.reset(AST); 100} 101 102bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 103 llvm::StringRef Filename, 104 InputKind InputKind) { 105 assert(!Instance && "Already processing a source file!"); 106 assert(!Filename.empty() && "Unexpected empty filename!"); 107 setCurrentFile(Filename, InputKind); 108 setCompilerInstance(&CI); 109 110 // AST files follow a very different path, since they share objects via the 111 // AST unit. 112 if (InputKind == IK_AST) { 113 assert(!usesPreprocessorOnly() && 114 "Attempt to pass AST file to preprocessor only action!"); 115 assert(hasASTFileSupport() && 116 "This action does not have AST file support!"); 117 118 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); 119 std::string Error; 120 ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags); 121 if (!AST) 122 goto failure; 123 124 setCurrentFile(Filename, InputKind, AST); 125 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 145 // Set up the file and source managers, if needed. 146 if (!CI.hasFileManager()) 147 CI.createFileManager(); 148 if (!CI.hasSourceManager()) 149 CI.createSourceManager(); 150 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. 167 CI.createPreprocessor(); 168 169 // 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(); 181 182 llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename)); 183 184 /// Use PCH? 185 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { 186 assert(hasPCHSupport() && "This action does not have PCH support!"); 187 ASTDeserializationListener *DeserialListener 188 = CI.getInvocation().getFrontendOpts().ChainedPCH ? 189 Consumer->GetASTDeserializationListener() : 0; 190 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) 191 DeserialListener = new DeserializedDeclsDumper(DeserialListener); 192 if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) 193 DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(), 194 CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn, 195 DeserialListener); 196 CI.createPCHExternalASTSource( 197 CI.getPreprocessorOpts().ImplicitPCHInclude, 198 CI.getPreprocessorOpts().DisablePCHValidation, 199 DeserialListener); 200 if (!CI.getASTContext().getExternalSource()) 201 goto failure; 202 } 203 204 CI.setASTConsumer(Consumer.take()); 205 if (!CI.hasASTConsumer()) 206 goto failure; 207 } 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(); 230 setCurrentFile("", IK_None); 231 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 = 247 llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>"); 248 CI.getSourceManager().createMainFileIDForMemBuffer(SB); 249 } else { 250 if (!CI.InitializeSourceManager(getCurrentFile())) 251 return; 252 } 253 254 if (CI.hasFrontendTimer()) { 255 llvm::TimeRegion Timer(CI.getFrontendTimer()); 256 ExecuteAction(); 257 } 258 else ExecuteAction(); 259} 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(); 273 if (!isCurrentFileAST()) { 274 CI.takeSema(); 275 CI.takeASTContext(); 276 } 277 } else { 278 if (!isCurrentFileAST()) { 279 CI.setSema(0); 280 CI.setASTContext(0); 281 } 282 CI.setASTConsumer(0); 283 } 284 285 // Inform the preprocessor we are done. 286 if (CI.hasPreprocessor()) 287 CI.getPreprocessor().EndSourceFile(); 288 289 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. 300 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); 301 302 // Inform the diagnostic client we are done with this source file. 303 CI.getDiagnosticClient().EndSourceFile(); 304 305 if (isCurrentFileAST()) { 306 CI.takeSema(); 307 CI.takeASTContext(); 308 CI.takePreprocessor(); 309 CI.takeSourceManager(); 310 CI.takeFileManager(); 311 } 312 313 setCompilerInstance(0); 314 setCurrentFile("", IK_None); 315} 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 335 if (!CI.hasSema()) 336 CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer); 337 338 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats); 339} 340 341ASTConsumer * 342PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, 343 llvm::StringRef InFile) { 344 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); 345} 346