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