ARCMT.cpp revision 224135
16059Samurai//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 26059Samurai// 36059Samurai// The LLVM Compiler Infrastructure 46059Samurai// 56059Samurai// This file is distributed under the University of Illinois Open Source 66059Samurai// License. See LICENSE.TXT for details. 76059Samurai// 86059Samurai//===----------------------------------------------------------------------===// 96059Samurai 106059Samurai#include "Internals.h" 116059Samurai#include "clang/Frontend/ASTUnit.h" 126059Samurai#include "clang/Frontend/CompilerInstance.h" 136059Samurai#include "clang/Frontend/Utils.h" 146059Samurai#include "clang/AST/ASTConsumer.h" 156059Samurai#include "clang/Rewrite/Rewriter.h" 166059Samurai#include "clang/Sema/SemaDiagnostic.h" 176059Samurai#include "clang/Basic/DiagnosticCategories.h" 186059Samurai#include "clang/Lex/Preprocessor.h" 198857Srgrimes#include "llvm/Support/MemoryBuffer.h" 2026326Sbrian#include "llvm/ADT/Triple.h" 218857Srgrimes 226059Samuraiusing namespace clang; 2313379Sphkusing namespace arcmt; 246059Samuraiusing llvm::StringRef; 256735Samurai 2613385Speterbool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs, 2713379Sphk SourceRange range) { 2826031Sbrian if (range.isInvalid()) 2926031Sbrian return false; 3026031Sbrian 3126031Sbrian bool cleared = false; 3226031Sbrian ListTy::iterator I = List.begin(); 3326031Sbrian while (I != List.end()) { 3426031Sbrian FullSourceLoc diagLoc = I->getLocation(); 356059Samurai if ((IDs.empty() || // empty means clear all diagnostics in the range. 366059Samurai std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 376059Samurai !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 386059Samurai (diagLoc == range.getEnd() || 396059Samurai diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 4013389Sphk cleared = true; 416059Samurai ListTy::iterator eraseS = I++; 4226031Sbrian while (I != List.end() && I->getLevel() == Diagnostic::Note) 436059Samurai ++I; 4426142Sbrian // Clear the diagnostic and any notes following it. 456059Samurai List.erase(eraseS, I); 4625630Sbrian continue; 4725630Sbrian } 486059Samurai 496059Samurai ++I; 506059Samurai } 516059Samurai 526059Samurai return cleared; 5326031Sbrian} 546735Samurai 556059Samuraibool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs, 566059Samurai SourceRange range) const { 576059Samurai if (range.isInvalid()) 586059Samurai return false; 5910528Samurai 606735Samurai ListTy::const_iterator I = List.begin(); 6114418Sache while (I != List.end()) { 626059Samurai FullSourceLoc diagLoc = I->getLocation(); 6322973Sphk if ((IDs.empty() || // empty means any diagnostic in the range. 6422973Sphk std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 656059Samurai !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 6623603Sache (diagLoc == range.getEnd() || 676059Samurai diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 686059Samurai return true; 696059Samurai } 706059Samurai 7110528Samurai ++I; 726059Samurai } 736059Samurai 746059Samurai return false; 756059Samurai} 766059Samurai 776059Samuraivoid CapturedDiagList::reportDiagnostics(Diagnostic &Diags) const { 786059Samurai for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 796059Samurai Diags.Report(*I); 806059Samurai} 816059Samurai 826059Samuraibool CapturedDiagList::hasErrors() const { 836059Samurai for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 846059Samurai if (I->getLevel() >= Diagnostic::Error) 8525566Sbrian return true; 8614418Sache 8714418Sache return false; 886059Samurai} 896059Samurai 906059Samurainamespace { 916059Samurai 926059Samuraiclass CaptureDiagnosticClient : public DiagnosticClient { 936059Samurai Diagnostic &Diags; 946059Samurai CapturedDiagList &CapturedDiags; 956059Samuraipublic: 966764Samurai CaptureDiagnosticClient(Diagnostic &diags, 9726142Sbrian CapturedDiagList &capturedDiags) 986059Samurai : Diags(diags), CapturedDiags(capturedDiags) { } 996059Samurai 1006059Samurai virtual void HandleDiagnostic(Diagnostic::Level level, 1016059Samurai const DiagnosticInfo &Info) { 1026059Samurai if (arcmt::isARCDiagnostic(Info.getID(), Diags) || 1036059Samurai level >= Diagnostic::Error || level == Diagnostic::Note) { 1046059Samurai CapturedDiags.push_back(StoredDiagnostic(level, Info)); 1056059Samurai return; 1066059Samurai } 1076059Samurai 1086059Samurai // Non-ARC warnings are ignored. 1096059Samurai Diags.setLastDiagnosticIgnored(); 1106059Samurai } 11120120Snate}; 11220120Snate 11325908Sbrian} // end anonymous namespace 11425908Sbrian 11520120Snatestatic inline llvm::StringRef SimulatorVersionDefineName() { 11610528Samurai return "__IPHONE_OS_VERSION_MIN_REQUIRED="; 1176059Samurai} 11810528Samurai 1196059Samurai/// \brief Parse the simulator version define: 12010528Samurai/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) 1216059Samurai// and return the grouped values as integers, e.g: 1226059Samurai// __IPHONE_OS_VERSION_MIN_REQUIRED=40201 1236059Samurai// will return Major=4, Minor=2, Micro=1. 1246059Samuraistatic bool GetVersionFromSimulatorDefine(llvm::StringRef define, 1256059Samurai unsigned &Major, unsigned &Minor, 1266059Samurai unsigned &Micro) { 1276059Samurai assert(define.startswith(SimulatorVersionDefineName())); 1286059Samurai llvm::StringRef name, version; 1296059Samurai llvm::tie(name, version) = define.split('='); 1306059Samurai if (version.empty()) 1316059Samurai return false; 1326059Samurai std::string verstr = version.str(); 1336059Samurai char *end; 13411336Samurai unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); 13511336Samurai if (*end != '\0') 1366059Samurai return false; 1376059Samurai Major = num / 10000; 1386059Samurai num = num % 10000; 1396059Samurai Minor = num / 100; 1406059Samurai Micro = num % 100; 1416059Samurai return true; 1426735Samurai} 1436735Samurai 1446735Samuraistatic bool HasARCRuntime(CompilerInvocation &origCI) { 1456735Samurai // This duplicates some functionality from Darwin::AddDeploymentTarget 1466735Samurai // but this function is well defined, so keep it decoupled from the driver 1476735Samurai // and avoid unrelated complications. 14811336Samurai 14911336Samurai for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size(); 15025801Sbrian i != e; ++i) { 15111336Samurai StringRef define = origCI.getPreprocessorOpts().Macros[i].first; 15211336Samurai bool isUndef = origCI.getPreprocessorOpts().Macros[i].second; 15311336Samurai if (isUndef) 15411336Samurai continue; 15511336Samurai if (!define.startswith(SimulatorVersionDefineName())) 15626256Sbrian continue; 15711336Samurai unsigned Major, Minor, Micro; 15811336Samurai if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && 15911336Samurai Major < 10 && Minor < 100 && Micro < 100) 16011336Samurai return Major >= 5; 16111336Samurai } 16211336Samurai 1636059Samurai llvm::Triple triple(origCI.getTargetOpts().Triple); 1646059Samurai 1656059Samurai if (triple.getOS() == llvm::Triple::IOS) 16610528Samurai return triple.getOSMajorVersion() >= 5; 16710528Samurai 16810528Samurai if (triple.getOS() == llvm::Triple::Darwin) 16910528Samurai return triple.getOSMajorVersion() >= 11; 17010528Samurai 17110528Samurai if (triple.getOS() == llvm::Triple::MacOSX) { 17210528Samurai unsigned Major, Minor, Micro; 17310528Samurai triple.getOSVersion(Major, Minor, Micro); 17420813Sjkh return Major > 10 || (Major == 10 && Minor >= 7); 17510528Samurai } 17610528Samurai 17710528Samurai return false; 17818856Ssos} 17910528Samurai 18010528SamuraiCompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) { 18110528Samurai llvm::OwningPtr<CompilerInvocation> CInvok; 18218911Ssos CInvok.reset(new CompilerInvocation(origCI)); 18310528Samurai CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); 18410528Samurai CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string(); 18510528Samurai std::string define = getARCMTMacroName(); 18610528Samurai define += '='; 18710528Samurai CInvok->getPreprocessorOpts().addMacroDef(define); 18818911Ssos CInvok->getLangOpts().ObjCAutoRefCount = true; 18910528Samurai CInvok->getDiagnosticOpts().ErrorLimit = 0; 19010528Samurai CInvok->getDiagnosticOpts().Warnings.push_back( 19110528Samurai "error=arc-unsafe-retained-assign"); 19218911Ssos CInvok->getLangOpts().ObjCRuntimeHasWeak = HasARCRuntime(origCI); 19318911Ssos 19418911Ssos return CInvok.take(); 19518911Ssos} 19618911Ssos 19718911Ssos//===----------------------------------------------------------------------===// 19818856Ssos// checkForManualIssues. 19910528Samurai//===----------------------------------------------------------------------===// 20018531Sbde 20118531Sbdebool arcmt::checkForManualIssues(CompilerInvocation &origCI, 20218531Sbde llvm::StringRef Filename, InputKind Kind, 20310528Samurai DiagnosticClient *DiagClient) { 20410528Samurai if (!origCI.getLangOpts().ObjC1) 20510528Samurai return false; 20610528Samurai 20710528Samurai std::vector<TransformFn> transforms = arcmt::getAllTransformations(); 20810528Samurai assert(!transforms.empty()); 20916263Sache 21016263Sache llvm::OwningPtr<CompilerInvocation> CInvok; 21116263Sache CInvok.reset(createInvocationForMigration(origCI)); 21216263Sache CInvok->getFrontendOpts().Inputs.clear(); 21316263Sache CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); 21416263Sache 21516263Sache CapturedDiagList capturedDiags; 21616263Sache 21710528Samurai assert(DiagClient); 21818790Ssos llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 21918790Ssos llvm::IntrusiveRefCntPtr<Diagnostic> Diags( 22018790Ssos new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 22125566Sbrian 22218790Ssos // Filter of all diagnostics. 22318790Ssos CaptureDiagnosticClient errRec(*Diags, capturedDiags); 22425566Sbrian Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 22522973Sphk 22622973Sphk llvm::OwningPtr<ASTUnit> Unit( 22725566Sbrian ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); 22818790Ssos if (!Unit) 22918790Ssos return true; 23018790Ssos 23125630Sbrian // Don't filter diagnostics anymore. 23218790Ssos Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 23310528Samurai 23425630Sbrian ASTContext &Ctx = Unit->getASTContext(); 23520813Sjkh 23610528Samurai if (Diags->hasFatalErrorOccurred()) { 23710528Samurai Diags->Reset(); 23810528Samurai DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 23910528Samurai capturedDiags.reportDiagnostics(*Diags); 24010528Samurai DiagClient->EndSourceFile(); 24110528Samurai return true; 24210528Samurai } 24310528Samurai 24410528Samurai // After parsing of source files ended, we want to reuse the 24520813Sjkh // diagnostics objects to emit further diagnostics. 24610528Samurai // We call BeginSourceFile because DiagnosticClient requires that 24720813Sjkh // diagnostics with source range information are emitted only in between 24810528Samurai // BeginSourceFile() and EndSourceFile(). 24910528Samurai DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 25010528Samurai 2516059Samurai // No macros will be added since we are just checking and we won't modify 2526059Samurai // source code. 2536059Samurai std::vector<SourceLocation> ARCMTMacroLocs; 2546059Samurai 25513760Sphk TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 2566735Samurai MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs); 2576735Samurai 2586735Samurai for (unsigned i=0, e = transforms.size(); i != e; ++i) 2596735Samurai transforms[i](pass); 2606735Samurai 2616735Samurai capturedDiags.reportDiagnostics(*Diags); 2626735Samurai 26314418Sache DiagClient->EndSourceFile(); 2646735Samurai 2656735Samurai // If we are migrating code that gets the '-fobjc-arc' flag, make sure 2666735Samurai // to remove it so that we don't get errors from normal compilation. 2676735Samurai origCI.getLangOpts().ObjCAutoRefCount = false; 2686735Samurai 2696735Samurai return capturedDiags.hasErrors(); 2706735Samurai} 2716735Samurai 2726735Samurai//===----------------------------------------------------------------------===// 2736735Samurai// applyTransformations. 2746764Samurai//===----------------------------------------------------------------------===// 2759240Sphk 2766735Samuraistatic bool applyTransforms(CompilerInvocation &origCI, 2776735Samurai llvm::StringRef Filename, InputKind Kind, 2786735Samurai DiagnosticClient *DiagClient, 2796735Samurai llvm::StringRef outputDir) { 2806735Samurai if (!origCI.getLangOpts().ObjC1) 2816735Samurai return false; 28210528Samurai 28310528Samurai // Make sure checking is successful first. 2846735Samurai CompilerInvocation CInvokForCheck(origCI); 2856735Samurai if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient)) 2866735Samurai return true; 2876735Samurai 28826031Sbrian CompilerInvocation CInvok(origCI); 28926031Sbrian CInvok.getFrontendOpts().Inputs.clear(); 2906764Samurai CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); 29114418Sache 2926735Samurai MigrationProcess migration(CInvok, DiagClient, outputDir); 2936059Samurai 2946735Samurai std::vector<TransformFn> transforms = arcmt::getAllTransformations(); 2956735Samurai assert(!transforms.empty()); 2966059Samurai 2976059Samurai for (unsigned i=0, e = transforms.size(); i != e; ++i) { 2986059Samurai bool err = migration.applyTransform(transforms[i]); 2996059Samurai if (err) return true; 3006059Samurai } 3016059Samurai 3026059Samurai llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 3036059Samurai llvm::IntrusiveRefCntPtr<Diagnostic> Diags( 3046059Samurai new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 3056059Samurai 3066059Samurai if (outputDir.empty()) { 3076059Samurai origCI.getLangOpts().ObjCAutoRefCount = true; 3086059Samurai return migration.getRemapper().overwriteOriginal(*Diags); 30915738Sphk } else { 31015738Sphk // If we are migrating code that gets the '-fobjc-arc' flag, make sure 31115738Sphk // to remove it so that we don't get errors from normal compilation. 3126059Samurai origCI.getLangOpts().ObjCAutoRefCount = false; 3136059Samurai return migration.getRemapper().flushToDisk(outputDir, *Diags); 3146059Samurai } 3156059Samurai} 3166059Samurai 3176059Samuraibool arcmt::applyTransformations(CompilerInvocation &origCI, 3186059Samurai llvm::StringRef Filename, InputKind Kind, 3196059Samurai DiagnosticClient *DiagClient) { 3206059Samurai return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef()); 3216059Samurai} 3226059Samurai 3236059Samuraibool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, 3246059Samurai llvm::StringRef Filename, InputKind Kind, 3256059Samurai DiagnosticClient *DiagClient, 3266059Samurai llvm::StringRef outputDir) { 3276059Samurai assert(!outputDir.empty() && "Expected output directory path"); 3286059Samurai return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir); 3296059Samurai} 3306059Samurai 3316059Samuraibool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 3326059Samurai remap, 3336059Samurai llvm::StringRef outputDir, 3346059Samurai DiagnosticClient *DiagClient) { 3356059Samurai assert(!outputDir.empty()); 3366059Samurai 3376059Samurai llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 3386059Samurai llvm::IntrusiveRefCntPtr<Diagnostic> Diags( 3396059Samurai new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 3406059Samurai 3416059Samurai FileRemapper remapper; 3426059Samurai bool err = remapper.initFromDisk(outputDir, *Diags, 3436059Samurai /*ignoreIfFilesChanged=*/true); 3446059Samurai if (err) 3456059Samurai return true; 3466059Samurai 3476059Samurai CompilerInvocation CI; 3486735Samurai remapper.applyMappings(CI); 3496735Samurai remap = CI.getPreprocessorOpts().RemappedFiles; 3506059Samurai 3516059Samurai return false; 3526059Samurai} 3536059Samurai 3546059Samurai//===----------------------------------------------------------------------===// 3556059Samurai// CollectTransformActions. 3566059Samurai//===----------------------------------------------------------------------===// 3576059Samurai 3586059Samurainamespace { 3596059Samurai 3606059Samuraiclass ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 3616059Samurai std::vector<SourceLocation> &ARCMTMacroLocs; 36213389Sphk 36313389Sphkpublic: 3646059Samurai ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 3659448Samurai : ARCMTMacroLocs(ARCMTMacroLocs) { } 3666059Samurai 3676059Samurai virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) { 3686059Samurai if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 3696059Samurai ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 3706059Samurai } 3716059Samurai}; 3726059Samurai 3736059Samuraiclass ARCMTMacroTrackerAction : public ASTFrontendAction { 3746059Samurai std::vector<SourceLocation> &ARCMTMacroLocs; 37526326Sbrian 37626326Sbrianpublic: 37726326Sbrian ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 37826326Sbrian : ARCMTMacroLocs(ARCMTMacroLocs) { } 37926326Sbrian 38026326Sbrian virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 38126326Sbrian llvm::StringRef InFile) { 38226326Sbrian CI.getPreprocessor().addPPCallbacks( 38326326Sbrian new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); 38426326Sbrian return new ASTConsumer(); 38526326Sbrian } 38626326Sbrian}; 38726326Sbrian 38826326Sbrianclass RewritesApplicator : public TransformActions::RewriteReceiver { 38926326Sbrian Rewriter &rewriter; 39025067Sbrian ASTContext &Ctx; 39125067Sbrian MigrationProcess::RewriteListener *Listener; 39225067Sbrian 39325067Sbrianpublic: 39425067Sbrian RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 39525067Sbrian MigrationProcess::RewriteListener *listener) 39625067Sbrian : rewriter(rewriter), Ctx(ctx), Listener(listener) { 39711336Samurai if (Listener) 39811336Samurai Listener->start(ctx); 39911336Samurai } 40011336Samurai ~RewritesApplicator() { 40111336Samurai if (Listener) 40211336Samurai Listener->finish(); 40311336Samurai } 40411336Samurai 40511336Samurai virtual void insert(SourceLocation loc, llvm::StringRef text) { 40611336Samurai bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 40711336Samurai /*indentNewLines=*/true); 40824939Sbrian if (!err && Listener) 40924939Sbrian Listener->insert(loc, text); 41024939Sbrian } 41124939Sbrian 41224939Sbrian virtual void remove(CharSourceRange range) { 41324939Sbrian Rewriter::RewriteOptions removeOpts; 41424939Sbrian removeOpts.IncludeInsertsAtBeginOfRange = false; 41524939Sbrian removeOpts.IncludeInsertsAtEndOfRange = false; 41624939Sbrian removeOpts.RemoveLineIfEmpty = true; 41711336Samurai 41811336Samurai bool err = rewriter.RemoveText(range, removeOpts); 41911336Samurai if (!err && Listener) 42011336Samurai Listener->remove(range); 42111336Samurai } 42211336Samurai 42311336Samurai virtual void increaseIndentation(CharSourceRange range, 42411336Samurai SourceLocation parentIndent) { 42518752Sjkh rewriter.IncreaseIndentation(range, parentIndent); 42618752Sjkh } 42718752Sjkh}; 42818752Sjkh 42918752Sjkh} // end anonymous namespace. 43018752Sjkh 43118752Sjkh/// \brief Anchor for VTable. 43218752SjkhMigrationProcess::RewriteListener::~RewriteListener() { } 43311336Samurai 43418752SjkhMigrationProcess::MigrationProcess(const CompilerInvocation &CI, 43518752Sjkh DiagnosticClient *diagClient, 43618752Sjkh llvm::StringRef outputDir) 43718752Sjkh : OrigCI(CI), DiagClient(diagClient) { 4386735Samurai if (!outputDir.empty()) { 4396059Samurai llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 44013760Sphk llvm::IntrusiveRefCntPtr<Diagnostic> Diags( 4416735Samurai new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 4426735Samurai Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); 4436735Samurai } 4446735Samurai} 4456735Samurai 4466735Samuraibool MigrationProcess::applyTransform(TransformFn trans, 4476735Samurai RewriteListener *listener) { 4486735Samurai llvm::OwningPtr<CompilerInvocation> CInvok; 4496735Samurai CInvok.reset(createInvocationForMigration(OrigCI)); 4506735Samurai CInvok->getDiagnosticOpts().IgnoreWarnings = true; 4516735Samurai 4526735Samurai Remapper.applyMappings(*CInvok); 4536735Samurai 4546735Samurai CapturedDiagList capturedDiags; 4556735Samurai std::vector<SourceLocation> ARCMTMacroLocs; 4566735Samurai 4576735Samurai assert(DiagClient); 4586735Samurai llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 4596735Samurai llvm::IntrusiveRefCntPtr<Diagnostic> Diags( 4606735Samurai new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 4616735Samurai 4626735Samurai // Filter of all diagnostics. 4636735Samurai CaptureDiagnosticClient errRec(*Diags, capturedDiags); 4646735Samurai Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 4656735Samurai 4666735Samurai llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction; 4676735Samurai ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 4686735Samurai 46926326Sbrian llvm::OwningPtr<ASTUnit> Unit( 47026326Sbrian ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags, 47126326Sbrian ASTAction.get())); 47226326Sbrian if (!Unit) 4736735Samurai return true; 4746735Samurai Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 4756735Samurai 4766735Samurai // Don't filter diagnostics anymore. 47725067Sbrian Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 47825690Sache 47925067Sbrian ASTContext &Ctx = Unit->getASTContext(); 48025067Sbrian 4816735Samurai if (Diags->hasFatalErrorOccurred()) { 4826735Samurai Diags->Reset(); 4836735Samurai DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 4846735Samurai capturedDiags.reportDiagnostics(*Diags); 48518752Sjkh DiagClient->EndSourceFile(); 48618752Sjkh return true; 48723598Sache } 48818752Sjkh 4896735Samurai // After parsing of source files ended, we want to reuse the 4906735Samurai // diagnostics objects to emit further diagnostics. 4916735Samurai // We call BeginSourceFile because DiagnosticClient requires that 4926735Samurai // diagnostics with source range information are emitted only in between 4936059Samurai // BeginSourceFile() and EndSourceFile(). 4946059Samurai DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 4956059Samurai 4966059Samurai Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions()); 4976059Samurai TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 4986059Samurai MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs); 4996059Samurai 5006059Samurai trans(pass); 5016059Samurai 5026059Samurai { 5036059Samurai RewritesApplicator applicator(rewriter, Ctx, listener); 5046059Samurai TA.applyRewrites(applicator); 5056059Samurai } 5066059Samurai 50725566Sbrian DiagClient->EndSourceFile(); 5086059Samurai 5096059Samurai if (DiagClient->getNumErrors()) 51025566Sbrian return true; 5116059Samurai 5126059Samurai for (Rewriter::buffer_iterator 5136059Samurai I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 5146059Samurai FileID FID = I->first; 5156059Samurai RewriteBuffer &buf = I->second; 5166059Samurai const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 5176059Samurai assert(file); 5186059Samurai std::string newFname = file->getName(); 5196059Samurai newFname += "-trans"; 5206059Samurai llvm::SmallString<512> newText; 5216059Samurai llvm::raw_svector_ostream vecOS(newText); 5226059Samurai buf.write(vecOS); 5236059Samurai vecOS.flush(); 5246059Samurai llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 5256059Samurai llvm::StringRef(newText.data(), newText.size()), newFname); 5266059Samurai llvm::SmallString<64> filePath(file->getName()); 5276059Samurai Unit->getFileManager().FixupRelativePath(filePath); 5286059Samurai Remapper.remap(filePath.str(), memBuf); 5296059Samurai } 5306059Samurai 5316059Samurai return false; 5326735Samurai} 5336735Samurai 5346059Samurai//===----------------------------------------------------------------------===// 5356059Samurai// isARCDiagnostic. 5366059Samurai//===----------------------------------------------------------------------===// 5376059Samurai 5386059Samuraibool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) { 5396059Samurai return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) == 54018885Sjkh diag::DiagCat_Automatic_Reference_Counting_Issue; 54118885Sjkh} 5426059Samurai