Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
      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 "Internals.h"
     11 #include "clang/AST/ASTConsumer.h"
     12 #include "clang/Basic/DiagnosticCategories.h"
     13 #include "clang/Frontend/ASTUnit.h"
     14 #include "clang/Frontend/CompilerInstance.h"
     15 #include "clang/Frontend/FrontendAction.h"
     16 #include "clang/Frontend/TextDiagnosticPrinter.h"
     17 #include "clang/Frontend/Utils.h"
     18 #include "clang/Lex/Preprocessor.h"
     19 #include "clang/Rewrite/Core/Rewriter.h"
     20 #include "clang/Sema/SemaDiagnostic.h"
     21 #include "clang/Serialization/ASTReader.h"
     22 #include "llvm/ADT/Triple.h"
     23 #include "llvm/Support/MemoryBuffer.h"
     24 #include <utility>
     25 using namespace clang;
     26 using namespace arcmt;
     27 
     28 bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
     29                                        SourceRange range) {
     30   if (range.isInvalid())
     31     return false;
     32 
     33   bool cleared = false;
     34   ListTy::iterator I = List.begin();
     35   while (I != List.end()) {
     36     FullSourceLoc diagLoc = I->getLocation();
     37     if ((IDs.empty() || // empty means clear all diagnostics in the range.
     38          std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
     39         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
     40         (diagLoc == range.getEnd() ||
     41            diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
     42       cleared = true;
     43       ListTy::iterator eraseS = I++;
     44       if (eraseS->getLevel() != DiagnosticsEngine::Note)
     45         while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
     46           ++I;
     47       // Clear the diagnostic and any notes following it.
     48       I = List.erase(eraseS, I);
     49       continue;
     50     }
     51 
     52     ++I;
     53   }
     54 
     55   return cleared;
     56 }
     57 
     58 bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
     59                                      SourceRange range) const {
     60   if (range.isInvalid())
     61     return false;
     62 
     63   ListTy::const_iterator I = List.begin();
     64   while (I != List.end()) {
     65     FullSourceLoc diagLoc = I->getLocation();
     66     if ((IDs.empty() || // empty means any diagnostic in the range.
     67          std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
     68         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
     69         (diagLoc == range.getEnd() ||
     70            diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
     71       return true;
     72     }
     73 
     74     ++I;
     75   }
     76 
     77   return false;
     78 }
     79 
     80 void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
     81   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
     82     Diags.Report(*I);
     83 }
     84 
     85 bool CapturedDiagList::hasErrors() const {
     86   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
     87     if (I->getLevel() >= DiagnosticsEngine::Error)
     88       return true;
     89 
     90   return false;
     91 }
     92 
     93 namespace {
     94 
     95 class CaptureDiagnosticConsumer : public DiagnosticConsumer {
     96   DiagnosticsEngine &Diags;
     97   DiagnosticConsumer &DiagClient;
     98   CapturedDiagList &CapturedDiags;
     99   bool HasBegunSourceFile;
    100 public:
    101   CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
    102                             DiagnosticConsumer &client,
    103                             CapturedDiagList &capturedDiags)
    104     : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
    105       HasBegunSourceFile(false) { }
    106 
    107   void BeginSourceFile(const LangOptions &Opts,
    108                        const Preprocessor *PP) override {
    109     // Pass BeginSourceFile message onto DiagClient on first call.
    110     // The corresponding EndSourceFile call will be made from an
    111     // explicit call to FinishCapture.
    112     if (!HasBegunSourceFile) {
    113       DiagClient.BeginSourceFile(Opts, PP);
    114       HasBegunSourceFile = true;
    115     }
    116   }
    117 
    118   void FinishCapture() {
    119     // Call EndSourceFile on DiagClient on completion of capture to
    120     // enable VerifyDiagnosticConsumer to check diagnostics *after*
    121     // it has received the diagnostic list.
    122     if (HasBegunSourceFile) {
    123       DiagClient.EndSourceFile();
    124       HasBegunSourceFile = false;
    125     }
    126   }
    127 
    128   ~CaptureDiagnosticConsumer() override {
    129     assert(!HasBegunSourceFile && "FinishCapture not called!");
    130   }
    131 
    132   void HandleDiagnostic(DiagnosticsEngine::Level level,
    133                         const Diagnostic &Info) override {
    134     if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
    135         level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
    136       if (Info.getLocation().isValid())
    137         CapturedDiags.push_back(StoredDiagnostic(level, Info));
    138       return;
    139     }
    140 
    141     // Non-ARC warnings are ignored.
    142     Diags.setLastDiagnosticIgnored();
    143   }
    144 };
    145 
    146 } // end anonymous namespace
    147 
    148 static bool HasARCRuntime(CompilerInvocation &origCI) {
    149   // This duplicates some functionality from Darwin::AddDeploymentTarget
    150   // but this function is well defined, so keep it decoupled from the driver
    151   // and avoid unrelated complications.
    152   llvm::Triple triple(origCI.getTargetOpts().Triple);
    153 
    154   if (triple.isiOS())
    155     return triple.getOSMajorVersion() >= 5;
    156 
    157   if (triple.isWatchOS())
    158     return true;
    159 
    160   if (triple.getOS() == llvm::Triple::Darwin)
    161     return triple.getOSMajorVersion() >= 11;
    162 
    163   if (triple.getOS() == llvm::Triple::MacOSX) {
    164     unsigned Major, Minor, Micro;
    165     triple.getOSVersion(Major, Minor, Micro);
    166     return Major > 10 || (Major == 10 && Minor >= 7);
    167   }
    168 
    169   return false;
    170 }
    171 
    172 static CompilerInvocation *
    173 createInvocationForMigration(CompilerInvocation &origCI,
    174                              const PCHContainerReader &PCHContainerRdr) {
    175   std::unique_ptr<CompilerInvocation> CInvok;
    176   CInvok.reset(new CompilerInvocation(origCI));
    177   PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
    178   if (!PPOpts.ImplicitPCHInclude.empty()) {
    179     // We can't use a PCH because it was likely built in non-ARC mode and we
    180     // want to parse in ARC. Include the original header.
    181     FileManager FileMgr(origCI.getFileSystemOpts());
    182     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    183     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    184         new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
    185                               new IgnoringDiagConsumer()));
    186     std::string OriginalFile = ASTReader::getOriginalSourceFile(
    187         PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
    188     if (!OriginalFile.empty())
    189       PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
    190     PPOpts.ImplicitPCHInclude.clear();
    191   }
    192   // FIXME: Get the original header of a PTH as well.
    193   CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
    194   std::string define = getARCMTMacroName();
    195   define += '=';
    196   CInvok->getPreprocessorOpts().addMacroDef(define);
    197   CInvok->getLangOpts()->ObjCAutoRefCount = true;
    198   CInvok->getLangOpts()->setGC(LangOptions::NonGC);
    199   CInvok->getDiagnosticOpts().ErrorLimit = 0;
    200   CInvok->getDiagnosticOpts().PedanticErrors = 0;
    201 
    202   // Ignore -Werror flags when migrating.
    203   std::vector<std::string> WarnOpts;
    204   for (std::vector<std::string>::iterator
    205          I = CInvok->getDiagnosticOpts().Warnings.begin(),
    206          E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
    207     if (!StringRef(*I).startswith("error"))
    208       WarnOpts.push_back(*I);
    209   }
    210   WarnOpts.push_back("error=arc-unsafe-retained-assign");
    211   CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
    212 
    213   CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI);
    214   CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime;
    215 
    216   return CInvok.release();
    217 }
    218 
    219 static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
    220                                    DiagnosticOptions *diagOpts,
    221                                    Preprocessor &PP) {
    222   TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
    223   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    224   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    225       new DiagnosticsEngine(DiagID, diagOpts, &printer,
    226                             /*ShouldOwnClient=*/false));
    227   Diags->setSourceManager(&PP.getSourceManager());
    228 
    229   printer.BeginSourceFile(PP.getLangOpts(), &PP);
    230   arcDiags.reportDiagnostics(*Diags);
    231   printer.EndSourceFile();
    232 }
    233 
    234 //===----------------------------------------------------------------------===//
    235 // checkForManualIssues.
    236 //===----------------------------------------------------------------------===//
    237 
    238 bool arcmt::checkForManualIssues(
    239     CompilerInvocation &origCI, const FrontendInputFile &Input,
    240     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
    241     DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
    242     StringRef plistOut) {
    243   if (!origCI.getLangOpts()->ObjC1)
    244     return false;
    245 
    246   LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
    247   bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
    248   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
    249 
    250   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
    251                                                                      NoFinalizeRemoval);
    252   assert(!transforms.empty());
    253 
    254   std::unique_ptr<CompilerInvocation> CInvok;
    255   CInvok.reset(
    256       createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
    257   CInvok->getFrontendOpts().Inputs.clear();
    258   CInvok->getFrontendOpts().Inputs.push_back(Input);
    259 
    260   CapturedDiagList capturedDiags;
    261 
    262   assert(DiagClient);
    263   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    264   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    265       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
    266                             DiagClient, /*ShouldOwnClient=*/false));
    267 
    268   // Filter of all diagnostics.
    269   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
    270   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
    271 
    272   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
    273       CInvok.release(), PCHContainerOps, Diags));
    274   if (!Unit) {
    275     errRec.FinishCapture();
    276     return true;
    277   }
    278 
    279   // Don't filter diagnostics anymore.
    280   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
    281 
    282   ASTContext &Ctx = Unit->getASTContext();
    283 
    284   if (Diags->hasFatalErrorOccurred()) {
    285     Diags->Reset();
    286     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
    287     capturedDiags.reportDiagnostics(*Diags);
    288     DiagClient->EndSourceFile();
    289     errRec.FinishCapture();
    290     return true;
    291   }
    292 
    293   if (emitPremigrationARCErrors)
    294     emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
    295                            Unit->getPreprocessor());
    296   if (!plistOut.empty()) {
    297     SmallVector<StoredDiagnostic, 8> arcDiags;
    298     for (CapturedDiagList::iterator
    299            I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
    300       arcDiags.push_back(*I);
    301     writeARCDiagsToPlist(plistOut, arcDiags,
    302                          Ctx.getSourceManager(), Ctx.getLangOpts());
    303   }
    304 
    305   // After parsing of source files ended, we want to reuse the
    306   // diagnostics objects to emit further diagnostics.
    307   // We call BeginSourceFile because DiagnosticConsumer requires that
    308   // diagnostics with source range information are emitted only in between
    309   // BeginSourceFile() and EndSourceFile().
    310   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
    311 
    312   // No macros will be added since we are just checking and we won't modify
    313   // source code.
    314   std::vector<SourceLocation> ARCMTMacroLocs;
    315 
    316   TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
    317   MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
    318                      ARCMTMacroLocs);
    319   pass.setNoFinalizeRemoval(NoFinalizeRemoval);
    320   if (!NoNSAllocReallocError)
    321     Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
    322                        SourceLocation());
    323 
    324   for (unsigned i=0, e = transforms.size(); i != e; ++i)
    325     transforms[i](pass);
    326 
    327   capturedDiags.reportDiagnostics(*Diags);
    328 
    329   DiagClient->EndSourceFile();
    330   errRec.FinishCapture();
    331 
    332   return capturedDiags.hasErrors() || testAct.hasReportedErrors();
    333 }
    334 
    335 //===----------------------------------------------------------------------===//
    336 // applyTransformations.
    337 //===----------------------------------------------------------------------===//
    338 
    339 static bool
    340 applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
    341                 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
    342                 DiagnosticConsumer *DiagClient, StringRef outputDir,
    343                 bool emitPremigrationARCErrors, StringRef plistOut) {
    344   if (!origCI.getLangOpts()->ObjC1)
    345     return false;
    346 
    347   LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
    348 
    349   // Make sure checking is successful first.
    350   CompilerInvocation CInvokForCheck(origCI);
    351   if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
    352                                   DiagClient, emitPremigrationARCErrors,
    353                                   plistOut))
    354     return true;
    355 
    356   CompilerInvocation CInvok(origCI);
    357   CInvok.getFrontendOpts().Inputs.clear();
    358   CInvok.getFrontendOpts().Inputs.push_back(Input);
    359 
    360   MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
    361   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
    362 
    363   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
    364                                                                      NoFinalizeRemoval);
    365   assert(!transforms.empty());
    366 
    367   for (unsigned i=0, e = transforms.size(); i != e; ++i) {
    368     bool err = migration.applyTransform(transforms[i]);
    369     if (err) return true;
    370   }
    371 
    372   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    373   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    374       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
    375                             DiagClient, /*ShouldOwnClient=*/false));
    376 
    377   if (outputDir.empty()) {
    378     origCI.getLangOpts()->ObjCAutoRefCount = true;
    379     return migration.getRemapper().overwriteOriginal(*Diags);
    380   } else {
    381     return migration.getRemapper().flushToDisk(outputDir, *Diags);
    382   }
    383 }
    384 
    385 bool arcmt::applyTransformations(
    386     CompilerInvocation &origCI, const FrontendInputFile &Input,
    387     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
    388     DiagnosticConsumer *DiagClient) {
    389   return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
    390                          StringRef(), false, StringRef());
    391 }
    392 
    393 bool arcmt::migrateWithTemporaryFiles(
    394     CompilerInvocation &origCI, const FrontendInputFile &Input,
    395     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
    396     DiagnosticConsumer *DiagClient, StringRef outputDir,
    397     bool emitPremigrationARCErrors, StringRef plistOut) {
    398   assert(!outputDir.empty() && "Expected output directory path");
    399   return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
    400                          emitPremigrationARCErrors, plistOut);
    401 }
    402 
    403 bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
    404                                   remap,
    405                               StringRef outputDir,
    406                               DiagnosticConsumer *DiagClient) {
    407   assert(!outputDir.empty());
    408 
    409   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    410   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    411       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
    412                             DiagClient, /*ShouldOwnClient=*/false));
    413 
    414   FileRemapper remapper;
    415   bool err = remapper.initFromDisk(outputDir, *Diags,
    416                                    /*ignoreIfFilesChanged=*/true);
    417   if (err)
    418     return true;
    419 
    420   PreprocessorOptions PPOpts;
    421   remapper.applyMappings(PPOpts);
    422   remap = PPOpts.RemappedFiles;
    423 
    424   return false;
    425 }
    426 
    427 
    428 //===----------------------------------------------------------------------===//
    429 // CollectTransformActions.
    430 //===----------------------------------------------------------------------===//
    431 
    432 namespace {
    433 
    434 class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
    435   std::vector<SourceLocation> &ARCMTMacroLocs;
    436 
    437 public:
    438   ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
    439     : ARCMTMacroLocs(ARCMTMacroLocs) { }
    440 
    441   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
    442                     SourceRange Range, const MacroArgs *Args) override {
    443     if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
    444       ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
    445   }
    446 };
    447 
    448 class ARCMTMacroTrackerAction : public ASTFrontendAction {
    449   std::vector<SourceLocation> &ARCMTMacroLocs;
    450 
    451 public:
    452   ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
    453     : ARCMTMacroLocs(ARCMTMacroLocs) { }
    454 
    455   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
    456                                                  StringRef InFile) override {
    457     CI.getPreprocessor().addPPCallbacks(
    458                llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
    459     return llvm::make_unique<ASTConsumer>();
    460   }
    461 };
    462 
    463 class RewritesApplicator : public TransformActions::RewriteReceiver {
    464   Rewriter &rewriter;
    465   MigrationProcess::RewriteListener *Listener;
    466 
    467 public:
    468   RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
    469                      MigrationProcess::RewriteListener *listener)
    470     : rewriter(rewriter), Listener(listener) {
    471     if (Listener)
    472       Listener->start(ctx);
    473   }
    474   ~RewritesApplicator() override {
    475     if (Listener)
    476       Listener->finish();
    477   }
    478 
    479   void insert(SourceLocation loc, StringRef text) override {
    480     bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
    481                                    /*indentNewLines=*/true);
    482     if (!err && Listener)
    483       Listener->insert(loc, text);
    484   }
    485 
    486   void remove(CharSourceRange range) override {
    487     Rewriter::RewriteOptions removeOpts;
    488     removeOpts.IncludeInsertsAtBeginOfRange = false;
    489     removeOpts.IncludeInsertsAtEndOfRange = false;
    490     removeOpts.RemoveLineIfEmpty = true;
    491 
    492     bool err = rewriter.RemoveText(range, removeOpts);
    493     if (!err && Listener)
    494       Listener->remove(range);
    495   }
    496 
    497   void increaseIndentation(CharSourceRange range,
    498                             SourceLocation parentIndent) override {
    499     rewriter.IncreaseIndentation(range, parentIndent);
    500   }
    501 };
    502 
    503 } // end anonymous namespace.
    504 
    505 /// \brief Anchor for VTable.
    506 MigrationProcess::RewriteListener::~RewriteListener() { }
    507 
    508 MigrationProcess::MigrationProcess(
    509     const CompilerInvocation &CI,
    510     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
    511     DiagnosticConsumer *diagClient, StringRef outputDir)
    512     : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
    513       DiagClient(diagClient), HadARCErrors(false) {
    514   if (!outputDir.empty()) {
    515     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    516     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    517       new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
    518                             DiagClient, /*ShouldOwnClient=*/false));
    519     Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
    520   }
    521 }
    522 
    523 bool MigrationProcess::applyTransform(TransformFn trans,
    524                                       RewriteListener *listener) {
    525   std::unique_ptr<CompilerInvocation> CInvok;
    526   CInvok.reset(
    527       createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
    528   CInvok->getDiagnosticOpts().IgnoreWarnings = true;
    529 
    530   Remapper.applyMappings(CInvok->getPreprocessorOpts());
    531 
    532   CapturedDiagList capturedDiags;
    533   std::vector<SourceLocation> ARCMTMacroLocs;
    534 
    535   assert(DiagClient);
    536   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
    537   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
    538       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
    539                             DiagClient, /*ShouldOwnClient=*/false));
    540 
    541   // Filter of all diagnostics.
    542   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
    543   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
    544 
    545   std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
    546   ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
    547 
    548   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
    549       CInvok.release(), PCHContainerOps, Diags, ASTAction.get()));
    550   if (!Unit) {
    551     errRec.FinishCapture();
    552     return true;
    553   }
    554   Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
    555 
    556   HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
    557 
    558   // Don't filter diagnostics anymore.
    559   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
    560 
    561   ASTContext &Ctx = Unit->getASTContext();
    562 
    563   if (Diags->hasFatalErrorOccurred()) {
    564     Diags->Reset();
    565     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
    566     capturedDiags.reportDiagnostics(*Diags);
    567     DiagClient->EndSourceFile();
    568     errRec.FinishCapture();
    569     return true;
    570   }
    571 
    572   // After parsing of source files ended, we want to reuse the
    573   // diagnostics objects to emit further diagnostics.
    574   // We call BeginSourceFile because DiagnosticConsumer requires that
    575   // diagnostics with source range information are emitted only in between
    576   // BeginSourceFile() and EndSourceFile().
    577   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
    578 
    579   Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
    580   TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
    581   MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
    582                      Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
    583 
    584   trans(pass);
    585 
    586   {
    587     RewritesApplicator applicator(rewriter, Ctx, listener);
    588     TA.applyRewrites(applicator);
    589   }
    590 
    591   DiagClient->EndSourceFile();
    592   errRec.FinishCapture();
    593 
    594   if (DiagClient->getNumErrors())
    595     return true;
    596 
    597   for (Rewriter::buffer_iterator
    598         I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
    599     FileID FID = I->first;
    600     RewriteBuffer &buf = I->second;
    601     const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
    602     assert(file);
    603     std::string newFname = file->getName();
    604     newFname += "-trans";
    605     SmallString<512> newText;
    606     llvm::raw_svector_ostream vecOS(newText);
    607     buf.write(vecOS);
    608     std::unique_ptr<llvm::MemoryBuffer> memBuf(
    609         llvm::MemoryBuffer::getMemBufferCopy(
    610             StringRef(newText.data(), newText.size()), newFname));
    611     SmallString<64> filePath(file->getName());
    612     Unit->getFileManager().FixupRelativePath(filePath);
    613     Remapper.remap(filePath.str(), std::move(memBuf));
    614   }
    615 
    616   return false;
    617 }
    618