clang API Documentation

ARCMT.cpp
Go to the documentation of this file.
00001 //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "Internals.h"
00011 #include "clang/AST/ASTConsumer.h"
00012 #include "clang/Basic/DiagnosticCategories.h"
00013 #include "clang/Frontend/ASTUnit.h"
00014 #include "clang/Frontend/CompilerInstance.h"
00015 #include "clang/Frontend/FrontendAction.h"
00016 #include "clang/Frontend/TextDiagnosticPrinter.h"
00017 #include "clang/Frontend/Utils.h"
00018 #include "clang/Lex/Preprocessor.h"
00019 #include "clang/Rewrite/Core/Rewriter.h"
00020 #include "clang/Sema/SemaDiagnostic.h"
00021 #include "clang/Serialization/ASTReader.h"
00022 #include "llvm/ADT/Triple.h"
00023 #include "llvm/Support/MemoryBuffer.h"
00024 using namespace clang;
00025 using namespace arcmt;
00026 
00027 bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
00028                                        SourceRange range) {
00029   if (range.isInvalid())
00030     return false;
00031 
00032   bool cleared = false;
00033   ListTy::iterator I = List.begin();
00034   while (I != List.end()) {
00035     FullSourceLoc diagLoc = I->getLocation();
00036     if ((IDs.empty() || // empty means clear all diagnostics in the range.
00037          std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
00038         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
00039         (diagLoc == range.getEnd() ||
00040            diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
00041       cleared = true;
00042       ListTy::iterator eraseS = I++;
00043       if (eraseS->getLevel() != DiagnosticsEngine::Note)
00044         while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
00045           ++I;
00046       // Clear the diagnostic and any notes following it.
00047       I = List.erase(eraseS, I);
00048       continue;
00049     }
00050 
00051     ++I;
00052   }
00053 
00054   return cleared;
00055 }
00056 
00057 bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
00058                                      SourceRange range) const {
00059   if (range.isInvalid())
00060     return false;
00061 
00062   ListTy::const_iterator I = List.begin();
00063   while (I != List.end()) {
00064     FullSourceLoc diagLoc = I->getLocation();
00065     if ((IDs.empty() || // empty means any diagnostic in the range.
00066          std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
00067         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
00068         (diagLoc == range.getEnd() ||
00069            diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
00070       return true;
00071     }
00072 
00073     ++I;
00074   }
00075 
00076   return false;
00077 }
00078 
00079 void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
00080   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
00081     Diags.Report(*I);
00082 }
00083 
00084 bool CapturedDiagList::hasErrors() const {
00085   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
00086     if (I->getLevel() >= DiagnosticsEngine::Error)
00087       return true;
00088 
00089   return false;
00090 }
00091 
00092 namespace {
00093 
00094 class CaptureDiagnosticConsumer : public DiagnosticConsumer {
00095   DiagnosticsEngine &Diags;
00096   DiagnosticConsumer &DiagClient;
00097   CapturedDiagList &CapturedDiags;
00098   bool HasBegunSourceFile;
00099 public:
00100   CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
00101                             DiagnosticConsumer &client,
00102                             CapturedDiagList &capturedDiags)
00103     : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
00104       HasBegunSourceFile(false) { }
00105 
00106   void BeginSourceFile(const LangOptions &Opts,
00107                        const Preprocessor *PP) override {
00108     // Pass BeginSourceFile message onto DiagClient on first call.
00109     // The corresponding EndSourceFile call will be made from an
00110     // explicit call to FinishCapture.
00111     if (!HasBegunSourceFile) {
00112       DiagClient.BeginSourceFile(Opts, PP);
00113       HasBegunSourceFile = true;
00114     }
00115   }
00116 
00117   void FinishCapture() {
00118     // Call EndSourceFile on DiagClient on completion of capture to
00119     // enable VerifyDiagnosticConsumer to check diagnostics *after*
00120     // it has received the diagnostic list.
00121     if (HasBegunSourceFile) {
00122       DiagClient.EndSourceFile();
00123       HasBegunSourceFile = false;
00124     }
00125   }
00126 
00127   virtual ~CaptureDiagnosticConsumer() {
00128     assert(!HasBegunSourceFile && "FinishCapture not called!");
00129   }
00130 
00131   void HandleDiagnostic(DiagnosticsEngine::Level level,
00132                         const Diagnostic &Info) override {
00133     if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
00134         level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
00135       if (Info.getLocation().isValid())
00136         CapturedDiags.push_back(StoredDiagnostic(level, Info));
00137       return;
00138     }
00139 
00140     // Non-ARC warnings are ignored.
00141     Diags.setLastDiagnosticIgnored();
00142   }
00143 };
00144 
00145 } // end anonymous namespace
00146 
00147 static bool HasARCRuntime(CompilerInvocation &origCI) {
00148   // This duplicates some functionality from Darwin::AddDeploymentTarget
00149   // but this function is well defined, so keep it decoupled from the driver
00150   // and avoid unrelated complications.
00151   llvm::Triple triple(origCI.getTargetOpts().Triple);
00152 
00153   if (triple.isiOS())
00154     return triple.getOSMajorVersion() >= 5;
00155 
00156   if (triple.getOS() == llvm::Triple::Darwin)
00157     return triple.getOSMajorVersion() >= 11;
00158 
00159   if (triple.getOS() == llvm::Triple::MacOSX) {
00160     unsigned Major, Minor, Micro;
00161     triple.getOSVersion(Major, Minor, Micro);
00162     return Major > 10 || (Major == 10 && Minor >= 7);
00163   }
00164 
00165   return false;
00166 }
00167 
00168 static CompilerInvocation *
00169 createInvocationForMigration(CompilerInvocation &origCI) {
00170   std::unique_ptr<CompilerInvocation> CInvok;
00171   CInvok.reset(new CompilerInvocation(origCI));
00172   PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
00173   if (!PPOpts.ImplicitPCHInclude.empty()) {
00174     // We can't use a PCH because it was likely built in non-ARC mode and we
00175     // want to parse in ARC. Include the original header.
00176     FileManager FileMgr(origCI.getFileSystemOpts());
00177     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00178     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00179         new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
00180                               new IgnoringDiagConsumer()));
00181     std::string OriginalFile =
00182         ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude,
00183                                          FileMgr, *Diags);
00184     if (!OriginalFile.empty())
00185       PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
00186     PPOpts.ImplicitPCHInclude.clear();
00187   }
00188   // FIXME: Get the original header of a PTH as well.
00189   CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
00190   std::string define = getARCMTMacroName();
00191   define += '=';
00192   CInvok->getPreprocessorOpts().addMacroDef(define);
00193   CInvok->getLangOpts()->ObjCAutoRefCount = true;
00194   CInvok->getLangOpts()->setGC(LangOptions::NonGC);
00195   CInvok->getDiagnosticOpts().ErrorLimit = 0;
00196   CInvok->getDiagnosticOpts().PedanticErrors = 0;
00197 
00198   // Ignore -Werror flags when migrating.
00199   std::vector<std::string> WarnOpts;
00200   for (std::vector<std::string>::iterator
00201          I = CInvok->getDiagnosticOpts().Warnings.begin(),
00202          E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
00203     if (!StringRef(*I).startswith("error"))
00204       WarnOpts.push_back(*I);
00205   }
00206   WarnOpts.push_back("error=arc-unsafe-retained-assign");
00207   CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
00208 
00209   CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI);
00210 
00211   return CInvok.release();
00212 }
00213 
00214 static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
00215                                    DiagnosticOptions *diagOpts,
00216                                    Preprocessor &PP) {
00217   TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
00218   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00219   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00220       new DiagnosticsEngine(DiagID, diagOpts, &printer,
00221                             /*ShouldOwnClient=*/false));
00222   Diags->setSourceManager(&PP.getSourceManager());
00223   
00224   printer.BeginSourceFile(PP.getLangOpts(), &PP);
00225   arcDiags.reportDiagnostics(*Diags);
00226   printer.EndSourceFile();
00227 }
00228 
00229 //===----------------------------------------------------------------------===//
00230 // checkForManualIssues.
00231 //===----------------------------------------------------------------------===//
00232 
00233 bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
00234                                  const FrontendInputFile &Input,
00235                                  DiagnosticConsumer *DiagClient,
00236                                  bool emitPremigrationARCErrors,
00237                                  StringRef plistOut) {
00238   if (!origCI.getLangOpts()->ObjC1)
00239     return false;
00240 
00241   LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
00242   bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
00243   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
00244 
00245   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
00246                                                                      NoFinalizeRemoval);
00247   assert(!transforms.empty());
00248 
00249   std::unique_ptr<CompilerInvocation> CInvok;
00250   CInvok.reset(createInvocationForMigration(origCI));
00251   CInvok->getFrontendOpts().Inputs.clear();
00252   CInvok->getFrontendOpts().Inputs.push_back(Input);
00253 
00254   CapturedDiagList capturedDiags;
00255 
00256   assert(DiagClient);
00257   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00258   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00259       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
00260                             DiagClient, /*ShouldOwnClient=*/false));
00261 
00262   // Filter of all diagnostics.
00263   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
00264   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
00265 
00266   std::unique_ptr<ASTUnit> Unit(
00267       ASTUnit::LoadFromCompilerInvocationAction(CInvok.release(), Diags));
00268   if (!Unit) {
00269     errRec.FinishCapture();
00270     return true;
00271   }
00272 
00273   // Don't filter diagnostics anymore.
00274   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
00275 
00276   ASTContext &Ctx = Unit->getASTContext();
00277 
00278   if (Diags->hasFatalErrorOccurred()) {
00279     Diags->Reset();
00280     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
00281     capturedDiags.reportDiagnostics(*Diags);
00282     DiagClient->EndSourceFile();
00283     errRec.FinishCapture();
00284     return true;
00285   }
00286 
00287   if (emitPremigrationARCErrors)
00288     emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
00289                            Unit->getPreprocessor());
00290   if (!plistOut.empty()) {
00291     SmallVector<StoredDiagnostic, 8> arcDiags;
00292     for (CapturedDiagList::iterator
00293            I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
00294       arcDiags.push_back(*I);
00295     writeARCDiagsToPlist(plistOut, arcDiags,
00296                          Ctx.getSourceManager(), Ctx.getLangOpts());
00297   }
00298 
00299   // After parsing of source files ended, we want to reuse the
00300   // diagnostics objects to emit further diagnostics.
00301   // We call BeginSourceFile because DiagnosticConsumer requires that 
00302   // diagnostics with source range information are emitted only in between
00303   // BeginSourceFile() and EndSourceFile().
00304   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
00305 
00306   // No macros will be added since we are just checking and we won't modify
00307   // source code.
00308   std::vector<SourceLocation> ARCMTMacroLocs;
00309 
00310   TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
00311   MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
00312                      ARCMTMacroLocs);
00313   pass.setNoFinalizeRemoval(NoFinalizeRemoval);
00314   if (!NoNSAllocReallocError)
00315     Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
00316                        SourceLocation());
00317 
00318   for (unsigned i=0, e = transforms.size(); i != e; ++i)
00319     transforms[i](pass);
00320 
00321   capturedDiags.reportDiagnostics(*Diags);
00322 
00323   DiagClient->EndSourceFile();
00324   errRec.FinishCapture();
00325 
00326   return capturedDiags.hasErrors() || testAct.hasReportedErrors();
00327 }
00328 
00329 //===----------------------------------------------------------------------===//
00330 // applyTransformations.
00331 //===----------------------------------------------------------------------===//
00332 
00333 static bool applyTransforms(CompilerInvocation &origCI,
00334                             const FrontendInputFile &Input,
00335                             DiagnosticConsumer *DiagClient,
00336                             StringRef outputDir,
00337                             bool emitPremigrationARCErrors,
00338                             StringRef plistOut) {
00339   if (!origCI.getLangOpts()->ObjC1)
00340     return false;
00341 
00342   LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
00343 
00344   // Make sure checking is successful first.
00345   CompilerInvocation CInvokForCheck(origCI);
00346   if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient,
00347                                   emitPremigrationARCErrors, plistOut))
00348     return true;
00349 
00350   CompilerInvocation CInvok(origCI);
00351   CInvok.getFrontendOpts().Inputs.clear();
00352   CInvok.getFrontendOpts().Inputs.push_back(Input);
00353   
00354   MigrationProcess migration(CInvok, DiagClient, outputDir);
00355   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
00356 
00357   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
00358                                                                      NoFinalizeRemoval);
00359   assert(!transforms.empty());
00360 
00361   for (unsigned i=0, e = transforms.size(); i != e; ++i) {
00362     bool err = migration.applyTransform(transforms[i]);
00363     if (err) return true;
00364   }
00365 
00366   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00367   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00368       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
00369                             DiagClient, /*ShouldOwnClient=*/false));
00370 
00371   if (outputDir.empty()) {
00372     origCI.getLangOpts()->ObjCAutoRefCount = true;
00373     return migration.getRemapper().overwriteOriginal(*Diags);
00374   } else {
00375     return migration.getRemapper().flushToDisk(outputDir, *Diags);
00376   }
00377 }
00378 
00379 bool arcmt::applyTransformations(CompilerInvocation &origCI,
00380                                  const FrontendInputFile &Input,
00381                                  DiagnosticConsumer *DiagClient) {
00382   return applyTransforms(origCI, Input, DiagClient,
00383                          StringRef(), false, StringRef());
00384 }
00385 
00386 bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
00387                                       const FrontendInputFile &Input,
00388                                       DiagnosticConsumer *DiagClient,
00389                                       StringRef outputDir,
00390                                       bool emitPremigrationARCErrors,
00391                                       StringRef plistOut) {
00392   assert(!outputDir.empty() && "Expected output directory path");
00393   return applyTransforms(origCI, Input, DiagClient,
00394                          outputDir, emitPremigrationARCErrors, plistOut);
00395 }
00396 
00397 bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
00398                                   remap,
00399                               StringRef outputDir,
00400                               DiagnosticConsumer *DiagClient) {
00401   assert(!outputDir.empty());
00402 
00403   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00404   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00405       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
00406                             DiagClient, /*ShouldOwnClient=*/false));
00407 
00408   FileRemapper remapper;
00409   bool err = remapper.initFromDisk(outputDir, *Diags,
00410                                    /*ignoreIfFilesChanged=*/true);
00411   if (err)
00412     return true;
00413 
00414   PreprocessorOptions PPOpts;
00415   remapper.applyMappings(PPOpts);
00416   remap = PPOpts.RemappedFiles;
00417 
00418   return false;
00419 }
00420 
00421 
00422 //===----------------------------------------------------------------------===//
00423 // CollectTransformActions.
00424 //===----------------------------------------------------------------------===//
00425 
00426 namespace {
00427 
00428 class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
00429   std::vector<SourceLocation> &ARCMTMacroLocs;
00430 
00431 public:
00432   ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
00433     : ARCMTMacroLocs(ARCMTMacroLocs) { }
00434 
00435   void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
00436                     SourceRange Range, const MacroArgs *Args) override {
00437     if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
00438       ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
00439   }
00440 };
00441 
00442 class ARCMTMacroTrackerAction : public ASTFrontendAction {
00443   std::vector<SourceLocation> &ARCMTMacroLocs;
00444 
00445 public:
00446   ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
00447     : ARCMTMacroLocs(ARCMTMacroLocs) { }
00448 
00449   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
00450                                                  StringRef InFile) override {
00451     CI.getPreprocessor().addPPCallbacks(
00452                llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
00453     return llvm::make_unique<ASTConsumer>();
00454   }
00455 };
00456 
00457 class RewritesApplicator : public TransformActions::RewriteReceiver {
00458   Rewriter &rewriter;
00459   MigrationProcess::RewriteListener *Listener;
00460 
00461 public:
00462   RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
00463                      MigrationProcess::RewriteListener *listener)
00464     : rewriter(rewriter), Listener(listener) {
00465     if (Listener)
00466       Listener->start(ctx);
00467   }
00468   ~RewritesApplicator() {
00469     if (Listener)
00470       Listener->finish();
00471   }
00472 
00473   void insert(SourceLocation loc, StringRef text) override {
00474     bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
00475                                    /*indentNewLines=*/true);
00476     if (!err && Listener)
00477       Listener->insert(loc, text);
00478   }
00479 
00480   void remove(CharSourceRange range) override {
00481     Rewriter::RewriteOptions removeOpts;
00482     removeOpts.IncludeInsertsAtBeginOfRange = false;
00483     removeOpts.IncludeInsertsAtEndOfRange = false;
00484     removeOpts.RemoveLineIfEmpty = true;
00485 
00486     bool err = rewriter.RemoveText(range, removeOpts);
00487     if (!err && Listener)
00488       Listener->remove(range);
00489   }
00490 
00491   void increaseIndentation(CharSourceRange range,
00492                             SourceLocation parentIndent) override {
00493     rewriter.IncreaseIndentation(range, parentIndent);
00494   }
00495 };
00496 
00497 } // end anonymous namespace.
00498 
00499 /// \brief Anchor for VTable.
00500 MigrationProcess::RewriteListener::~RewriteListener() { }
00501 
00502 MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
00503                                    DiagnosticConsumer *diagClient,
00504                                    StringRef outputDir)
00505   : OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) {
00506   if (!outputDir.empty()) {
00507     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00508     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00509       new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
00510                             DiagClient, /*ShouldOwnClient=*/false));
00511     Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
00512   }
00513 }
00514 
00515 bool MigrationProcess::applyTransform(TransformFn trans,
00516                                       RewriteListener *listener) {
00517   std::unique_ptr<CompilerInvocation> CInvok;
00518   CInvok.reset(createInvocationForMigration(OrigCI));
00519   CInvok->getDiagnosticOpts().IgnoreWarnings = true;
00520 
00521   Remapper.applyMappings(CInvok->getPreprocessorOpts());
00522 
00523   CapturedDiagList capturedDiags;
00524   std::vector<SourceLocation> ARCMTMacroLocs;
00525 
00526   assert(DiagClient);
00527   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
00528   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
00529       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
00530                             DiagClient, /*ShouldOwnClient=*/false));
00531 
00532   // Filter of all diagnostics.
00533   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
00534   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
00535 
00536   std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
00537   ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
00538 
00539   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
00540       CInvok.release(), Diags, ASTAction.get()));
00541   if (!Unit) {
00542     errRec.FinishCapture();
00543     return true;
00544   }
00545   Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
00546 
00547   HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
00548 
00549   // Don't filter diagnostics anymore.
00550   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
00551 
00552   ASTContext &Ctx = Unit->getASTContext();
00553 
00554   if (Diags->hasFatalErrorOccurred()) {
00555     Diags->Reset();
00556     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
00557     capturedDiags.reportDiagnostics(*Diags);
00558     DiagClient->EndSourceFile();
00559     errRec.FinishCapture();
00560     return true;
00561   }
00562 
00563   // After parsing of source files ended, we want to reuse the
00564   // diagnostics objects to emit further diagnostics.
00565   // We call BeginSourceFile because DiagnosticConsumer requires that 
00566   // diagnostics with source range information are emitted only in between
00567   // BeginSourceFile() and EndSourceFile().
00568   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
00569 
00570   Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
00571   TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
00572   MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
00573                      Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
00574 
00575   trans(pass);
00576 
00577   {
00578     RewritesApplicator applicator(rewriter, Ctx, listener);
00579     TA.applyRewrites(applicator);
00580   }
00581 
00582   DiagClient->EndSourceFile();
00583   errRec.FinishCapture();
00584 
00585   if (DiagClient->getNumErrors())
00586     return true;
00587 
00588   for (Rewriter::buffer_iterator
00589         I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
00590     FileID FID = I->first;
00591     RewriteBuffer &buf = I->second;
00592     const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
00593     assert(file);
00594     std::string newFname = file->getName();
00595     newFname += "-trans";
00596     SmallString<512> newText;
00597     llvm::raw_svector_ostream vecOS(newText);
00598     buf.write(vecOS);
00599     vecOS.flush();
00600     std::unique_ptr<llvm::MemoryBuffer> memBuf(
00601         llvm::MemoryBuffer::getMemBufferCopy(
00602             StringRef(newText.data(), newText.size()), newFname));
00603     SmallString<64> filePath(file->getName());
00604     Unit->getFileManager().FixupRelativePath(filePath);
00605     Remapper.remap(filePath.str(), std::move(memBuf));
00606   }
00607 
00608   return false;
00609 }