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