ARCMT.cpp revision 249423
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 } 143226633Sdim 144226633Sdim DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { 145226633Sdim // Just drop any diagnostics that come from cloned consumers; they'll 146226633Sdim // have different source managers anyway. 147226633Sdim return new IgnoringDiagConsumer(); 148226633Sdim } 149224135Sdim}; 150224135Sdim 151224135Sdim} // end anonymous namespace 152224135Sdim 153224135Sdimstatic bool HasARCRuntime(CompilerInvocation &origCI) { 154224135Sdim // This duplicates some functionality from Darwin::AddDeploymentTarget 155224135Sdim // but this function is well defined, so keep it decoupled from the driver 156224135Sdim // and avoid unrelated complications. 157224135Sdim llvm::Triple triple(origCI.getTargetOpts().Triple); 158224135Sdim 159224135Sdim if (triple.getOS() == llvm::Triple::IOS) 160224135Sdim return triple.getOSMajorVersion() >= 5; 161224135Sdim 162224135Sdim if (triple.getOS() == llvm::Triple::Darwin) 163224135Sdim return triple.getOSMajorVersion() >= 11; 164224135Sdim 165224135Sdim if (triple.getOS() == llvm::Triple::MacOSX) { 166224135Sdim unsigned Major, Minor, Micro; 167224135Sdim triple.getOSVersion(Major, Minor, Micro); 168224135Sdim return Major > 10 || (Major == 10 && Minor >= 7); 169224135Sdim } 170224135Sdim 171224135Sdim return false; 172224135Sdim} 173224135Sdim 174226633Sdimstatic CompilerInvocation * 175226633SdimcreateInvocationForMigration(CompilerInvocation &origCI) { 176234353Sdim OwningPtr<CompilerInvocation> CInvok; 177224135Sdim CInvok.reset(new CompilerInvocation(origCI)); 178249423Sdim PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); 179249423Sdim if (!PPOpts.ImplicitPCHInclude.empty()) { 180249423Sdim // We can't use a PCH because it was likely built in non-ARC mode and we 181249423Sdim // want to parse in ARC. Include the original header. 182249423Sdim FileManager FileMgr(origCI.getFileSystemOpts()); 183249423Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 184249423Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 185249423Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 186249423Sdim new IgnoringDiagConsumer())); 187249423Sdim std::string OriginalFile = 188249423Sdim ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude, 189249423Sdim FileMgr, *Diags); 190249423Sdim if (!OriginalFile.empty()) 191249423Sdim PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile); 192249423Sdim PPOpts.ImplicitPCHInclude.clear(); 193249423Sdim } 194249423Sdim // FIXME: Get the original header of a PTH as well. 195249423Sdim CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear(); 196224135Sdim std::string define = getARCMTMacroName(); 197224135Sdim define += '='; 198224135Sdim CInvok->getPreprocessorOpts().addMacroDef(define); 199234353Sdim CInvok->getLangOpts()->ObjCAutoRefCount = true; 200234353Sdim CInvok->getLangOpts()->setGC(LangOptions::NonGC); 201224135Sdim CInvok->getDiagnosticOpts().ErrorLimit = 0; 202239462Sdim CInvok->getDiagnosticOpts().PedanticErrors = 0; 203239462Sdim 204239462Sdim // Ignore -Werror flags when migrating. 205239462Sdim std::vector<std::string> WarnOpts; 206239462Sdim for (std::vector<std::string>::iterator 207239462Sdim I = CInvok->getDiagnosticOpts().Warnings.begin(), 208239462Sdim E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { 209239462Sdim if (!StringRef(*I).startswith("error")) 210239462Sdim WarnOpts.push_back(*I); 211239462Sdim } 212239462Sdim WarnOpts.push_back("error=arc-unsafe-retained-assign"); 213239462Sdim CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts); 214239462Sdim 215243830Sdim CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI); 216224135Sdim 217224135Sdim return CInvok.take(); 218224135Sdim} 219224135Sdim 220226633Sdimstatic void emitPremigrationErrors(const CapturedDiagList &arcDiags, 221243830Sdim DiagnosticOptions *diagOpts, 222226633Sdim Preprocessor &PP) { 223226633Sdim TextDiagnosticPrinter printer(llvm::errs(), diagOpts); 224234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 225234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 226243830Sdim new DiagnosticsEngine(DiagID, diagOpts, &printer, 227243830Sdim /*ShouldOwnClient=*/false)); 228226633Sdim Diags->setSourceManager(&PP.getSourceManager()); 229226633Sdim 230234353Sdim printer.BeginSourceFile(PP.getLangOpts(), &PP); 231226633Sdim arcDiags.reportDiagnostics(*Diags); 232226633Sdim printer.EndSourceFile(); 233226633Sdim} 234226633Sdim 235224135Sdim//===----------------------------------------------------------------------===// 236224135Sdim// checkForManualIssues. 237224135Sdim//===----------------------------------------------------------------------===// 238224135Sdim 239224135Sdimbool arcmt::checkForManualIssues(CompilerInvocation &origCI, 240234353Sdim const FrontendInputFile &Input, 241226633Sdim DiagnosticConsumer *DiagClient, 242226633Sdim bool emitPremigrationARCErrors, 243226633Sdim StringRef plistOut) { 244234353Sdim if (!origCI.getLangOpts()->ObjC1) 245224135Sdim return false; 246224135Sdim 247234353Sdim LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 248234353Sdim bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; 249234353Sdim bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 250234353Sdim 251234353Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 252234353Sdim NoFinalizeRemoval); 253224135Sdim assert(!transforms.empty()); 254224135Sdim 255234353Sdim OwningPtr<CompilerInvocation> CInvok; 256224135Sdim CInvok.reset(createInvocationForMigration(origCI)); 257224135Sdim CInvok->getFrontendOpts().Inputs.clear(); 258234353Sdim CInvok->getFrontendOpts().Inputs.push_back(Input); 259224135Sdim 260224135Sdim CapturedDiagList capturedDiags; 261224135Sdim 262224135Sdim assert(DiagClient); 263234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 264234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 265243830Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 266243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 267224135Sdim 268224135Sdim // Filter of all diagnostics. 269239462Sdim CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 270224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 271224135Sdim 272234353Sdim OwningPtr<ASTUnit> Unit( 273224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); 274239462Sdim if (!Unit) { 275239462Sdim errRec.FinishCapture(); 276224135Sdim return true; 277239462Sdim } 278224135Sdim 279224135Sdim // Don't filter diagnostics anymore. 280224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 281224135Sdim 282224135Sdim ASTContext &Ctx = Unit->getASTContext(); 283224135Sdim 284224135Sdim if (Diags->hasFatalErrorOccurred()) { 285224135Sdim Diags->Reset(); 286234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 287224135Sdim capturedDiags.reportDiagnostics(*Diags); 288224135Sdim DiagClient->EndSourceFile(); 289239462Sdim errRec.FinishCapture(); 290224135Sdim return true; 291224135Sdim } 292224135Sdim 293226633Sdim if (emitPremigrationARCErrors) 294243830Sdim emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), 295226633Sdim Unit->getPreprocessor()); 296226633Sdim if (!plistOut.empty()) { 297226633Sdim SmallVector<StoredDiagnostic, 8> arcDiags; 298226633Sdim for (CapturedDiagList::iterator 299226633Sdim I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) 300226633Sdim arcDiags.push_back(*I); 301226633Sdim writeARCDiagsToPlist(plistOut, arcDiags, 302234353Sdim Ctx.getSourceManager(), Ctx.getLangOpts()); 303226633Sdim } 304226633Sdim 305224135Sdim // After parsing of source files ended, we want to reuse the 306224135Sdim // diagnostics objects to emit further diagnostics. 307226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 308224135Sdim // diagnostics with source range information are emitted only in between 309224135Sdim // BeginSourceFile() and EndSourceFile(). 310234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 311224135Sdim 312224135Sdim // No macros will be added since we are just checking and we won't modify 313224135Sdim // source code. 314224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 315224135Sdim 316224135Sdim TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 317249423Sdim MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, 318249423Sdim ARCMTMacroLocs); 319234353Sdim pass.setNSAllocReallocError(NoNSAllocReallocError); 320234353Sdim pass.setNoFinalizeRemoval(NoFinalizeRemoval); 321224135Sdim 322224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) 323224135Sdim transforms[i](pass); 324224135Sdim 325224135Sdim capturedDiags.reportDiagnostics(*Diags); 326224135Sdim 327224135Sdim DiagClient->EndSourceFile(); 328239462Sdim errRec.FinishCapture(); 329224135Sdim 330224135Sdim // If we are migrating code that gets the '-fobjc-arc' flag, make sure 331224135Sdim // to remove it so that we don't get errors from normal compilation. 332234353Sdim origCI.getLangOpts()->ObjCAutoRefCount = false; 333224135Sdim 334226633Sdim return capturedDiags.hasErrors() || testAct.hasReportedErrors(); 335224135Sdim} 336224135Sdim 337224135Sdim//===----------------------------------------------------------------------===// 338224135Sdim// applyTransformations. 339224135Sdim//===----------------------------------------------------------------------===// 340224135Sdim 341224135Sdimstatic bool applyTransforms(CompilerInvocation &origCI, 342234353Sdim const FrontendInputFile &Input, 343226633Sdim DiagnosticConsumer *DiagClient, 344226633Sdim StringRef outputDir, 345226633Sdim bool emitPremigrationARCErrors, 346226633Sdim StringRef plistOut) { 347234353Sdim if (!origCI.getLangOpts()->ObjC1) 348224135Sdim return false; 349224135Sdim 350234353Sdim LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 351234353Sdim 352224135Sdim // Make sure checking is successful first. 353224135Sdim CompilerInvocation CInvokForCheck(origCI); 354234353Sdim if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient, 355226633Sdim emitPremigrationARCErrors, plistOut)) 356224135Sdim return true; 357224135Sdim 358224135Sdim CompilerInvocation CInvok(origCI); 359224135Sdim CInvok.getFrontendOpts().Inputs.clear(); 360234353Sdim CInvok.getFrontendOpts().Inputs.push_back(Input); 361224135Sdim 362224135Sdim MigrationProcess migration(CInvok, DiagClient, outputDir); 363234353Sdim bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 364224135Sdim 365234353Sdim std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 366234353Sdim NoFinalizeRemoval); 367224135Sdim assert(!transforms.empty()); 368224135Sdim 369224135Sdim for (unsigned i=0, e = transforms.size(); i != e; ++i) { 370224135Sdim bool err = migration.applyTransform(transforms[i]); 371224135Sdim if (err) return true; 372224135Sdim } 373224135Sdim 374234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 375234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 376243830Sdim new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 377243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 378224135Sdim 379224135Sdim if (outputDir.empty()) { 380234353Sdim origCI.getLangOpts()->ObjCAutoRefCount = true; 381224135Sdim return migration.getRemapper().overwriteOriginal(*Diags); 382224135Sdim } else { 383224135Sdim // If we are migrating code that gets the '-fobjc-arc' flag, make sure 384224135Sdim // to remove it so that we don't get errors from normal compilation. 385234353Sdim origCI.getLangOpts()->ObjCAutoRefCount = false; 386224135Sdim return migration.getRemapper().flushToDisk(outputDir, *Diags); 387224135Sdim } 388224135Sdim} 389224135Sdim 390224135Sdimbool arcmt::applyTransformations(CompilerInvocation &origCI, 391234353Sdim const FrontendInputFile &Input, 392226633Sdim DiagnosticConsumer *DiagClient) { 393234353Sdim return applyTransforms(origCI, Input, DiagClient, 394226633Sdim StringRef(), false, StringRef()); 395224135Sdim} 396224135Sdim 397224135Sdimbool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI, 398234353Sdim const FrontendInputFile &Input, 399226633Sdim DiagnosticConsumer *DiagClient, 400226633Sdim StringRef outputDir, 401226633Sdim bool emitPremigrationARCErrors, 402226633Sdim StringRef plistOut) { 403224135Sdim assert(!outputDir.empty() && "Expected output directory path"); 404234353Sdim return applyTransforms(origCI, Input, DiagClient, 405226633Sdim outputDir, emitPremigrationARCErrors, plistOut); 406224135Sdim} 407224135Sdim 408224135Sdimbool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 409224135Sdim remap, 410226633Sdim StringRef outputDir, 411226633Sdim DiagnosticConsumer *DiagClient) { 412224135Sdim assert(!outputDir.empty()); 413224135Sdim 414234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 415234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 416243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 417243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 418224135Sdim 419224135Sdim FileRemapper remapper; 420224135Sdim bool err = remapper.initFromDisk(outputDir, *Diags, 421224135Sdim /*ignoreIfFilesChanged=*/true); 422224135Sdim if (err) 423224135Sdim return true; 424224135Sdim 425234353Sdim PreprocessorOptions PPOpts; 426234353Sdim remapper.applyMappings(PPOpts); 427234353Sdim remap = PPOpts.RemappedFiles; 428224135Sdim 429224135Sdim return false; 430224135Sdim} 431224135Sdim 432234353Sdimbool arcmt::getFileRemappingsFromFileList( 433234353Sdim std::vector<std::pair<std::string,std::string> > &remap, 434234353Sdim ArrayRef<StringRef> remapFiles, 435234353Sdim DiagnosticConsumer *DiagClient) { 436234353Sdim bool hasErrorOccurred = false; 437234353Sdim llvm::StringMap<bool> Uniquer; 438234353Sdim 439249423Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 440249423Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 441243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 442243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 443234353Sdim 444234353Sdim for (ArrayRef<StringRef>::iterator 445234353Sdim I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) { 446234353Sdim StringRef file = *I; 447234353Sdim 448234353Sdim FileRemapper remapper; 449234353Sdim bool err = remapper.initFromFile(file, *Diags, 450234353Sdim /*ignoreIfFilesChanged=*/true); 451234353Sdim hasErrorOccurred = hasErrorOccurred || err; 452234353Sdim if (err) 453234353Sdim continue; 454234353Sdim 455234353Sdim PreprocessorOptions PPOpts; 456234353Sdim remapper.applyMappings(PPOpts); 457234353Sdim for (PreprocessorOptions::remapped_file_iterator 458234353Sdim RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end(); 459234353Sdim RI != RE; ++RI) { 460234353Sdim bool &inserted = Uniquer[RI->first]; 461234353Sdim if (inserted) 462234353Sdim continue; 463234353Sdim inserted = true; 464234353Sdim remap.push_back(*RI); 465234353Sdim } 466234353Sdim } 467234353Sdim 468234353Sdim return hasErrorOccurred; 469234353Sdim} 470234353Sdim 471224135Sdim//===----------------------------------------------------------------------===// 472224135Sdim// CollectTransformActions. 473224135Sdim//===----------------------------------------------------------------------===// 474224135Sdim 475224135Sdimnamespace { 476224135Sdim 477224135Sdimclass ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 478224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 479224135Sdim 480224135Sdimpublic: 481224135Sdim ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 482224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 483224135Sdim 484249423Sdim virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, 485226633Sdim SourceRange Range) { 486224135Sdim if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 487224135Sdim ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 488224135Sdim } 489224135Sdim}; 490224135Sdim 491224135Sdimclass ARCMTMacroTrackerAction : public ASTFrontendAction { 492224135Sdim std::vector<SourceLocation> &ARCMTMacroLocs; 493224135Sdim 494224135Sdimpublic: 495224135Sdim ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 496224135Sdim : ARCMTMacroLocs(ARCMTMacroLocs) { } 497224135Sdim 498224135Sdim virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, 499226633Sdim StringRef InFile) { 500224135Sdim CI.getPreprocessor().addPPCallbacks( 501224135Sdim new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); 502224135Sdim return new ASTConsumer(); 503224135Sdim } 504224135Sdim}; 505224135Sdim 506224135Sdimclass RewritesApplicator : public TransformActions::RewriteReceiver { 507224135Sdim Rewriter &rewriter; 508224135Sdim MigrationProcess::RewriteListener *Listener; 509224135Sdim 510224135Sdimpublic: 511224135Sdim RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 512224135Sdim MigrationProcess::RewriteListener *listener) 513239462Sdim : rewriter(rewriter), Listener(listener) { 514224135Sdim if (Listener) 515224135Sdim Listener->start(ctx); 516224135Sdim } 517224135Sdim ~RewritesApplicator() { 518224135Sdim if (Listener) 519224135Sdim Listener->finish(); 520224135Sdim } 521224135Sdim 522226633Sdim virtual void insert(SourceLocation loc, StringRef text) { 523224135Sdim bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 524224135Sdim /*indentNewLines=*/true); 525224135Sdim if (!err && Listener) 526224135Sdim Listener->insert(loc, text); 527224135Sdim } 528224135Sdim 529224135Sdim virtual void remove(CharSourceRange range) { 530224135Sdim Rewriter::RewriteOptions removeOpts; 531224135Sdim removeOpts.IncludeInsertsAtBeginOfRange = false; 532224135Sdim removeOpts.IncludeInsertsAtEndOfRange = false; 533224135Sdim removeOpts.RemoveLineIfEmpty = true; 534224135Sdim 535224135Sdim bool err = rewriter.RemoveText(range, removeOpts); 536224135Sdim if (!err && Listener) 537224135Sdim Listener->remove(range); 538224135Sdim } 539224135Sdim 540224135Sdim virtual void increaseIndentation(CharSourceRange range, 541224135Sdim SourceLocation parentIndent) { 542224135Sdim rewriter.IncreaseIndentation(range, parentIndent); 543224135Sdim } 544224135Sdim}; 545224135Sdim 546224135Sdim} // end anonymous namespace. 547224135Sdim 548224135Sdim/// \brief Anchor for VTable. 549224135SdimMigrationProcess::RewriteListener::~RewriteListener() { } 550224135Sdim 551224135SdimMigrationProcess::MigrationProcess(const CompilerInvocation &CI, 552226633Sdim DiagnosticConsumer *diagClient, 553226633Sdim StringRef outputDir) 554224135Sdim : OrigCI(CI), DiagClient(diagClient) { 555224135Sdim if (!outputDir.empty()) { 556234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 557234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 558243830Sdim new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), 559243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 560224135Sdim Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); 561224135Sdim } 562224135Sdim} 563224135Sdim 564224135Sdimbool MigrationProcess::applyTransform(TransformFn trans, 565224135Sdim RewriteListener *listener) { 566234353Sdim OwningPtr<CompilerInvocation> CInvok; 567224135Sdim CInvok.reset(createInvocationForMigration(OrigCI)); 568224135Sdim CInvok->getDiagnosticOpts().IgnoreWarnings = true; 569224135Sdim 570234353Sdim Remapper.applyMappings(CInvok->getPreprocessorOpts()); 571224135Sdim 572224135Sdim CapturedDiagList capturedDiags; 573224135Sdim std::vector<SourceLocation> ARCMTMacroLocs; 574224135Sdim 575224135Sdim assert(DiagClient); 576234353Sdim IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 577234353Sdim IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 578243830Sdim new DiagnosticsEngine(DiagID, new DiagnosticOptions, 579243830Sdim DiagClient, /*ShouldOwnClient=*/false)); 580224135Sdim 581224135Sdim // Filter of all diagnostics. 582239462Sdim CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 583224135Sdim Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 584224135Sdim 585234353Sdim OwningPtr<ARCMTMacroTrackerAction> ASTAction; 586224135Sdim ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 587224135Sdim 588234353Sdim OwningPtr<ASTUnit> Unit( 589224135Sdim ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags, 590224135Sdim ASTAction.get())); 591239462Sdim if (!Unit) { 592239462Sdim errRec.FinishCapture(); 593224135Sdim return true; 594239462Sdim } 595224135Sdim Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 596224135Sdim 597224135Sdim // Don't filter diagnostics anymore. 598224135Sdim Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 599224135Sdim 600224135Sdim ASTContext &Ctx = Unit->getASTContext(); 601224135Sdim 602224135Sdim if (Diags->hasFatalErrorOccurred()) { 603224135Sdim Diags->Reset(); 604234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 605224135Sdim capturedDiags.reportDiagnostics(*Diags); 606224135Sdim DiagClient->EndSourceFile(); 607239462Sdim errRec.FinishCapture(); 608224135Sdim return true; 609224135Sdim } 610224135Sdim 611224135Sdim // After parsing of source files ended, we want to reuse the 612224135Sdim // diagnostics objects to emit further diagnostics. 613226633Sdim // We call BeginSourceFile because DiagnosticConsumer requires that 614224135Sdim // diagnostics with source range information are emitted only in between 615224135Sdim // BeginSourceFile() and EndSourceFile(). 616234353Sdim DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 617224135Sdim 618234353Sdim Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 619224135Sdim TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 620234353Sdim MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), 621249423Sdim Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); 622224135Sdim 623224135Sdim trans(pass); 624224135Sdim 625224135Sdim { 626224135Sdim RewritesApplicator applicator(rewriter, Ctx, listener); 627224135Sdim TA.applyRewrites(applicator); 628224135Sdim } 629224135Sdim 630224135Sdim DiagClient->EndSourceFile(); 631239462Sdim errRec.FinishCapture(); 632224135Sdim 633224135Sdim if (DiagClient->getNumErrors()) 634224135Sdim return true; 635224135Sdim 636224135Sdim for (Rewriter::buffer_iterator 637224135Sdim I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 638224135Sdim FileID FID = I->first; 639224135Sdim RewriteBuffer &buf = I->second; 640224135Sdim const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 641224135Sdim assert(file); 642224135Sdim std::string newFname = file->getName(); 643224135Sdim newFname += "-trans"; 644234353Sdim SmallString<512> newText; 645224135Sdim llvm::raw_svector_ostream vecOS(newText); 646224135Sdim buf.write(vecOS); 647224135Sdim vecOS.flush(); 648224135Sdim llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 649226633Sdim StringRef(newText.data(), newText.size()), newFname); 650234353Sdim SmallString<64> filePath(file->getName()); 651224135Sdim Unit->getFileManager().FixupRelativePath(filePath); 652224135Sdim Remapper.remap(filePath.str(), memBuf); 653224135Sdim } 654224135Sdim 655224135Sdim return false; 656224135Sdim} 657