CompilerInstance.cpp revision 47e65e63326505b86ac2e0dfb20c13b6c71db714
1//===--- CompilerInstance.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/CompilerInstance.h" 11#include "clang/Sema/Sema.h" 12#include "clang/AST/ASTConsumer.h" 13#include "clang/AST/ASTContext.h" 14#include "clang/Basic/Diagnostic.h" 15#include "clang/Basic/FileManager.h" 16#include "clang/Basic/SourceManager.h" 17#include "clang/Basic/TargetInfo.h" 18#include "clang/Basic/Version.h" 19#include "clang/Lex/HeaderSearch.h" 20#include "clang/Lex/Preprocessor.h" 21#include "clang/Lex/PTHManager.h" 22#include "clang/Frontend/ChainedDiagnosticClient.h" 23#include "clang/Frontend/FrontendAction.h" 24#include "clang/Frontend/FrontendDiagnostic.h" 25#include "clang/Frontend/TextDiagnosticPrinter.h" 26#include "clang/Frontend/VerifyDiagnosticsClient.h" 27#include "clang/Frontend/Utils.h" 28#include "clang/Serialization/ASTReader.h" 29#include "clang/Sema/CodeCompleteConsumer.h" 30#include "llvm/LLVMContext.h" 31#include "llvm/Support/MemoryBuffer.h" 32#include "llvm/Support/raw_ostream.h" 33#include "llvm/ADT/Statistic.h" 34#include "llvm/Support/Timer.h" 35#include "llvm/System/Host.h" 36#include "llvm/System/Path.h" 37#include "llvm/System/Program.h" 38using namespace clang; 39 40CompilerInstance::CompilerInstance() 41 : Invocation(new CompilerInvocation()) { 42} 43 44CompilerInstance::~CompilerInstance() { 45} 46 47void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) { 48 LLVMContext.reset(Value); 49} 50 51void CompilerInstance::setInvocation(CompilerInvocation *Value) { 52 Invocation.reset(Value); 53} 54 55void CompilerInstance::setDiagnostics(Diagnostic *Value) { 56 Diagnostics = Value; 57} 58 59void CompilerInstance::setTarget(TargetInfo *Value) { 60 Target.reset(Value); 61} 62 63void CompilerInstance::setFileManager(FileManager *Value) { 64 FileMgr.reset(Value); 65} 66 67void CompilerInstance::setSourceManager(SourceManager *Value) { 68 SourceMgr.reset(Value); 69} 70 71void CompilerInstance::setPreprocessor(Preprocessor *Value) { 72 PP.reset(Value); 73} 74 75void CompilerInstance::setASTContext(ASTContext *Value) { 76 Context.reset(Value); 77} 78 79void CompilerInstance::setSema(Sema *S) { 80 TheSema.reset(S); 81} 82 83void CompilerInstance::setASTConsumer(ASTConsumer *Value) { 84 Consumer.reset(Value); 85} 86 87void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { 88 CompletionConsumer.reset(Value); 89} 90 91// Diagnostics 92namespace { 93 class BinaryDiagnosticSerializer : public DiagnosticClient { 94 llvm::raw_ostream &OS; 95 SourceManager *SourceMgr; 96 public: 97 explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS) 98 : OS(OS), SourceMgr(0) { } 99 100 virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, 101 const DiagnosticInfo &Info); 102 }; 103} 104 105void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, 106 const DiagnosticInfo &Info) { 107 StoredDiagnostic(DiagLevel, Info).Serialize(OS); 108} 109 110static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 111 unsigned argc, char **argv, 112 Diagnostic &Diags) { 113 std::string ErrorInfo; 114 llvm::OwningPtr<llvm::raw_ostream> OS( 115 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); 116 if (!ErrorInfo.empty()) { 117 Diags.Report(diag::err_fe_unable_to_open_logfile) 118 << DiagOpts.DumpBuildInformation << ErrorInfo; 119 return; 120 } 121 122 (*OS) << "clang -cc1 command line arguments: "; 123 for (unsigned i = 0; i != argc; ++i) 124 (*OS) << argv[i] << ' '; 125 (*OS) << '\n'; 126 127 // Chain in a diagnostic client which will log the diagnostics. 128 DiagnosticClient *Logger = 129 new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); 130 Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); 131} 132 133void CompilerInstance::createDiagnostics(int Argc, char **Argv) { 134 Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv); 135} 136 137llvm::IntrusiveRefCntPtr<Diagnostic> 138CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 139 int Argc, char **Argv) { 140 llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic()); 141 142 // Create the diagnostic client for reporting errors or for 143 // implementing -verify. 144 llvm::OwningPtr<DiagnosticClient> DiagClient; 145 if (Opts.BinaryOutput) { 146 if (llvm::sys::Program::ChangeStderrToBinary()) { 147 // We weren't able to set standard error to binary, which is a 148 // bit of a problem. So, just create a text diagnostic printer 149 // to complain about this problem, and pretend that the user 150 // didn't try to use binary output. 151 Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); 152 Diags->Report(diag::err_fe_stderr_binary); 153 return Diags; 154 } else { 155 Diags->setClient(new BinaryDiagnosticSerializer(llvm::errs())); 156 } 157 } else { 158 Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); 159 } 160 161 // Chain in -verify checker, if requested. 162 if (Opts.VerifyDiagnostics) 163 Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); 164 165 if (!Opts.DumpBuildInformation.empty()) 166 SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); 167 168 // Configure our handling of diagnostics. 169 ProcessWarningOptions(*Diags, Opts); 170 171 return Diags; 172} 173 174// File Manager 175 176void CompilerInstance::createFileManager() { 177 FileMgr.reset(new FileManager()); 178} 179 180// Source Manager 181 182void CompilerInstance::createSourceManager() { 183 SourceMgr.reset(new SourceManager(getDiagnostics())); 184} 185 186// Preprocessor 187 188void CompilerInstance::createPreprocessor() { 189 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 190 getPreprocessorOpts(), getHeaderSearchOpts(), 191 getDependencyOutputOpts(), getTarget(), 192 getFrontendOpts(), getSourceManager(), 193 getFileManager())); 194} 195 196Preprocessor * 197CompilerInstance::createPreprocessor(Diagnostic &Diags, 198 const LangOptions &LangInfo, 199 const PreprocessorOptions &PPOpts, 200 const HeaderSearchOptions &HSOpts, 201 const DependencyOutputOptions &DepOpts, 202 const TargetInfo &Target, 203 const FrontendOptions &FEOpts, 204 SourceManager &SourceMgr, 205 FileManager &FileMgr) { 206 // Create a PTH manager if we are using some form of a token cache. 207 PTHManager *PTHMgr = 0; 208 if (!PPOpts.TokenCache.empty()) 209 PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); 210 211 // Create the Preprocessor. 212 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 213 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 214 SourceMgr, *HeaderInfo, PTHMgr, 215 /*OwnsHeaderSearch=*/true); 216 217 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 218 // That argument is used as the IdentifierInfoLookup argument to 219 // IdentifierTable's ctor. 220 if (PTHMgr) { 221 PTHMgr->setPreprocessor(PP); 222 PP->setPTHManager(PTHMgr); 223 } 224 225 if (PPOpts.DetailedRecord) 226 PP->createPreprocessingRecord(); 227 228 InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); 229 230 // Handle generating dependencies, if requested. 231 if (!DepOpts.OutputFile.empty()) 232 AttachDependencyFileGen(*PP, DepOpts); 233 234 return PP; 235} 236 237// ASTContext 238 239void CompilerInstance::createASTContext() { 240 Preprocessor &PP = getPreprocessor(); 241 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 242 getTarget(), PP.getIdentifierTable(), 243 PP.getSelectorTable(), PP.getBuiltinInfo(), 244 /*size_reserve=*/ 0)); 245} 246 247// ExternalASTSource 248 249void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 250 bool DisablePCHValidation, 251 void *DeserializationListener){ 252 llvm::OwningPtr<ExternalASTSource> Source; 253 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 254 DisablePCHValidation, 255 getPreprocessor(), getASTContext(), 256 DeserializationListener)); 257 getASTContext().setExternalSource(Source); 258} 259 260ExternalASTSource * 261CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 262 const std::string &Sysroot, 263 bool DisablePCHValidation, 264 Preprocessor &PP, 265 ASTContext &Context, 266 void *DeserializationListener) { 267 llvm::OwningPtr<ASTReader> Reader; 268 Reader.reset(new ASTReader(PP, &Context, 269 Sysroot.empty() ? 0 : Sysroot.c_str(), 270 DisablePCHValidation)); 271 272 Reader->setDeserializationListener( 273 static_cast<ASTDeserializationListener *>(DeserializationListener)); 274 switch (Reader->ReadAST(Path)) { 275 case ASTReader::Success: 276 // Set the predefines buffer as suggested by the PCH reader. Typically, the 277 // predefines buffer will be empty. 278 PP.setPredefines(Reader->getSuggestedPredefines()); 279 return Reader.take(); 280 281 case ASTReader::Failure: 282 // Unrecoverable failure: don't even try to process the input file. 283 break; 284 285 case ASTReader::IgnorePCH: 286 // No suitable PCH file could be found. Return an error. 287 break; 288 } 289 290 return 0; 291} 292 293// Code Completion 294 295static bool EnableCodeCompletion(Preprocessor &PP, 296 const std::string &Filename, 297 unsigned Line, 298 unsigned Column) { 299 // Tell the source manager to chop off the given file at a specific 300 // line and column. 301 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 302 if (!Entry) { 303 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 304 << Filename; 305 return true; 306 } 307 308 // Truncate the named file at the given line/column. 309 PP.SetCodeCompletionPoint(Entry, Line, Column); 310 return false; 311} 312 313void CompilerInstance::createCodeCompletionConsumer() { 314 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 315 if (!CompletionConsumer) { 316 CompletionConsumer.reset( 317 createCodeCompletionConsumer(getPreprocessor(), 318 Loc.FileName, Loc.Line, Loc.Column, 319 getFrontendOpts().DebugCodeCompletionPrinter, 320 getFrontendOpts().ShowMacrosInCodeCompletion, 321 getFrontendOpts().ShowCodePatternsInCodeCompletion, 322 getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, 323 llvm::outs())); 324 if (!CompletionConsumer) 325 return; 326 } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, 327 Loc.Line, Loc.Column)) { 328 CompletionConsumer.reset(); 329 return; 330 } 331 332 if (CompletionConsumer->isOutputBinary() && 333 llvm::sys::Program::ChangeStdoutToBinary()) { 334 getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); 335 CompletionConsumer.reset(); 336 } 337} 338 339void CompilerInstance::createFrontendTimer() { 340 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 341} 342 343CodeCompleteConsumer * 344CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 345 const std::string &Filename, 346 unsigned Line, 347 unsigned Column, 348 bool UseDebugPrinter, 349 bool ShowMacros, 350 bool ShowCodePatterns, 351 bool ShowGlobals, 352 llvm::raw_ostream &OS) { 353 if (EnableCodeCompletion(PP, Filename, Line, Column)) 354 return 0; 355 356 // Set up the creation routine for code-completion. 357 if (UseDebugPrinter) 358 return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, 359 ShowGlobals, OS); 360 else 361 return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, 362 ShowGlobals, OS); 363} 364 365void CompilerInstance::createSema(bool CompleteTranslationUnit, 366 CodeCompleteConsumer *CompletionConsumer) { 367 TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), 368 CompleteTranslationUnit, CompletionConsumer)); 369} 370 371// Output Files 372 373void CompilerInstance::addOutputFile(llvm::StringRef Path, 374 llvm::raw_ostream *OS) { 375 assert(OS && "Attempt to add empty stream to output list!"); 376 OutputFiles.push_back(std::make_pair(Path, OS)); 377} 378 379void CompilerInstance::clearOutputFiles(bool EraseFiles) { 380 for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator 381 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 382 delete it->second; 383 if (EraseFiles && !it->first.empty()) 384 llvm::sys::Path(it->first).eraseFromDisk(); 385 } 386 OutputFiles.clear(); 387} 388 389llvm::raw_fd_ostream * 390CompilerInstance::createDefaultOutputFile(bool Binary, 391 llvm::StringRef InFile, 392 llvm::StringRef Extension) { 393 return createOutputFile(getFrontendOpts().OutputFile, Binary, 394 InFile, Extension); 395} 396 397llvm::raw_fd_ostream * 398CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 399 bool Binary, 400 llvm::StringRef InFile, 401 llvm::StringRef Extension) { 402 std::string Error, OutputPathName; 403 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 404 InFile, Extension, 405 &OutputPathName); 406 if (!OS) { 407 getDiagnostics().Report(diag::err_fe_unable_to_open_output) 408 << OutputPath << Error; 409 return 0; 410 } 411 412 // Add the output file -- but don't try to remove "-", since this means we are 413 // using stdin. 414 addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); 415 416 return OS; 417} 418 419llvm::raw_fd_ostream * 420CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 421 std::string &Error, 422 bool Binary, 423 llvm::StringRef InFile, 424 llvm::StringRef Extension, 425 std::string *ResultPathName) { 426 std::string OutFile; 427 if (!OutputPath.empty()) { 428 OutFile = OutputPath; 429 } else if (InFile == "-") { 430 OutFile = "-"; 431 } else if (!Extension.empty()) { 432 llvm::sys::Path Path(InFile); 433 Path.eraseSuffix(); 434 Path.appendSuffix(Extension); 435 OutFile = Path.str(); 436 } else { 437 OutFile = "-"; 438 } 439 440 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 441 new llvm::raw_fd_ostream(OutFile.c_str(), Error, 442 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 443 if (!Error.empty()) 444 return 0; 445 446 if (ResultPathName) 447 *ResultPathName = OutFile; 448 449 return OS.take(); 450} 451 452// Initialization Utilities 453 454bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 455 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 456 getSourceManager(), getFrontendOpts()); 457} 458 459bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 460 Diagnostic &Diags, 461 FileManager &FileMgr, 462 SourceManager &SourceMgr, 463 const FrontendOptions &Opts) { 464 // Figure out where to get and map in the main file. 465 if (InputFile != "-") { 466 const FileEntry *File = FileMgr.getFile(InputFile); 467 if (File) SourceMgr.createMainFileID(File, SourceLocation()); 468 if (SourceMgr.getMainFileID().isInvalid()) { 469 Diags.Report(diag::err_fe_error_reading) << InputFile; 470 return false; 471 } 472 } else { 473 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); 474 if (SB) SourceMgr.createMainFileIDForMemBuffer(SB); 475 if (SourceMgr.getMainFileID().isInvalid()) { 476 Diags.Report(diag::err_fe_error_reading_stdin); 477 return false; 478 } 479 } 480 481 return true; 482} 483 484// High-Level Operations 485 486bool CompilerInstance::ExecuteAction(FrontendAction &Act) { 487 assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); 488 assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); 489 assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); 490 491 // FIXME: Take this as an argument, once all the APIs we used have moved to 492 // taking it as an input instead of hard-coding llvm::errs. 493 llvm::raw_ostream &OS = llvm::errs(); 494 495 // Create the target instance. 496 setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); 497 if (!hasTarget()) 498 return false; 499 500 // Inform the target of the language options. 501 // 502 // FIXME: We shouldn't need to do this, the target should be immutable once 503 // created. This complexity should be lifted elsewhere. 504 getTarget().setForcedLangOptions(getLangOpts()); 505 506 // Validate/process some options. 507 if (getHeaderSearchOpts().Verbose) 508 OS << "clang -cc1 version " CLANG_VERSION_STRING 509 << " based upon " << PACKAGE_STRING 510 << " hosted on " << llvm::sys::getHostTriple() << "\n"; 511 512 if (getFrontendOpts().ShowTimers) 513 createFrontendTimer(); 514 515 if (getFrontendOpts().ShowStats) 516 llvm::EnableStatistics(); 517 518 for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { 519 const std::string &InFile = getFrontendOpts().Inputs[i].second; 520 521 // Reset the ID tables if we are reusing the SourceManager. 522 if (hasSourceManager()) 523 getSourceManager().clearIDTables(); 524 525 if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) { 526 Act.Execute(); 527 Act.EndSourceFile(); 528 } 529 } 530 531 if (getDiagnosticOpts().ShowCarets) { 532 unsigned NumWarnings = getDiagnostics().getNumWarnings(); 533 unsigned NumErrors = getDiagnostics().getNumErrors() - 534 getDiagnostics().getNumErrorsSuppressed(); 535 536 if (NumWarnings) 537 OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); 538 if (NumWarnings && NumErrors) 539 OS << " and "; 540 if (NumErrors) 541 OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); 542 if (NumWarnings || NumErrors) 543 OS << " generated.\n"; 544 } 545 546 if (getFrontendOpts().ShowStats && hasFileManager()) { 547 getFileManager().PrintStats(); 548 OS << "\n"; 549 } 550 551 // Return the appropriate status when verifying diagnostics. 552 // 553 // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need 554 // this. 555 if (getDiagnosticOpts().VerifyDiagnostics) 556 return !static_cast<VerifyDiagnosticsClient&>( 557 getDiagnosticClient()).HadErrors(); 558 559 return !getDiagnostics().getNumErrors(); 560} 561 562 563