FrontendAction.cpp revision d560ce3b66325ff22cd3aca23c6de3143bd74d24
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/AST/DeclGroup.h" 14#include "clang/Frontend/ASTUnit.h" 15#include "clang/Frontend/ChainedIncludesSource.h" 16#include "clang/Frontend/CompilerInstance.h" 17#include "clang/Frontend/FrontendDiagnostic.h" 18#include "clang/Frontend/FrontendPluginRegistry.h" 19#include "clang/Frontend/LayoutOverrideSource.h" 20#include "clang/Frontend/MultiplexConsumer.h" 21#include "clang/Lex/HeaderSearch.h" 22#include "clang/Lex/Preprocessor.h" 23#include "clang/Parse/ParseAST.h" 24#include "clang/Serialization/ASTDeserializationListener.h" 25#include "clang/Serialization/ASTReader.h" 26#include "clang/Serialization/GlobalModuleIndex.h" 27#include "llvm/Support/ErrorHandling.h" 28#include "llvm/Support/FileSystem.h" 29#include "llvm/Support/MemoryBuffer.h" 30#include "llvm/Support/Timer.h" 31#include "llvm/Support/raw_ostream.h" 32#include "llvm/Support/system_error.h" 33using namespace clang; 34 35namespace { 36 37class DelegatingDeserializationListener : public ASTDeserializationListener { 38 ASTDeserializationListener *Previous; 39 40public: 41 explicit DelegatingDeserializationListener( 42 ASTDeserializationListener *Previous) 43 : Previous(Previous) { } 44 45 virtual void ReaderInitialized(ASTReader *Reader) { 46 if (Previous) 47 Previous->ReaderInitialized(Reader); 48 } 49 virtual void IdentifierRead(serialization::IdentID ID, 50 IdentifierInfo *II) { 51 if (Previous) 52 Previous->IdentifierRead(ID, II); 53 } 54 virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { 55 if (Previous) 56 Previous->TypeRead(Idx, T); 57 } 58 virtual void DeclRead(serialization::DeclID ID, const Decl *D) { 59 if (Previous) 60 Previous->DeclRead(ID, D); 61 } 62 virtual void SelectorRead(serialization::SelectorID ID, Selector Sel) { 63 if (Previous) 64 Previous->SelectorRead(ID, Sel); 65 } 66 virtual void MacroDefinitionRead(serialization::PreprocessedEntityID PPID, 67 MacroDefinition *MD) { 68 if (Previous) 69 Previous->MacroDefinitionRead(PPID, MD); 70 } 71}; 72 73/// \brief Dumps deserialized declarations. 74class DeserializedDeclsDumper : public DelegatingDeserializationListener { 75public: 76 explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous) 77 : DelegatingDeserializationListener(Previous) { } 78 79 virtual void DeclRead(serialization::DeclID ID, const Decl *D) { 80 llvm::outs() << "PCH DECL: " << D->getDeclKindName(); 81 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) 82 llvm::outs() << " - " << *ND; 83 llvm::outs() << "\n"; 84 85 DelegatingDeserializationListener::DeclRead(ID, D); 86 } 87}; 88 89/// \brief Checks deserialized declarations and emits error if a name 90/// matches one given in command-line using -error-on-deserialized-decl. 91class DeserializedDeclsChecker : public DelegatingDeserializationListener { 92 ASTContext &Ctx; 93 std::set<std::string> NamesToCheck; 94 95public: 96 DeserializedDeclsChecker(ASTContext &Ctx, 97 const std::set<std::string> &NamesToCheck, 98 ASTDeserializationListener *Previous) 99 : DelegatingDeserializationListener(Previous), 100 Ctx(Ctx), NamesToCheck(NamesToCheck) { } 101 102 virtual void DeclRead(serialization::DeclID ID, const Decl *D) { 103 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) 104 if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) { 105 unsigned DiagID 106 = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, 107 "%0 was deserialized"); 108 Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) 109 << ND->getNameAsString(); 110 } 111 112 DelegatingDeserializationListener::DeclRead(ID, D); 113 } 114}; 115 116} // end anonymous namespace 117 118FrontendAction::FrontendAction() : Instance(0) {} 119 120FrontendAction::~FrontendAction() {} 121 122void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput, 123 ASTUnit *AST) { 124 this->CurrentInput = CurrentInput; 125 CurrentASTUnit.reset(AST); 126} 127 128ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, 129 StringRef InFile) { 130 ASTConsumer* Consumer = CreateASTConsumer(CI, InFile); 131 if (!Consumer) 132 return 0; 133 134 if (CI.getFrontendOpts().AddPluginActions.size() == 0) 135 return Consumer; 136 137 // Make sure the non-plugin consumer is first, so that plugins can't 138 // modifiy the AST. 139 std::vector<ASTConsumer*> Consumers(1, Consumer); 140 141 for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size(); 142 i != e; ++i) { 143 // This is O(|plugins| * |add_plugins|), but since both numbers are 144 // way below 50 in practice, that's ok. 145 for (FrontendPluginRegistry::iterator 146 it = FrontendPluginRegistry::begin(), 147 ie = FrontendPluginRegistry::end(); 148 it != ie; ++it) { 149 if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) { 150 OwningPtr<PluginASTAction> P(it->instantiate()); 151 FrontendAction* c = P.get(); 152 if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i])) 153 Consumers.push_back(c->CreateASTConsumer(CI, InFile)); 154 } 155 } 156 } 157 158 return new MultiplexConsumer(Consumers); 159} 160 161 162bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 163 const FrontendInputFile &Input) { 164 assert(!Instance && "Already processing a source file!"); 165 assert(!Input.isEmpty() && "Unexpected empty filename!"); 166 setCurrentInput(Input); 167 setCompilerInstance(&CI); 168 169 StringRef InputFile = Input.getFile(); 170 bool HasBegunSourceFile = false; 171 if (!BeginInvocation(CI)) 172 goto failure; 173 174 // AST files follow a very different path, since they share objects via the 175 // AST unit. 176 if (Input.getKind() == IK_AST) { 177 assert(!usesPreprocessorOnly() && 178 "Attempt to pass AST file to preprocessor only action!"); 179 assert(hasASTFileSupport() && 180 "This action does not have AST file support!"); 181 182 IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); 183 std::string Error; 184 ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags, 185 CI.getFileSystemOpts()); 186 if (!AST) 187 goto failure; 188 189 setCurrentInput(Input, AST); 190 191 // Inform the diagnostic client we are processing a source file. 192 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); 193 HasBegunSourceFile = true; 194 195 // Set the shared objects, these are reset when we finish processing the 196 // file, otherwise the CompilerInstance will happily destroy them. 197 CI.setFileManager(&AST->getFileManager()); 198 CI.setSourceManager(&AST->getSourceManager()); 199 CI.setPreprocessor(&AST->getPreprocessor()); 200 CI.setASTContext(&AST->getASTContext()); 201 202 // Initialize the action. 203 if (!BeginSourceFileAction(CI, InputFile)) 204 goto failure; 205 206 // Create the AST consumer. 207 CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile)); 208 if (!CI.hasASTConsumer()) 209 goto failure; 210 211 return true; 212 } 213 214 // Set up the file and source managers, if needed. 215 if (!CI.hasFileManager()) 216 CI.createFileManager(); 217 if (!CI.hasSourceManager()) 218 CI.createSourceManager(CI.getFileManager()); 219 220 // IR files bypass the rest of initialization. 221 if (Input.getKind() == IK_LLVM_IR) { 222 assert(hasIRSupport() && 223 "This action does not have IR file support!"); 224 225 // Inform the diagnostic client we are processing a source file. 226 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0); 227 HasBegunSourceFile = true; 228 229 // Initialize the action. 230 if (!BeginSourceFileAction(CI, InputFile)) 231 goto failure; 232 233 return true; 234 } 235 236 // If the implicit PCH include is actually a directory, rather than 237 // a single file, search for a suitable PCH file in that directory. 238 if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { 239 FileManager &FileMgr = CI.getFileManager(); 240 PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); 241 StringRef PCHInclude = PPOpts.ImplicitPCHInclude; 242 if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) { 243 llvm::error_code EC; 244 SmallString<128> DirNative; 245 llvm::sys::path::native(PCHDir->getName(), DirNative); 246 bool Found = false; 247 for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; 248 Dir != DirEnd && !EC; Dir.increment(EC)) { 249 // Check whether this is an acceptable AST file. 250 if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr, 251 CI.getLangOpts(), 252 CI.getTargetOpts(), 253 CI.getPreprocessorOpts())) { 254 PPOpts.ImplicitPCHInclude = Dir->path(); 255 Found = true; 256 break; 257 } 258 } 259 260 if (!Found) { 261 CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude; 262 return true; 263 } 264 } 265 } 266 267 // Set up the preprocessor. 268 CI.createPreprocessor(); 269 270 // Inform the diagnostic client we are processing a source file. 271 CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 272 &CI.getPreprocessor()); 273 HasBegunSourceFile = true; 274 275 // Initialize the action. 276 if (!BeginSourceFileAction(CI, InputFile)) 277 goto failure; 278 279 // Create the AST context and consumer unless this is a preprocessor only 280 // action. 281 if (!usesPreprocessorOnly()) { 282 CI.createASTContext(); 283 284 OwningPtr<ASTConsumer> Consumer( 285 CreateWrappedASTConsumer(CI, InputFile)); 286 if (!Consumer) 287 goto failure; 288 289 CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); 290 291 if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { 292 // Convert headers to PCH and chain them. 293 OwningPtr<ExternalASTSource> source; 294 source.reset(ChainedIncludesSource::create(CI)); 295 if (!source) 296 goto failure; 297 CI.getASTContext().setExternalSource(source); 298 299 } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { 300 // Use PCH. 301 assert(hasPCHSupport() && "This action does not have PCH support!"); 302 ASTDeserializationListener *DeserialListener = 303 Consumer->GetASTDeserializationListener(); 304 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) 305 DeserialListener = new DeserializedDeclsDumper(DeserialListener); 306 if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) 307 DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(), 308 CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn, 309 DeserialListener); 310 CI.createPCHExternalASTSource( 311 CI.getPreprocessorOpts().ImplicitPCHInclude, 312 CI.getPreprocessorOpts().DisablePCHValidation, 313 CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, 314 DeserialListener); 315 if (!CI.getASTContext().getExternalSource()) 316 goto failure; 317 } 318 319 CI.setASTConsumer(Consumer.take()); 320 if (!CI.hasASTConsumer()) 321 goto failure; 322 } 323 324 // Initialize built-in info as long as we aren't using an external AST 325 // source. 326 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { 327 Preprocessor &PP = CI.getPreprocessor(); 328 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), 329 PP.getLangOpts()); 330 } 331 332 // If there is a layout overrides file, attach an external AST source that 333 // provides the layouts from that file. 334 if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && 335 CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { 336 OwningPtr<ExternalASTSource> 337 Override(new LayoutOverrideSource( 338 CI.getFrontendOpts().OverrideRecordLayoutsFile)); 339 CI.getASTContext().setExternalSource(Override); 340 } 341 342 return true; 343 344 // If we failed, reset state since the client will not end up calling the 345 // matching EndSourceFile(). 346 failure: 347 if (isCurrentFileAST()) { 348 CI.setASTContext(0); 349 CI.setPreprocessor(0); 350 CI.setSourceManager(0); 351 CI.setFileManager(0); 352 } 353 354 if (HasBegunSourceFile) 355 CI.getDiagnosticClient().EndSourceFile(); 356 CI.clearOutputFiles(/*EraseFiles=*/true); 357 setCurrentInput(FrontendInputFile()); 358 setCompilerInstance(0); 359 return false; 360} 361 362bool FrontendAction::Execute() { 363 CompilerInstance &CI = getCompilerInstance(); 364 365 // Initialize the main file entry. This needs to be delayed until after PCH 366 // has loaded. 367 if (!isCurrentFileAST()) { 368 if (!CI.InitializeSourceManager(getCurrentInput())) 369 return false; 370 } 371 372 if (CI.hasFrontendTimer()) { 373 llvm::TimeRegion Timer(CI.getFrontendTimer()); 374 ExecuteAction(); 375 } 376 else ExecuteAction(); 377 378 // If we are supposed to rebuild the global module index, do so now unless 379 // there were any module-build failures. 380 if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() && 381 CI.hasPreprocessor()) { 382 GlobalModuleIndex::writeIndex( 383 CI.getFileManager(), 384 CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); 385 } 386 387 return true; 388} 389 390void FrontendAction::EndSourceFile() { 391 CompilerInstance &CI = getCompilerInstance(); 392 393 // Inform the diagnostic client we are done with this source file. 394 CI.getDiagnosticClient().EndSourceFile(); 395 396 // Finalize the action. 397 EndSourceFileAction(); 398 399 // Release the consumer and the AST, in that order since the consumer may 400 // perform actions in its destructor which require the context. 401 // 402 // FIXME: There is more per-file stuff we could just drop here? 403 if (CI.getFrontendOpts().DisableFree) { 404 CI.takeASTConsumer(); 405 if (!isCurrentFileAST()) { 406 CI.takeSema(); 407 CI.resetAndLeakASTContext(); 408 } 409 } else { 410 if (!isCurrentFileAST()) { 411 CI.setSema(0); 412 CI.setASTContext(0); 413 } 414 CI.setASTConsumer(0); 415 } 416 417 // Inform the preprocessor we are done. 418 if (CI.hasPreprocessor()) 419 CI.getPreprocessor().EndSourceFile(); 420 421 if (CI.getFrontendOpts().ShowStats) { 422 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; 423 CI.getPreprocessor().PrintStats(); 424 CI.getPreprocessor().getIdentifierTable().PrintStats(); 425 CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); 426 CI.getSourceManager().PrintStats(); 427 llvm::errs() << "\n"; 428 } 429 430 // Cleanup the output streams, and erase the output files if we encountered 431 // an error. 432 CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred()); 433 434 if (isCurrentFileAST()) { 435 CI.takeSema(); 436 CI.resetAndLeakASTContext(); 437 CI.resetAndLeakPreprocessor(); 438 CI.resetAndLeakSourceManager(); 439 CI.resetAndLeakFileManager(); 440 } 441 442 setCompilerInstance(0); 443 setCurrentInput(FrontendInputFile()); 444} 445 446//===----------------------------------------------------------------------===// 447// Utility Actions 448//===----------------------------------------------------------------------===// 449 450void ASTFrontendAction::ExecuteAction() { 451 CompilerInstance &CI = getCompilerInstance(); 452 453 // FIXME: Move the truncation aspect of this into Sema, we delayed this till 454 // here so the source manager would be initialized. 455 if (hasCodeCompletionSupport() && 456 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 457 CI.createCodeCompletionConsumer(); 458 459 // Use a code completion consumer? 460 CodeCompleteConsumer *CompletionConsumer = 0; 461 if (CI.hasCodeCompletionConsumer()) 462 CompletionConsumer = &CI.getCodeCompletionConsumer(); 463 464 if (!CI.hasSema()) 465 CI.createSema(getTranslationUnitKind(), CompletionConsumer); 466 467 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats, 468 CI.getFrontendOpts().SkipFunctionBodies); 469} 470 471void PluginASTAction::anchor() { } 472 473ASTConsumer * 474PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, 475 StringRef InFile) { 476 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); 477} 478 479ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, 480 StringRef InFile) { 481 return WrappedAction->CreateASTConsumer(CI, InFile); 482} 483bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { 484 return WrappedAction->BeginInvocation(CI); 485} 486bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, 487 StringRef Filename) { 488 WrappedAction->setCurrentInput(getCurrentInput()); 489 WrappedAction->setCompilerInstance(&CI); 490 return WrappedAction->BeginSourceFileAction(CI, Filename); 491} 492void WrapperFrontendAction::ExecuteAction() { 493 WrappedAction->ExecuteAction(); 494} 495void WrapperFrontendAction::EndSourceFileAction() { 496 WrappedAction->EndSourceFileAction(); 497} 498 499bool WrapperFrontendAction::usesPreprocessorOnly() const { 500 return WrappedAction->usesPreprocessorOnly(); 501} 502TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() { 503 return WrappedAction->getTranslationUnitKind(); 504} 505bool WrapperFrontendAction::hasPCHSupport() const { 506 return WrappedAction->hasPCHSupport(); 507} 508bool WrapperFrontendAction::hasASTFileSupport() const { 509 return WrappedAction->hasASTFileSupport(); 510} 511bool WrapperFrontendAction::hasIRSupport() const { 512 return WrappedAction->hasIRSupport(); 513} 514bool WrapperFrontendAction::hasCodeCompletionSupport() const { 515 return WrappedAction->hasCodeCompletionSupport(); 516} 517 518WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction) 519 : WrappedAction(WrappedAction) {} 520 521