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