FrontendAction.cpp revision 1f01f7c160c06f8290b4f1c203e36b242074c6b1
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.setModuleManager(static_cast<ASTReader*>( 298 &static_cast<ChainedIncludesSource*>(source.get())->getFinalReader())); 299 CI.getASTContext().setExternalSource(source); 300 301 } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { 302 // Use PCH. 303 assert(hasPCHSupport() && "This action does not have PCH support!"); 304 ASTDeserializationListener *DeserialListener = 305 Consumer->GetASTDeserializationListener(); 306 if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) 307 DeserialListener = new DeserializedDeclsDumper(DeserialListener); 308 if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) 309 DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(), 310 CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn, 311 DeserialListener); 312 CI.createPCHExternalASTSource( 313 CI.getPreprocessorOpts().ImplicitPCHInclude, 314 CI.getPreprocessorOpts().DisablePCHValidation, 315 CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, 316 DeserialListener); 317 if (!CI.getASTContext().getExternalSource()) 318 goto failure; 319 } 320 321 CI.setASTConsumer(Consumer.take()); 322 if (!CI.hasASTConsumer()) 323 goto failure; 324 } 325 326 // Initialize built-in info as long as we aren't using an external AST 327 // source. 328 if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { 329 Preprocessor &PP = CI.getPreprocessor(); 330 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), 331 PP.getLangOpts()); 332 } 333 334 // If there is a layout overrides file, attach an external AST source that 335 // provides the layouts from that file. 336 if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && 337 CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { 338 OwningPtr<ExternalASTSource> 339 Override(new LayoutOverrideSource( 340 CI.getFrontendOpts().OverrideRecordLayoutsFile)); 341 CI.getASTContext().setExternalSource(Override); 342 } 343 344 return true; 345 346 // If we failed, reset state since the client will not end up calling the 347 // matching EndSourceFile(). 348 failure: 349 if (isCurrentFileAST()) { 350 CI.setASTContext(0); 351 CI.setPreprocessor(0); 352 CI.setSourceManager(0); 353 CI.setFileManager(0); 354 } 355 356 if (HasBegunSourceFile) 357 CI.getDiagnosticClient().EndSourceFile(); 358 CI.clearOutputFiles(/*EraseFiles=*/true); 359 setCurrentInput(FrontendInputFile()); 360 setCompilerInstance(0); 361 return false; 362} 363 364bool FrontendAction::Execute() { 365 CompilerInstance &CI = getCompilerInstance(); 366 367 // Initialize the main file entry. This needs to be delayed until after PCH 368 // has loaded. 369 if (!isCurrentFileAST()) { 370 if (!CI.InitializeSourceManager(getCurrentInput())) 371 return false; 372 } 373 374 if (CI.hasFrontendTimer()) { 375 llvm::TimeRegion Timer(CI.getFrontendTimer()); 376 ExecuteAction(); 377 } 378 else ExecuteAction(); 379 380 // If we are supposed to rebuild the global module index, do so now unless 381 // there were any module-build failures. 382 if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() && 383 CI.hasPreprocessor()) { 384 GlobalModuleIndex::writeIndex( 385 CI.getFileManager(), 386 CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath()); 387 } 388 389 return true; 390} 391 392void FrontendAction::EndSourceFile() { 393 CompilerInstance &CI = getCompilerInstance(); 394 395 // Inform the diagnostic client we are done with this source file. 396 CI.getDiagnosticClient().EndSourceFile(); 397 398 // Finalize the action. 399 EndSourceFileAction(); 400 401 // Release the consumer and the AST, in that order since the consumer may 402 // perform actions in its destructor which require the context. 403 // 404 // FIXME: There is more per-file stuff we could just drop here? 405 if (CI.getFrontendOpts().DisableFree) { 406 CI.takeASTConsumer(); 407 if (!isCurrentFileAST()) { 408 CI.takeSema(); 409 CI.resetAndLeakASTContext(); 410 } 411 } else { 412 if (!isCurrentFileAST()) { 413 CI.setSema(0); 414 CI.setASTContext(0); 415 } 416 CI.setASTConsumer(0); 417 } 418 419 // Inform the preprocessor we are done. 420 if (CI.hasPreprocessor()) 421 CI.getPreprocessor().EndSourceFile(); 422 423 if (CI.getFrontendOpts().ShowStats) { 424 llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; 425 CI.getPreprocessor().PrintStats(); 426 CI.getPreprocessor().getIdentifierTable().PrintStats(); 427 CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); 428 CI.getSourceManager().PrintStats(); 429 llvm::errs() << "\n"; 430 } 431 432 // Cleanup the output streams, and erase the output files if instructed by the 433 // FrontendAction. 434 CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles()); 435 436 if (isCurrentFileAST()) { 437 CI.takeSema(); 438 CI.resetAndLeakASTContext(); 439 CI.resetAndLeakPreprocessor(); 440 CI.resetAndLeakSourceManager(); 441 CI.resetAndLeakFileManager(); 442 } 443 444 setCompilerInstance(0); 445 setCurrentInput(FrontendInputFile()); 446} 447 448bool FrontendAction::shouldEraseOutputFiles() { 449 return getCompilerInstance().getDiagnostics().hasErrorOccurred(); 450} 451 452//===----------------------------------------------------------------------===// 453// Utility Actions 454//===----------------------------------------------------------------------===// 455 456void ASTFrontendAction::ExecuteAction() { 457 CompilerInstance &CI = getCompilerInstance(); 458 459 // FIXME: Move the truncation aspect of this into Sema, we delayed this till 460 // here so the source manager would be initialized. 461 if (hasCodeCompletionSupport() && 462 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 463 CI.createCodeCompletionConsumer(); 464 465 // Use a code completion consumer? 466 CodeCompleteConsumer *CompletionConsumer = 0; 467 if (CI.hasCodeCompletionConsumer()) 468 CompletionConsumer = &CI.getCodeCompletionConsumer(); 469 470 if (!CI.hasSema()) 471 CI.createSema(getTranslationUnitKind(), CompletionConsumer); 472 473 ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats, 474 CI.getFrontendOpts().SkipFunctionBodies); 475} 476 477void PluginASTAction::anchor() { } 478 479ASTConsumer * 480PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, 481 StringRef InFile) { 482 llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); 483} 484 485ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI, 486 StringRef InFile) { 487 return WrappedAction->CreateASTConsumer(CI, InFile); 488} 489bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) { 490 return WrappedAction->BeginInvocation(CI); 491} 492bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI, 493 StringRef Filename) { 494 WrappedAction->setCurrentInput(getCurrentInput()); 495 WrappedAction->setCompilerInstance(&CI); 496 return WrappedAction->BeginSourceFileAction(CI, Filename); 497} 498void WrapperFrontendAction::ExecuteAction() { 499 WrappedAction->ExecuteAction(); 500} 501void WrapperFrontendAction::EndSourceFileAction() { 502 WrappedAction->EndSourceFileAction(); 503} 504 505bool WrapperFrontendAction::usesPreprocessorOnly() const { 506 return WrappedAction->usesPreprocessorOnly(); 507} 508TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() { 509 return WrappedAction->getTranslationUnitKind(); 510} 511bool WrapperFrontendAction::hasPCHSupport() const { 512 return WrappedAction->hasPCHSupport(); 513} 514bool WrapperFrontendAction::hasASTFileSupport() const { 515 return WrappedAction->hasASTFileSupport(); 516} 517bool WrapperFrontendAction::hasIRSupport() const { 518 return WrappedAction->hasIRSupport(); 519} 520bool WrapperFrontendAction::hasCodeCompletionSupport() const { 521 return WrappedAction->hasCodeCompletionSupport(); 522} 523 524WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction) 525 : WrappedAction(WrappedAction) {} 526 527