ARCMT.cpp revision 261991
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" 11249423Sdim#include "clang/AST/ASTConsumer.h" 12249423Sdim#include "clang/Basic/DiagnosticCategories.h" 13224135Sdim#include "clang/Frontend/ASTUnit.h" 14224135Sdim#include "clang/Frontend/CompilerInstance.h" 15234353Sdim#include "clang/Frontend/FrontendAction.h" 16226633Sdim#include "clang/Frontend/TextDiagnosticPrinter.h" 17224135Sdim#include "clang/Frontend/Utils.h" 18249423Sdim#include "clang/Lex/Preprocessor.h" 19243830Sdim#include "clang/Rewrite/Core/Rewriter.h" 20224135Sdim#include "clang/Sema/SemaDiagnostic.h" 21249423Sdim#include "clang/Serialization/ASTReader.h" 22249423Sdim#include "llvm/ADT/Triple.h" 23224135Sdim#include "llvm/Support/MemoryBuffer.h" 24224135Sdimusing namespace clang; 25224135Sdimusing namespace arcmt; 26224135Sdim 27226633Sdimbool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, 28224135Sdim SourceRange range) { 29224135Sdim if (range.isInvalid()) 30224135Sdim return false; 31224135Sdim 32224135Sdim bool cleared = false; 33224135Sdim ListTy::iterator I = List.begin(); 34224135Sdim while (I != List.end()) { 35224135Sdim FullSourceLoc diagLoc = I->getLocation(); 36224135Sdim if ((IDs.empty() || // empty means clear all diagnostics in the range. 37224135Sdim std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 38224135Sdim !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 39224135Sdim (diagLoc == range.getEnd() || 40224135Sdim diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 41224135Sdim cleared = true; 42224135Sdim ListTy::iterator eraseS = I++; 43249423Sdim if (eraseS->getLevel() != DiagnosticsEngine::Note) 44249423Sdim while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) 45249423Sdim ++I; 46224135Sdim // Clear the diagnostic and any notes following it. 47243830Sdim I = List.erase(eraseS, I); 48224135Sdim continue; 49224135Sdim } 50224135Sdim 51224135Sdim ++I; 52224135Sdim } 53224135Sdim 54224135Sdim return cleared; 55224135Sdim} 56224135Sdim 57226633Sdimbool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, 58224135Sdim SourceRange range) const { 59224135Sdim if (range.isInvalid()) 60224135Sdim return false; 61224135Sdim 62224135Sdim ListTy::const_iterator I = List.begin(); 63224135Sdim while (I != List.end()) { 64224135Sdim FullSourceLoc diagLoc = I->getLocation(); 65224135Sdim if ((IDs.empty() || // empty means any diagnostic in the range. 66224135Sdim std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 67224135Sdim !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 68224135Sdim (diagLoc == range.getEnd() || 69224135Sdim diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 70224135Sdim return true; 71224135Sdim } 72224135Sdim 73224135Sdim ++I; 74224135Sdim } 75224135Sdim 76224135Sdim return false; 77224135Sdim} 78224135Sdim 79226633Sdimvoid CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { 80224135Sdim for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 81224135Sdim Diags.Report(*I); 82224135Sdim} 83224135Sdim 84224135Sdimbool CapturedDiagList::hasErrors() const { 85224135Sdim for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 86226633Sdim if (I->getLevel() >= DiagnosticsEngine::Error) 87224135Sdim return true; 88224135Sdim 89224135Sdim return false; 90224135Sdim} 91224135Sdim 92224135Sdimnamespace { 93224135Sdim 94226633Sdimclass CaptureDiagnosticConsumer : public DiagnosticConsumer { 95226633Sdim DiagnosticsEngine &Diags; 96239462Sdim DiagnosticConsumer &DiagClient; 97224135Sdim CapturedDiagList &CapturedDiags; 98239462Sdim bool HasBegunSourceFile; 99224135Sdimpublic: 100226633Sdim CaptureDiagnosticConsumer(DiagnosticsEngine &diags, 101239462Sdim DiagnosticConsumer &client, 102239462Sdim CapturedDiagList &capturedDiags) 103239462Sdim : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags), 104239462Sdim HasBegunSourceFile(false) { } 105224135Sdim 106239462Sdim virtual void BeginSourceFile(const LangOptions &Opts, 107239462Sdim const Preprocessor *PP) { 108239462Sdim // Pass BeginSourceFile message onto DiagClient on first call. 109239462Sdim // The corresponding EndSourceFile call will be made from an 110239462Sdim // explicit call to FinishCapture. 111239462Sdim if (!HasBegunSourceFile) { 112239462Sdim DiagClient.BeginSourceFile(Opts, PP); 113239462Sdim HasBegunSourceFile = true; 114239462Sdim } 115239462Sdim } 116239462Sdim 117239462Sdim void FinishCapture() { 118239462Sdim // Call EndSourceFile on DiagClient on completion of capture to 119239462Sdim // enable VerifyDiagnosticConsumer to check diagnostics *after* 120239462Sdim // it has received the diagnostic list. 121239462Sdim if (HasBegunSourceFile) { 122239462Sdim DiagClient.EndSourceFile(); 123239462Sdim HasBegunSourceFile = false; 124239462Sdim } 125239462Sdim } 126239462Sdim 127239462Sdim virtual ~CaptureDiagnosticConsumer() { 128239462Sdim assert(!HasBegunSourceFile && "FinishCapture not called!"); 129239462Sdim } 130239462Sdim 131226633Sdim virtual void HandleDiagnostic(DiagnosticsEngine::Level level, 132226633Sdim const Diagnostic &Info) { 133234353Sdim if (DiagnosticIDs::isARCDiagnostic(Info.getID()) || 134226633Sdim level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { 135249423Sdim if (Info.getLocation().isValid()) 136249423Sdim CapturedDiags.push_back(StoredDiagnostic(level, Info)); 137224135Sdim return; 138224135Sdim } 139224135Sdim 140224135Sdim // Non-ARC warnings are ignored. 141224135Sdim Diags.setLastDiagnosticIgnored(); 142224135Sdim } 143224135Sdim}; 144224135Sdim 145224135Sdim} // end anonymous namespace 146224135Sdim 147224135Sdimstatic bool HasARCRuntime(CompilerInvocation &origCI) { 148224135Sdim // This duplicates some functionality from Darwin::AddDeploymentTarget 149224135Sdim // but this function is well defined, so keep it decoupled from the driver 150224135Sdim // and avoid unrelated complications. 151224135Sdim llvm::Triple triple(origCI.getTargetOpts().Triple); 152224135Sdim 153261991Sdim if (triple.isiOS()) 154224135Sdim return triple.getOSMajorVersion() >= 5; 155224135Sdim 156224135Sdim if (triple.getOS() == llvm::Triple::Darwin) 157224135Sdim return triple.getOSMajorVersion() >= 11; 158224135Sdim 159224135Sdim if (triple.getOS() == llvm::Triple::MacOSX) { 160224135Sdim unsigned Major, Minor, Micro; 161224135Sdim triple.getOSVersion(Major, Minor, Micro); 162224135Sdim return Major > 10 || (Major == 10 && Minor >= 7); 163224135Sdim } 164224135Sdim 165224135Sdim return false; 166224135Sdim} 167224135Sdim 168226633Sdimstatic CompilerInvocation * 169226633SdimcreateInvocationForMigration(CompilerInvocation &origCI) { 170234353Sdim OwningPtr<CompilerInvocation> CInvok; 171224135Sdim CInvok.reset(new CompilerInvocation(origCI)); 172249423Sdim PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); 173249423Sdim if (!PPOpts.ImplicitPCHInclude.empty()) { 174249423Sdim // We can't use a PCH because it was likely built in non-ARC mode and we 175249423Sdim // want to parse in ARC. Include the original header. 176249423Sdim FileManager FileMgr(origCI.getFileSystemOpts()); 177249423Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 178249423Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 179249423Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 180249423Sdim new IgnoringDiagConsumer())); 181249423Sdim std::string OriginalFile = 182249423Sdim ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude, 183249423Sdim FileMgr, *Diags); 184249423Sdim if (!OriginalFile.empty()) 185249423Sdim PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile); 186249423Sdim PPOpts.ImplicitPCHInclude.clear(); 187249423Sdim } 188249423Sdim // FIXME: Get the original header of a PTH as well. 189249423Sdim CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear(); 190224135Sdim std::string define = getARCMTMacroName(); 191224135Sdim define += '='; 192224135Sdim CInvok->getPreprocessorOpts().addMacroDef(define); 193234353Sdim CInvok->getLangOpts()->ObjCAutoRefCount = true; 194234353Sdim CInvok->getLangOpts()->setGC(LangOptions::NonGC); 195224135Sdim CInvok->getDiagnosticOpts().ErrorLimit = 0; 196239462Sdim CInvok->getDiagnosticOpts().PedanticErrors = 0; 197239462Sdim 198239462Sdim // Ignore -Werror flags when migrating. 199239462Sdim std::vector<std::string> WarnOpts; 200239462Sdim for (std::vector<std::string>::iterator 201239462Sdim I = CInvok->getDiagnosticOpts().Warnings.begin(), 202239462Sdim E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { 203239462Sdim if (!StringRef(*I).startswith("error")) 204239462Sdim WarnOpts.push_back(*I); 205239462Sdim } 206239462Sdim WarnOpts.push_back("error=arc-unsafe-retained-assign"); 207239462Sdim CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts); 208239462Sdim 209243830Sdim CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI); 210224135Sdim 211224135Sdim return CInvok.take(); 212224135Sdim} 213224135Sdim 214226633Sdimstatic void emitPremigrationErrors(const CapturedDiagList &arcDiags, 215243830Sdim DiagnosticOptions *diagOpts, 216226633Sdim Preprocessor &PP) { 217226633Sdim TextDiagnosticPrinter printer(llvm::errs(), diagOpts); 218234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 219234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 220243830Sdim new DiagnosticsEngine(DiagID, diagOpts, &printer, 221243830Sdim /*ShouldOwnClient=*/false)); 222226633Sdim Diags->setSourceManager(&PP.getSourceManager()); 223226633Sdim 224234353Sdim printer.BeginSourceFile(PP.getLangOpts(), &PP); 225226633Sdim arcDiags.reportDiagnostics(*Diags); 226226633Sdim printer.EndSourceFile(); 227226633Sdim} 228226633Sdim 229224135Sdim//===----------------------------------------------------------------------===// 230224135Sdim// checkForManualIssues. 231224135Sdim//===----------------------------------------------------------------------===// 232224135Sdim 233224135Sdimbool arcmt::checkForManualIssues(CompilerInvocation &origCI, 234234353Sdim const FrontendInputFile &Input, 235226633Sdim DiagnosticConsumer *DiagClient, 236226633Sdim bool emitPremigrationARCErrors, 237226633Sdim StringRef plistOut) { 238234353Sdim if (!origCI.getLangOpts()->ObjC1) 239224135Sdim return false; 240224135Sdim 241234353Sdim LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 242234353Sdim bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; 243234353Sdim bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 244234353Sdim 245234353Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 246234353Sdim NoFinalizeRemoval); 247224135Sdim assert(!transforms.empty()); 248224135Sdim 249234353Sdim OwningPtr<CompilerInvocation> CInvok; 250224135Sdim CInvok.reset(createInvocationForMigration(origCI)); 251224135Sdim CInvok->getFrontendOpts().Inputs.clear(); 252234353Sdim CInvok->getFrontendOpts().Inputs.push_back(Input); 253224135Sdim 254224135Sdim CapturedDiagList capturedDiags; 255224135Sdim 256224135Sdim assert(DiagClient); 257234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 258234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 259243830Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 260243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 261224135Sdim 262224135Sdim // Filter of all diagnostics. 263239462Sdim CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 264224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 265224135Sdim 266234353Sdim OwningPtr<ASTUnit> Unit( 267224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); 268239462Sdim if (!Unit) { 269239462Sdim errRec.FinishCapture(); 270224135Sdim return true; 271239462Sdim } 272224135Sdim 273224135Sdim // Don't filter diagnostics anymore. 274224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 275224135Sdim 276224135Sdim ASTContext &Ctx = Unit->getASTContext(); 277224135Sdim 278224135Sdim if (Diags->hasFatalErrorOccurred()) { 279224135Sdim Diags->Reset(); 280234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 281224135Sdim capturedDiags.reportDiagnostics(*Diags); 282224135Sdim DiagClient->EndSourceFile(); 283239462Sdim errRec.FinishCapture(); 284224135Sdim return true; 285224135Sdim } 286224135Sdim 287226633Sdim if (emitPremigrationARCErrors) 288243830Sdim emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), 289226633Sdim Unit->getPreprocessor()); 290226633Sdim if (!plistOut.empty()) { 291226633Sdim SmallVector<StoredDiagnostic, 8> arcDiags; 292226633Sdim for (CapturedDiagList::iterator 293226633Sdim I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) 294226633Sdim arcDiags.push_back(*I); 295226633Sdim writeARCDiagsToPlist(plistOut, arcDiags, 296234353Sdim Ctx.getSourceManager(), Ctx.getLangOpts()); 297226633Sdim } 298226633Sdim 299224135Sdim // After parsing of source files ended, we want to reuse the 300224135Sdim // diagnostics objects to emit further diagnostics. 301226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 302224135Sdim // diagnostics with source range information are emitted only in between 303224135Sdim // BeginSourceFile() and EndSourceFile(). 304234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 305224135Sdim 306224135Sdim // No macros will be added since we are just checking and we won't modify 307224135Sdim // source code. 308224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 309224135Sdim 310224135Sdim TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 311249423Sdim MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, 312249423Sdim ARCMTMacroLocs); 313234353Sdim pass.setNSAllocReallocError(NoNSAllocReallocError); 314234353Sdim pass.setNoFinalizeRemoval(NoFinalizeRemoval); 315224135Sdim 316224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) 317224135Sdim transforms[i](pass); 318224135Sdim 319224135Sdim capturedDiags.reportDiagnostics(*Diags); 320224135Sdim 321224135Sdim DiagClient->EndSourceFile(); 322239462Sdim errRec.FinishCapture(); 323224135Sdim 324226633Sdim return capturedDiags.hasErrors() || testAct.hasReportedErrors(); 325224135Sdim} 326224135Sdim 327224135Sdim//===----------------------------------------------------------------------===// 328224135Sdim// applyTransformations. 329224135Sdim//===----------------------------------------------------------------------===// 330224135Sdim 331224135Sdimstatic bool applyTransforms(CompilerInvocation &origCI, 332234353Sdim const FrontendInputFile &Input, 333226633Sdim DiagnosticConsumer *DiagClient, 334226633Sdim StringRef outputDir, 335226633Sdim bool emitPremigrationARCErrors, 336226633Sdim StringRef plistOut) { 337234353Sdim if (!origCI.getLangOpts()->ObjC1) 338224135Sdim return false; 339224135Sdim 340234353Sdim LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 341234353Sdim 342224135Sdim // Make sure checking is successful first. 343224135Sdim CompilerInvocation CInvokForCheck(origCI); 344234353Sdim if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient, 345226633Sdim emitPremigrationARCErrors, plistOut)) 346224135Sdim return true; 347224135Sdim 348224135Sdim CompilerInvocation CInvok(origCI); 349224135Sdim CInvok.getFrontendOpts().Inputs.clear(); 350234353Sdim CInvok.getFrontendOpts().Inputs.push_back(Input); 351224135Sdim 352224135Sdim MigrationProcess migration(CInvok, DiagClient, outputDir); 353234353Sdim bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 354224135Sdim 355234353Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 356234353Sdim NoFinalizeRemoval); 357224135Sdim assert(!transforms.empty()); 358224135Sdim 359224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) { 360224135Sdim bool err = migration.applyTransform(transforms[i]); 361224135Sdim if (err) return true; 362224135Sdim } 363224135Sdim 364234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 365234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 366243830Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 367243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 368224135Sdim 369224135Sdim if (outputDir.empty()) { 370234353Sdim origCI.getLangOpts()->ObjCAutoRefCount = true; 371224135Sdim return migration.getRemapper().overwriteOriginal(*Diags); 372224135Sdim } else { 373224135Sdim return migration.getRemapper().flushToDisk(outputDir, *Diags); 374224135Sdim } 375224135Sdim} 376224135Sdim 377224135Sdimbool arcmt::applyTransformations(CompilerInvocation &origCI, 378234353Sdim const FrontendInputFile &Input, 379226633Sdim DiagnosticConsumer *DiagClient) { 380234353Sdim return applyTransforms(origCI, Input, DiagClient, 381226633Sdim StringRef(), false, StringRef()); 382224135Sdim} 383224135Sdim 384224135Sdimbool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, 385234353Sdim const FrontendInputFile &Input, 386226633Sdim DiagnosticConsumer *DiagClient, 387226633Sdim StringRef outputDir, 388226633Sdim bool emitPremigrationARCErrors, 389226633Sdim StringRef plistOut) { 390224135Sdim assert(!outputDir.empty() && "Expected output directory path"); 391234353Sdim return applyTransforms(origCI, Input, DiagClient, 392226633Sdim outputDir, emitPremigrationARCErrors, plistOut); 393224135Sdim} 394224135Sdim 395224135Sdimbool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 396224135Sdim remap, 397226633Sdim StringRef outputDir, 398226633Sdim DiagnosticConsumer *DiagClient) { 399224135Sdim assert(!outputDir.empty()); 400224135Sdim 401234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 402234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 403243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 404243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 405224135Sdim 406224135Sdim FileRemapper remapper; 407224135Sdim bool err = remapper.initFromDisk(outputDir, *Diags, 408224135Sdim /*ignoreIfFilesChanged=*/true); 409224135Sdim if (err) 410224135Sdim return true; 411224135Sdim 412234353Sdim PreprocessorOptions PPOpts; 413234353Sdim remapper.applyMappings(PPOpts); 414234353Sdim remap = PPOpts.RemappedFiles; 415224135Sdim 416224135Sdim return false; 417224135Sdim} 418224135Sdim 419234353Sdimbool arcmt::getFileRemappingsFromFileList( 420234353Sdim std::vector<std::pair<std::string,std::string> > &remap, 421234353Sdim ArrayRef<StringRef> remapFiles, 422234353Sdim DiagnosticConsumer *DiagClient) { 423234353Sdim bool hasErrorOccurred = false; 424234353Sdim llvm::StringMap<bool> Uniquer; 425234353Sdim 426249423Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 427249423Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 428243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 429243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 430234353Sdim 431234353Sdim for (ArrayRef<StringRef>::iterator 432234353Sdim I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) { 433234353Sdim StringRef file = *I; 434234353Sdim 435234353Sdim FileRemapper remapper; 436234353Sdim bool err = remapper.initFromFile(file, *Diags, 437234353Sdim /*ignoreIfFilesChanged=*/true); 438234353Sdim hasErrorOccurred = hasErrorOccurred || err; 439234353Sdim if (err) 440234353Sdim continue; 441234353Sdim 442234353Sdim PreprocessorOptions PPOpts; 443234353Sdim remapper.applyMappings(PPOpts); 444234353Sdim for (PreprocessorOptions::remapped_file_iterator 445234353Sdim RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end(); 446234353Sdim RI != RE; ++RI) { 447234353Sdim bool &inserted = Uniquer[RI->first]; 448234353Sdim if (inserted) 449234353Sdim continue; 450234353Sdim inserted = true; 451234353Sdim remap.push_back(*RI); 452234353Sdim } 453234353Sdim } 454234353Sdim 455234353Sdim return hasErrorOccurred; 456234353Sdim} 457234353Sdim 458224135Sdim//===----------------------------------------------------------------------===// 459224135Sdim// CollectTransformActions. 460224135Sdim//===----------------------------------------------------------------------===// 461224135Sdim 462224135Sdimnamespace { 463224135Sdim 464224135Sdimclass ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 465224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 466224135Sdim 467224135Sdimpublic: 468224135Sdim ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 469224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 470224135Sdim 471249423Sdim virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, 472251662Sdim SourceRange Range, const MacroArgs *Args) { 473224135Sdim if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 474224135Sdim ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 475224135Sdim } 476224135Sdim}; 477224135Sdim 478224135Sdimclass ARCMTMacroTrackerAction : public ASTFrontendAction { 479224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 480224135Sdim 481224135Sdimpublic: 482224135Sdim ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 483224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 484224135Sdim 485224135Sdim virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 486226633Sdim StringRef InFile) { 487224135Sdim CI.getPreprocessor().addPPCallbacks( 488224135Sdim new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); 489224135Sdim return new ASTConsumer(); 490224135Sdim } 491224135Sdim}; 492224135Sdim 493224135Sdimclass RewritesApplicator : public TransformActions::RewriteReceiver { 494224135Sdim Rewriter &rewriter; 495224135Sdim MigrationProcess::RewriteListener *Listener; 496224135Sdim 497224135Sdimpublic: 498224135Sdim RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 499224135Sdim MigrationProcess::RewriteListener *listener) 500239462Sdim : rewriter(rewriter), Listener(listener) { 501224135Sdim if (Listener) 502224135Sdim Listener->start(ctx); 503224135Sdim } 504224135Sdim ~RewritesApplicator() { 505224135Sdim if (Listener) 506224135Sdim Listener->finish(); 507224135Sdim } 508224135Sdim 509226633Sdim virtual void insert(SourceLocation loc, StringRef text) { 510224135Sdim bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 511224135Sdim /*indentNewLines=*/true); 512224135Sdim if (!err && Listener) 513224135Sdim Listener->insert(loc, text); 514224135Sdim } 515224135Sdim 516224135Sdim virtual void remove(CharSourceRange range) { 517224135Sdim Rewriter::RewriteOptions removeOpts; 518224135Sdim removeOpts.IncludeInsertsAtBeginOfRange = false; 519224135Sdim removeOpts.IncludeInsertsAtEndOfRange = false; 520224135Sdim removeOpts.RemoveLineIfEmpty = true; 521224135Sdim 522224135Sdim bool err = rewriter.RemoveText(range, removeOpts); 523224135Sdim if (!err && Listener) 524224135Sdim Listener->remove(range); 525224135Sdim } 526224135Sdim 527224135Sdim virtual void increaseIndentation(CharSourceRange range, 528224135Sdim SourceLocation parentIndent) { 529224135Sdim rewriter.IncreaseIndentation(range, parentIndent); 530224135Sdim } 531224135Sdim}; 532224135Sdim 533224135Sdim} // end anonymous namespace. 534224135Sdim 535224135Sdim/// \brief Anchor for VTable. 536224135SdimMigrationProcess::RewriteListener::~RewriteListener() { } 537224135Sdim 538224135SdimMigrationProcess::MigrationProcess(const CompilerInvocation &CI, 539226633Sdim DiagnosticConsumer *diagClient, 540226633Sdim StringRef outputDir) 541261991Sdim : OrigCI(CI), DiagClient(diagClient), HadARCErrors(false) { 542224135Sdim if (!outputDir.empty()) { 543234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 544234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 545243830Sdim new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), 546243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 547224135Sdim Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); 548224135Sdim } 549224135Sdim} 550224135Sdim 551224135Sdimbool MigrationProcess::applyTransform(TransformFn trans, 552224135Sdim RewriteListener *listener) { 553234353Sdim OwningPtr<CompilerInvocation> CInvok; 554224135Sdim CInvok.reset(createInvocationForMigration(OrigCI)); 555224135Sdim CInvok->getDiagnosticOpts().IgnoreWarnings = true; 556224135Sdim 557234353Sdim Remapper.applyMappings(CInvok->getPreprocessorOpts()); 558224135Sdim 559224135Sdim CapturedDiagList capturedDiags; 560224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 561224135Sdim 562224135Sdim assert(DiagClient); 563234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 564234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 565243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 566243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 567224135Sdim 568224135Sdim // Filter of all diagnostics. 569239462Sdim CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 570224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 571224135Sdim 572234353Sdim OwningPtr<ARCMTMacroTrackerAction> ASTAction; 573224135Sdim ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 574224135Sdim 575234353Sdim OwningPtr<ASTUnit> Unit( 576224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags, 577224135Sdim ASTAction.get())); 578239462Sdim if (!Unit) { 579239462Sdim errRec.FinishCapture(); 580224135Sdim return true; 581239462Sdim } 582224135Sdim Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 583224135Sdim 584261991Sdim HadARCErrors = HadARCErrors || capturedDiags.hasErrors(); 585261991Sdim 586224135Sdim // Don't filter diagnostics anymore. 587224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 588224135Sdim 589224135Sdim ASTContext &Ctx = Unit->getASTContext(); 590224135Sdim 591224135Sdim if (Diags->hasFatalErrorOccurred()) { 592224135Sdim Diags->Reset(); 593234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 594224135Sdim capturedDiags.reportDiagnostics(*Diags); 595224135Sdim DiagClient->EndSourceFile(); 596239462Sdim errRec.FinishCapture(); 597224135Sdim return true; 598224135Sdim } 599224135Sdim 600224135Sdim // After parsing of source files ended, we want to reuse the 601224135Sdim // diagnostics objects to emit further diagnostics. 602226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 603224135Sdim // diagnostics with source range information are emitted only in between 604224135Sdim // BeginSourceFile() and EndSourceFile(). 605234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 606224135Sdim 607234353Sdim Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 608224135Sdim TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 609234353Sdim MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), 610249423Sdim Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); 611224135Sdim 612224135Sdim trans(pass); 613224135Sdim 614224135Sdim { 615224135Sdim RewritesApplicator applicator(rewriter, Ctx, listener); 616224135Sdim TA.applyRewrites(applicator); 617224135Sdim } 618224135Sdim 619224135Sdim DiagClient->EndSourceFile(); 620239462Sdim errRec.FinishCapture(); 621224135Sdim 622224135Sdim if (DiagClient->getNumErrors()) 623224135Sdim return true; 624224135Sdim 625224135Sdim for (Rewriter::buffer_iterator 626224135Sdim I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 627224135Sdim FileID FID = I->first; 628224135Sdim RewriteBuffer &buf = I->second; 629224135Sdim const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 630224135Sdim assert(file); 631224135Sdim std::string newFname = file->getName(); 632224135Sdim newFname += "-trans"; 633234353Sdim SmallString<512> newText; 634224135Sdim llvm::raw_svector_ostream vecOS(newText); 635224135Sdim buf.write(vecOS); 636224135Sdim vecOS.flush(); 637224135Sdim llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 638226633Sdim StringRef(newText.data(), newText.size()), newFname); 639234353Sdim SmallString<64> filePath(file->getName()); 640224135Sdim Unit->getFileManager().FixupRelativePath(filePath); 641224135Sdim Remapper.remap(filePath.str(), memBuf); 642224135Sdim } 643224135Sdim 644224135Sdim return false; 645224135Sdim} 646