CompilerInstance.cpp 21 KB

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