ARCMT.cpp revision 226633
1224135Sdim//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 2224135Sdim// 3224135Sdim// The LLVM Compiler Infrastructure 4224135Sdim// 5224135Sdim// This file is distributed under the University of Illinois Open Source 6224135Sdim// License. See LICENSE.TXT for details. 7224135Sdim// 8224135Sdim//===----------------------------------------------------------------------===// 9224135Sdim 10224135Sdim#include "Internals.h" 11224135Sdim#include "clang/Frontend/ASTUnit.h" 12224135Sdim#include "clang/Frontend/CompilerInstance.h" 13226633Sdim#include "clang/Frontend/TextDiagnosticPrinter.h" 14224135Sdim#include "clang/Frontend/Utils.h" 15224135Sdim#include "clang/AST/ASTConsumer.h" 16224135Sdim#include "clang/Rewrite/Rewriter.h" 17224135Sdim#include "clang/Sema/SemaDiagnostic.h" 18224135Sdim#include "clang/Basic/DiagnosticCategories.h" 19224135Sdim#include "clang/Lex/Preprocessor.h" 20224135Sdim#include "llvm/Support/MemoryBuffer.h" 21224135Sdim#include "llvm/ADT/Triple.h" 22224135Sdimusing namespace clang; 23224135Sdimusing namespace arcmt; 24224135Sdim 25226633Sdimbool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, 26224135Sdim SourceRange range) { 27224135Sdim if (range.isInvalid()) 28224135Sdim return false; 29224135Sdim 30224135Sdim bool cleared = false; 31224135Sdim ListTy::iterator I = List.begin(); 32224135Sdim while (I != List.end()) { 33224135Sdim FullSourceLoc diagLoc = I->getLocation(); 34224135Sdim if ((IDs.empty() || // empty means clear all diagnostics in the range. 35224135Sdim std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 36224135Sdim !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 37224135Sdim (diagLoc == range.getEnd() || 38224135Sdim diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 39224135Sdim cleared = true; 40224135Sdim ListTy::iterator eraseS = I++; 41226633Sdim while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) 42224135Sdim ++I; 43224135Sdim // Clear the diagnostic and any notes following it. 44224135Sdim List.erase(eraseS, I); 45224135Sdim continue; 46224135Sdim } 47224135Sdim 48224135Sdim ++I; 49224135Sdim } 50224135Sdim 51224135Sdim return cleared; 52224135Sdim} 53224135Sdim 54226633Sdimbool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, 55224135Sdim SourceRange range) const { 56224135Sdim if (range.isInvalid()) 57224135Sdim return false; 58224135Sdim 59224135Sdim ListTy::const_iterator I = List.begin(); 60224135Sdim while (I != List.end()) { 61224135Sdim FullSourceLoc diagLoc = I->getLocation(); 62224135Sdim if ((IDs.empty() || // empty means any diagnostic in the range. 63224135Sdim std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 64224135Sdim !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 65224135Sdim (diagLoc == range.getEnd() || 66224135Sdim diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 67224135Sdim return true; 68224135Sdim } 69224135Sdim 70224135Sdim ++I; 71224135Sdim } 72224135Sdim 73224135Sdim return false; 74224135Sdim} 75224135Sdim 76226633Sdimvoid CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { 77224135Sdim for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 78224135Sdim Diags.Report(*I); 79224135Sdim} 80224135Sdim 81224135Sdimbool CapturedDiagList::hasErrors() const { 82224135Sdim for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 83226633Sdim if (I->getLevel() >= DiagnosticsEngine::Error) 84224135Sdim return true; 85224135Sdim 86224135Sdim return false; 87224135Sdim} 88224135Sdim 89224135Sdimnamespace { 90224135Sdim 91226633Sdimclass CaptureDiagnosticConsumer : public DiagnosticConsumer { 92226633Sdim DiagnosticsEngine &Diags; 93224135Sdim CapturedDiagList &CapturedDiags; 94224135Sdimpublic: 95226633Sdim CaptureDiagnosticConsumer(DiagnosticsEngine &diags, 96226633Sdim CapturedDiagList &capturedDiags) 97224135Sdim : Diags(diags), CapturedDiags(capturedDiags) { } 98224135Sdim 99226633Sdim virtual void HandleDiagnostic(DiagnosticsEngine::Level level, 100226633Sdim const Diagnostic &Info) { 101224135Sdim if (arcmt::isARCDiagnostic(Info.getID(), Diags) || 102226633Sdim level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { 103224135Sdim CapturedDiags.push_back(StoredDiagnostic(level, Info)); 104224135Sdim return; 105224135Sdim } 106224135Sdim 107224135Sdim // Non-ARC warnings are ignored. 108224135Sdim Diags.setLastDiagnosticIgnored(); 109224135Sdim } 110226633Sdim 111226633Sdim DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { 112226633Sdim // Just drop any diagnostics that come from cloned consumers; they'll 113226633Sdim // have different source managers anyway. 114226633Sdim return new IgnoringDiagConsumer(); 115226633Sdim } 116224135Sdim}; 117224135Sdim 118224135Sdim} // end anonymous namespace 119224135Sdim 120226633Sdimstatic inline StringRef SimulatorVersionDefineName() { 121224135Sdim return "__IPHONE_OS_VERSION_MIN_REQUIRED="; 122224135Sdim} 123224135Sdim 124224135Sdim/// \brief Parse the simulator version define: 125224135Sdim/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) 126224135Sdim// and return the grouped values as integers, e.g: 127224135Sdim// __IPHONE_OS_VERSION_MIN_REQUIRED=40201 128224135Sdim// will return Major=4, Minor=2, Micro=1. 129226633Sdimstatic bool GetVersionFromSimulatorDefine(StringRef define, 130224135Sdim unsigned &Major, unsigned &Minor, 131224135Sdim unsigned &Micro) { 132224135Sdim assert(define.startswith(SimulatorVersionDefineName())); 133226633Sdim StringRef name, version; 134224135Sdim llvm::tie(name, version) = define.split('='); 135224135Sdim if (version.empty()) 136224135Sdim return false; 137224135Sdim std::string verstr = version.str(); 138224135Sdim char *end; 139224135Sdim unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); 140224135Sdim if (*end != '\0') 141224135Sdim return false; 142224135Sdim Major = num / 10000; 143224135Sdim num = num % 10000; 144224135Sdim Minor = num / 100; 145224135Sdim Micro = num % 100; 146224135Sdim return true; 147224135Sdim} 148224135Sdim 149224135Sdimstatic bool HasARCRuntime(CompilerInvocation &origCI) { 150224135Sdim // This duplicates some functionality from Darwin::AddDeploymentTarget 151224135Sdim // but this function is well defined, so keep it decoupled from the driver 152224135Sdim // and avoid unrelated complications. 153224135Sdim 154224135Sdim for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size(); 155224135Sdim i != e; ++i) { 156224135Sdim StringRef define = origCI.getPreprocessorOpts().Macros[i].first; 157224135Sdim bool isUndef = origCI.getPreprocessorOpts().Macros[i].second; 158224135Sdim if (isUndef) 159224135Sdim continue; 160224135Sdim if (!define.startswith(SimulatorVersionDefineName())) 161224135Sdim continue; 162226633Sdim unsigned Major = 0, Minor = 0, Micro = 0; 163224135Sdim if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && 164224135Sdim Major < 10 && Minor < 100 && Micro < 100) 165224135Sdim return Major >= 5; 166224135Sdim } 167224135Sdim 168224135Sdim llvm::Triple triple(origCI.getTargetOpts().Triple); 169224135Sdim 170224135Sdim if (triple.getOS() == llvm::Triple::IOS) 171224135Sdim return triple.getOSMajorVersion() >= 5; 172224135Sdim 173224135Sdim if (triple.getOS() == llvm::Triple::Darwin) 174224135Sdim return triple.getOSMajorVersion() >= 11; 175224135Sdim 176224135Sdim if (triple.getOS() == llvm::Triple::MacOSX) { 177224135Sdim unsigned Major, Minor, Micro; 178224135Sdim triple.getOSVersion(Major, Minor, Micro); 179224135Sdim return Major > 10 || (Major == 10 && Minor >= 7); 180224135Sdim } 181224135Sdim 182224135Sdim return false; 183224135Sdim} 184224135Sdim 185226633Sdimstatic CompilerInvocation * 186226633SdimcreateInvocationForMigration(CompilerInvocation &origCI) { 187224135Sdim llvm::OwningPtr<CompilerInvocation> CInvok; 188224135Sdim CInvok.reset(new CompilerInvocation(origCI)); 189224135Sdim CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string(); 190224135Sdim CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string(); 191224135Sdim std::string define = getARCMTMacroName(); 192224135Sdim define += '='; 193224135Sdim CInvok->getPreprocessorOpts().addMacroDef(define); 194224135Sdim CInvok->getLangOpts().ObjCAutoRefCount = true; 195224135Sdim CInvok->getDiagnosticOpts().ErrorLimit = 0; 196224135Sdim CInvok->getDiagnosticOpts().Warnings.push_back( 197224135Sdim "error=arc-unsafe-retained-assign"); 198224135Sdim CInvok->getLangOpts().ObjCRuntimeHasWeak = HasARCRuntime(origCI); 199224135Sdim 200224135Sdim return CInvok.take(); 201224135Sdim} 202224135Sdim 203226633Sdimstatic void emitPremigrationErrors(const CapturedDiagList &arcDiags, 204226633Sdim const DiagnosticOptions &diagOpts, 205226633Sdim Preprocessor &PP) { 206226633Sdim TextDiagnosticPrinter printer(llvm::errs(), diagOpts); 207226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 208226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 209226633Sdim new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false)); 210226633Sdim Diags->setSourceManager(&PP.getSourceManager()); 211226633Sdim 212226633Sdim printer.BeginSourceFile(PP.getLangOptions(), &PP); 213226633Sdim arcDiags.reportDiagnostics(*Diags); 214226633Sdim printer.EndSourceFile(); 215226633Sdim} 216226633Sdim 217224135Sdim//===----------------------------------------------------------------------===// 218224135Sdim// checkForManualIssues. 219224135Sdim//===----------------------------------------------------------------------===// 220224135Sdim 221224135Sdimbool arcmt::checkForManualIssues(CompilerInvocation &origCI, 222226633Sdim StringRef Filename, InputKind Kind, 223226633Sdim DiagnosticConsumer *DiagClient, 224226633Sdim bool emitPremigrationARCErrors, 225226633Sdim StringRef plistOut) { 226224135Sdim if (!origCI.getLangOpts().ObjC1) 227224135Sdim return false; 228224135Sdim 229224135Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(); 230224135Sdim assert(!transforms.empty()); 231224135Sdim 232224135Sdim llvm::OwningPtr<CompilerInvocation> CInvok; 233224135Sdim CInvok.reset(createInvocationForMigration(origCI)); 234224135Sdim CInvok->getFrontendOpts().Inputs.clear(); 235224135Sdim CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); 236224135Sdim 237224135Sdim CapturedDiagList capturedDiags; 238224135Sdim 239224135Sdim assert(DiagClient); 240224135Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 241226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 242226633Sdim new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 243224135Sdim 244224135Sdim // Filter of all diagnostics. 245226633Sdim CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); 246224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 247224135Sdim 248224135Sdim llvm::OwningPtr<ASTUnit> Unit( 249224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); 250224135Sdim if (!Unit) 251224135Sdim return true; 252224135Sdim 253224135Sdim // Don't filter diagnostics anymore. 254224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 255224135Sdim 256224135Sdim ASTContext &Ctx = Unit->getASTContext(); 257224135Sdim 258224135Sdim if (Diags->hasFatalErrorOccurred()) { 259224135Sdim Diags->Reset(); 260224135Sdim DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 261224135Sdim capturedDiags.reportDiagnostics(*Diags); 262224135Sdim DiagClient->EndSourceFile(); 263224135Sdim return true; 264224135Sdim } 265224135Sdim 266226633Sdim if (emitPremigrationARCErrors) 267226633Sdim emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(), 268226633Sdim Unit->getPreprocessor()); 269226633Sdim if (!plistOut.empty()) { 270226633Sdim SmallVector<StoredDiagnostic, 8> arcDiags; 271226633Sdim for (CapturedDiagList::iterator 272226633Sdim I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) 273226633Sdim arcDiags.push_back(*I); 274226633Sdim writeARCDiagsToPlist(plistOut, arcDiags, 275226633Sdim Ctx.getSourceManager(), Ctx.getLangOptions()); 276226633Sdim } 277226633Sdim 278224135Sdim // After parsing of source files ended, we want to reuse the 279224135Sdim // diagnostics objects to emit further diagnostics. 280226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 281224135Sdim // diagnostics with source range information are emitted only in between 282224135Sdim // BeginSourceFile() and EndSourceFile(). 283224135Sdim DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 284224135Sdim 285224135Sdim // No macros will be added since we are just checking and we won't modify 286224135Sdim // source code. 287224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 288224135Sdim 289224135Sdim TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 290224135Sdim MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs); 291224135Sdim 292224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) 293224135Sdim transforms[i](pass); 294224135Sdim 295224135Sdim capturedDiags.reportDiagnostics(*Diags); 296224135Sdim 297224135Sdim DiagClient->EndSourceFile(); 298224135Sdim 299224135Sdim // If we are migrating code that gets the '-fobjc-arc' flag, make sure 300224135Sdim // to remove it so that we don't get errors from normal compilation. 301224135Sdim origCI.getLangOpts().ObjCAutoRefCount = false; 302224135Sdim 303226633Sdim return capturedDiags.hasErrors() || testAct.hasReportedErrors(); 304224135Sdim} 305224135Sdim 306224135Sdim//===----------------------------------------------------------------------===// 307224135Sdim// applyTransformations. 308224135Sdim//===----------------------------------------------------------------------===// 309224135Sdim 310224135Sdimstatic bool applyTransforms(CompilerInvocation &origCI, 311226633Sdim StringRef Filename, InputKind Kind, 312226633Sdim DiagnosticConsumer *DiagClient, 313226633Sdim StringRef outputDir, 314226633Sdim bool emitPremigrationARCErrors, 315226633Sdim StringRef plistOut) { 316224135Sdim if (!origCI.getLangOpts().ObjC1) 317224135Sdim return false; 318224135Sdim 319224135Sdim // Make sure checking is successful first. 320224135Sdim CompilerInvocation CInvokForCheck(origCI); 321226633Sdim if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient, 322226633Sdim emitPremigrationARCErrors, plistOut)) 323224135Sdim return true; 324224135Sdim 325224135Sdim CompilerInvocation CInvok(origCI); 326224135Sdim CInvok.getFrontendOpts().Inputs.clear(); 327224135Sdim CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); 328224135Sdim 329224135Sdim MigrationProcess migration(CInvok, DiagClient, outputDir); 330224135Sdim 331224135Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(); 332224135Sdim assert(!transforms.empty()); 333224135Sdim 334224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) { 335224135Sdim bool err = migration.applyTransform(transforms[i]); 336224135Sdim if (err) return true; 337224135Sdim } 338224135Sdim 339224135Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 340226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 341226633Sdim new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 342224135Sdim 343224135Sdim if (outputDir.empty()) { 344224135Sdim origCI.getLangOpts().ObjCAutoRefCount = true; 345224135Sdim return migration.getRemapper().overwriteOriginal(*Diags); 346224135Sdim } else { 347224135Sdim // If we are migrating code that gets the '-fobjc-arc' flag, make sure 348224135Sdim // to remove it so that we don't get errors from normal compilation. 349224135Sdim origCI.getLangOpts().ObjCAutoRefCount = false; 350224135Sdim return migration.getRemapper().flushToDisk(outputDir, *Diags); 351224135Sdim } 352224135Sdim} 353224135Sdim 354224135Sdimbool arcmt::applyTransformations(CompilerInvocation &origCI, 355226633Sdim StringRef Filename, InputKind Kind, 356226633Sdim DiagnosticConsumer *DiagClient) { 357226633Sdim return applyTransforms(origCI, Filename, Kind, DiagClient, 358226633Sdim StringRef(), false, StringRef()); 359224135Sdim} 360224135Sdim 361224135Sdimbool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, 362226633Sdim StringRef Filename, InputKind Kind, 363226633Sdim DiagnosticConsumer *DiagClient, 364226633Sdim StringRef outputDir, 365226633Sdim bool emitPremigrationARCErrors, 366226633Sdim StringRef plistOut) { 367224135Sdim assert(!outputDir.empty() && "Expected output directory path"); 368226633Sdim return applyTransforms(origCI, Filename, Kind, DiagClient, 369226633Sdim outputDir, emitPremigrationARCErrors, plistOut); 370224135Sdim} 371224135Sdim 372224135Sdimbool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 373224135Sdim remap, 374226633Sdim StringRef outputDir, 375226633Sdim DiagnosticConsumer *DiagClient) { 376224135Sdim assert(!outputDir.empty()); 377224135Sdim 378224135Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 379226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 380226633Sdim new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 381224135Sdim 382224135Sdim FileRemapper remapper; 383224135Sdim bool err = remapper.initFromDisk(outputDir, *Diags, 384224135Sdim /*ignoreIfFilesChanged=*/true); 385224135Sdim if (err) 386224135Sdim return true; 387224135Sdim 388224135Sdim CompilerInvocation CI; 389224135Sdim remapper.applyMappings(CI); 390224135Sdim remap = CI.getPreprocessorOpts().RemappedFiles; 391224135Sdim 392224135Sdim return false; 393224135Sdim} 394224135Sdim 395224135Sdim//===----------------------------------------------------------------------===// 396224135Sdim// CollectTransformActions. 397224135Sdim//===----------------------------------------------------------------------===// 398224135Sdim 399224135Sdimnamespace { 400224135Sdim 401224135Sdimclass ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 402224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 403224135Sdim 404224135Sdimpublic: 405224135Sdim ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 406224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 407224135Sdim 408226633Sdim virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI, 409226633Sdim SourceRange Range) { 410224135Sdim if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 411224135Sdim ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 412224135Sdim } 413224135Sdim}; 414224135Sdim 415224135Sdimclass ARCMTMacroTrackerAction : public ASTFrontendAction { 416224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 417224135Sdim 418224135Sdimpublic: 419224135Sdim ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 420224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 421224135Sdim 422224135Sdim virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 423226633Sdim StringRef InFile) { 424224135Sdim CI.getPreprocessor().addPPCallbacks( 425224135Sdim new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); 426224135Sdim return new ASTConsumer(); 427224135Sdim } 428224135Sdim}; 429224135Sdim 430224135Sdimclass RewritesApplicator : public TransformActions::RewriteReceiver { 431224135Sdim Rewriter &rewriter; 432224135Sdim ASTContext &Ctx; 433224135Sdim MigrationProcess::RewriteListener *Listener; 434224135Sdim 435224135Sdimpublic: 436224135Sdim RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 437224135Sdim MigrationProcess::RewriteListener *listener) 438224135Sdim : rewriter(rewriter), Ctx(ctx), Listener(listener) { 439224135Sdim if (Listener) 440224135Sdim Listener->start(ctx); 441224135Sdim } 442224135Sdim ~RewritesApplicator() { 443224135Sdim if (Listener) 444224135Sdim Listener->finish(); 445224135Sdim } 446224135Sdim 447226633Sdim virtual void insert(SourceLocation loc, StringRef text) { 448224135Sdim bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 449224135Sdim /*indentNewLines=*/true); 450224135Sdim if (!err && Listener) 451224135Sdim Listener->insert(loc, text); 452224135Sdim } 453224135Sdim 454224135Sdim virtual void remove(CharSourceRange range) { 455224135Sdim Rewriter::RewriteOptions removeOpts; 456224135Sdim removeOpts.IncludeInsertsAtBeginOfRange = false; 457224135Sdim removeOpts.IncludeInsertsAtEndOfRange = false; 458224135Sdim removeOpts.RemoveLineIfEmpty = true; 459224135Sdim 460224135Sdim bool err = rewriter.RemoveText(range, removeOpts); 461224135Sdim if (!err && Listener) 462224135Sdim Listener->remove(range); 463224135Sdim } 464224135Sdim 465224135Sdim virtual void increaseIndentation(CharSourceRange range, 466224135Sdim SourceLocation parentIndent) { 467224135Sdim rewriter.IncreaseIndentation(range, parentIndent); 468224135Sdim } 469224135Sdim}; 470224135Sdim 471224135Sdim} // end anonymous namespace. 472224135Sdim 473224135Sdim/// \brief Anchor for VTable. 474224135SdimMigrationProcess::RewriteListener::~RewriteListener() { } 475224135Sdim 476224135SdimMigrationProcess::MigrationProcess(const CompilerInvocation &CI, 477226633Sdim DiagnosticConsumer *diagClient, 478226633Sdim StringRef outputDir) 479224135Sdim : OrigCI(CI), DiagClient(diagClient) { 480224135Sdim if (!outputDir.empty()) { 481224135Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 482226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 483226633Sdim new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 484224135Sdim Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); 485224135Sdim } 486224135Sdim} 487224135Sdim 488224135Sdimbool MigrationProcess::applyTransform(TransformFn trans, 489224135Sdim RewriteListener *listener) { 490224135Sdim llvm::OwningPtr<CompilerInvocation> CInvok; 491224135Sdim CInvok.reset(createInvocationForMigration(OrigCI)); 492224135Sdim CInvok->getDiagnosticOpts().IgnoreWarnings = true; 493224135Sdim 494224135Sdim Remapper.applyMappings(*CInvok); 495224135Sdim 496224135Sdim CapturedDiagList capturedDiags; 497224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 498224135Sdim 499224135Sdim assert(DiagClient); 500224135Sdim llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 501226633Sdim llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 502226633Sdim new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); 503224135Sdim 504224135Sdim // Filter of all diagnostics. 505226633Sdim CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); 506224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 507224135Sdim 508224135Sdim llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction; 509224135Sdim ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 510224135Sdim 511224135Sdim llvm::OwningPtr<ASTUnit> Unit( 512224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags, 513224135Sdim ASTAction.get())); 514224135Sdim if (!Unit) 515224135Sdim return true; 516224135Sdim Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 517224135Sdim 518224135Sdim // Don't filter diagnostics anymore. 519224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 520224135Sdim 521224135Sdim ASTContext &Ctx = Unit->getASTContext(); 522224135Sdim 523224135Sdim if (Diags->hasFatalErrorOccurred()) { 524224135Sdim Diags->Reset(); 525224135Sdim DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 526224135Sdim capturedDiags.reportDiagnostics(*Diags); 527224135Sdim DiagClient->EndSourceFile(); 528224135Sdim return true; 529224135Sdim } 530224135Sdim 531224135Sdim // After parsing of source files ended, we want to reuse the 532224135Sdim // diagnostics objects to emit further diagnostics. 533226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 534224135Sdim // diagnostics with source range information are emitted only in between 535224135Sdim // BeginSourceFile() and EndSourceFile(). 536224135Sdim DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); 537224135Sdim 538224135Sdim Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions()); 539224135Sdim TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 540224135Sdim MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs); 541224135Sdim 542224135Sdim trans(pass); 543224135Sdim 544224135Sdim { 545224135Sdim RewritesApplicator applicator(rewriter, Ctx, listener); 546224135Sdim TA.applyRewrites(applicator); 547224135Sdim } 548224135Sdim 549224135Sdim DiagClient->EndSourceFile(); 550224135Sdim 551224135Sdim if (DiagClient->getNumErrors()) 552224135Sdim return true; 553224135Sdim 554224135Sdim for (Rewriter::buffer_iterator 555224135Sdim I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 556224135Sdim FileID FID = I->first; 557224135Sdim RewriteBuffer &buf = I->second; 558224135Sdim const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 559224135Sdim assert(file); 560224135Sdim std::string newFname = file->getName(); 561224135Sdim newFname += "-trans"; 562224135Sdim llvm::SmallString<512> newText; 563224135Sdim llvm::raw_svector_ostream vecOS(newText); 564224135Sdim buf.write(vecOS); 565224135Sdim vecOS.flush(); 566224135Sdim llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 567226633Sdim StringRef(newText.data(), newText.size()), newFname); 568224135Sdim llvm::SmallString<64> filePath(file->getName()); 569224135Sdim Unit->getFileManager().FixupRelativePath(filePath); 570224135Sdim Remapper.remap(filePath.str(), memBuf); 571224135Sdim } 572224135Sdim 573224135Sdim return false; 574224135Sdim} 575224135Sdim 576224135Sdim//===----------------------------------------------------------------------===// 577224135Sdim// isARCDiagnostic. 578224135Sdim//===----------------------------------------------------------------------===// 579224135Sdim 580226633Sdimbool arcmt::isARCDiagnostic(unsigned diagID, DiagnosticsEngine &Diag) { 581224135Sdim return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) == 582224135Sdim diag::DiagCat_Automatic_Reference_Counting_Issue; 583224135Sdim} 584