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