1//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "Internals.h" 11#include "clang/AST/ASTConsumer.h" 12#include "clang/Basic/DiagnosticCategories.h" 13#include "clang/Frontend/ASTUnit.h" 14#include "clang/Frontend/CompilerInstance.h" 15#include "clang/Frontend/FrontendAction.h" 16#include "clang/Frontend/TextDiagnosticPrinter.h" 17#include "clang/Frontend/Utils.h" 18#include "clang/Lex/Preprocessor.h" 19#include "clang/Rewrite/Core/Rewriter.h" 20#include "clang/Sema/SemaDiagnostic.h" 21#include "clang/Serialization/ASTReader.h" 22#include "llvm/ADT/Triple.h" 23#include "llvm/Support/MemoryBuffer.h" 24#include <utility> 25using namespace clang; 26using namespace arcmt; 27 28bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, 29 SourceRange range) { 30 if (range.isInvalid()) 31 return false; 32 33 bool cleared = false; 34 ListTy::iterator I = List.begin(); 35 while (I != List.end()) { 36 FullSourceLoc diagLoc = I->getLocation(); 37 if ((IDs.empty() || // empty means clear all diagnostics in the range. 38 std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 39 !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 40 (diagLoc == range.getEnd() || 41 diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 42 cleared = true; 43 ListTy::iterator eraseS = I++; 44 if (eraseS->getLevel() != DiagnosticsEngine::Note) 45 while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) 46 ++I; 47 // Clear the diagnostic and any notes following it. 48 I = List.erase(eraseS, I); 49 continue; 50 } 51 52 ++I; 53 } 54 55 return cleared; 56} 57 58bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, 59 SourceRange range) const { 60 if (range.isInvalid()) 61 return false; 62 63 ListTy::const_iterator I = List.begin(); 64 while (I != List.end()) { 65 FullSourceLoc diagLoc = I->getLocation(); 66 if ((IDs.empty() || // empty means any diagnostic in the range. 67 std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) && 68 !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && 69 (diagLoc == range.getEnd() || 70 diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { 71 return true; 72 } 73 74 ++I; 75 } 76 77 return false; 78} 79 80void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { 81 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 82 Diags.Report(*I); 83} 84 85bool CapturedDiagList::hasErrors() const { 86 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) 87 if (I->getLevel() >= DiagnosticsEngine::Error) 88 return true; 89 90 return false; 91} 92 93namespace { 94 95class CaptureDiagnosticConsumer : public DiagnosticConsumer { 96 DiagnosticsEngine &Diags; 97 DiagnosticConsumer &DiagClient; 98 CapturedDiagList &CapturedDiags; 99 bool HasBegunSourceFile; 100public: 101 CaptureDiagnosticConsumer(DiagnosticsEngine &diags, 102 DiagnosticConsumer &client, 103 CapturedDiagList &capturedDiags) 104 : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags), 105 HasBegunSourceFile(false) { } 106 107 void BeginSourceFile(const LangOptions &Opts, 108 const Preprocessor *PP) override { 109 // Pass BeginSourceFile message onto DiagClient on first call. 110 // The corresponding EndSourceFile call will be made from an 111 // explicit call to FinishCapture. 112 if (!HasBegunSourceFile) { 113 DiagClient.BeginSourceFile(Opts, PP); 114 HasBegunSourceFile = true; 115 } 116 } 117 118 void FinishCapture() { 119 // Call EndSourceFile on DiagClient on completion of capture to 120 // enable VerifyDiagnosticConsumer to check diagnostics *after* 121 // it has received the diagnostic list. 122 if (HasBegunSourceFile) { 123 DiagClient.EndSourceFile(); 124 HasBegunSourceFile = false; 125 } 126 } 127 128 ~CaptureDiagnosticConsumer() override { 129 assert(!HasBegunSourceFile && "FinishCapture not called!"); 130 } 131 132 void HandleDiagnostic(DiagnosticsEngine::Level level, 133 const Diagnostic &Info) override { 134 if (DiagnosticIDs::isARCDiagnostic(Info.getID()) || 135 level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { 136 if (Info.getLocation().isValid()) 137 CapturedDiags.push_back(StoredDiagnostic(level, Info)); 138 return; 139 } 140 141 // Non-ARC warnings are ignored. 142 Diags.setLastDiagnosticIgnored(); 143 } 144}; 145 146} // end anonymous namespace 147 148static bool HasARCRuntime(CompilerInvocation &origCI) { 149 // This duplicates some functionality from Darwin::AddDeploymentTarget 150 // but this function is well defined, so keep it decoupled from the driver 151 // and avoid unrelated complications. 152 llvm::Triple triple(origCI.getTargetOpts().Triple); 153 154 if (triple.isiOS()) 155 return triple.getOSMajorVersion() >= 5; 156 157 if (triple.isWatchOS()) 158 return true; 159 160 if (triple.getOS() == llvm::Triple::Darwin) 161 return triple.getOSMajorVersion() >= 11; 162 163 if (triple.getOS() == llvm::Triple::MacOSX) { 164 unsigned Major, Minor, Micro; 165 triple.getOSVersion(Major, Minor, Micro); 166 return Major > 10 || (Major == 10 && Minor >= 7); 167 } 168 169 return false; 170} 171 172static CompilerInvocation * 173createInvocationForMigration(CompilerInvocation &origCI, 174 const PCHContainerReader &PCHContainerRdr) { 175 std::unique_ptr<CompilerInvocation> CInvok; 176 CInvok.reset(new CompilerInvocation(origCI)); 177 PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); 178 if (!PPOpts.ImplicitPCHInclude.empty()) { 179 // We can't use a PCH because it was likely built in non-ARC mode and we 180 // want to parse in ARC. Include the original header. 181 FileManager FileMgr(origCI.getFileSystemOpts()); 182 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 183 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 184 new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 185 new IgnoringDiagConsumer())); 186 std::string OriginalFile = ASTReader::getOriginalSourceFile( 187 PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags); 188 if (!OriginalFile.empty()) 189 PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile); 190 PPOpts.ImplicitPCHInclude.clear(); 191 } 192 // FIXME: Get the original header of a PTH as well. 193 CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear(); 194 std::string define = getARCMTMacroName(); 195 define += '='; 196 CInvok->getPreprocessorOpts().addMacroDef(define); 197 CInvok->getLangOpts()->ObjCAutoRefCount = true; 198 CInvok->getLangOpts()->setGC(LangOptions::NonGC); 199 CInvok->getDiagnosticOpts().ErrorLimit = 0; 200 CInvok->getDiagnosticOpts().PedanticErrors = 0; 201 202 // Ignore -Werror flags when migrating. 203 std::vector<std::string> WarnOpts; 204 for (std::vector<std::string>::iterator 205 I = CInvok->getDiagnosticOpts().Warnings.begin(), 206 E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { 207 if (!StringRef(*I).startswith("error")) 208 WarnOpts.push_back(*I); 209 } 210 WarnOpts.push_back("error=arc-unsafe-retained-assign"); 211 CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts); 212 213 CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI); 214 CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime; 215 216 return CInvok.release(); 217} 218 219static void emitPremigrationErrors(const CapturedDiagList &arcDiags, 220 DiagnosticOptions *diagOpts, 221 Preprocessor &PP) { 222 TextDiagnosticPrinter printer(llvm::errs(), diagOpts); 223 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 224 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 225 new DiagnosticsEngine(DiagID, diagOpts, &printer, 226 /*ShouldOwnClient=*/false)); 227 Diags->setSourceManager(&PP.getSourceManager()); 228 229 printer.BeginSourceFile(PP.getLangOpts(), &PP); 230 arcDiags.reportDiagnostics(*Diags); 231 printer.EndSourceFile(); 232} 233 234//===----------------------------------------------------------------------===// 235// checkForManualIssues. 236//===----------------------------------------------------------------------===// 237 238bool arcmt::checkForManualIssues( 239 CompilerInvocation &origCI, const FrontendInputFile &Input, 240 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 241 DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors, 242 StringRef plistOut) { 243 if (!origCI.getLangOpts()->ObjC1) 244 return false; 245 246 LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 247 bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; 248 bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 249 250 std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 251 NoFinalizeRemoval); 252 assert(!transforms.empty()); 253 254 std::unique_ptr<CompilerInvocation> CInvok; 255 CInvok.reset( 256 createInvocationForMigration(origCI, PCHContainerOps->getRawReader())); 257 CInvok->getFrontendOpts().Inputs.clear(); 258 CInvok->getFrontendOpts().Inputs.push_back(Input); 259 260 CapturedDiagList capturedDiags; 261 262 assert(DiagClient); 263 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 264 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 265 new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 266 DiagClient, /*ShouldOwnClient=*/false)); 267 268 // Filter of all diagnostics. 269 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 270 Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 271 272 std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( 273 CInvok.release(), PCHContainerOps, Diags)); 274 if (!Unit) { 275 errRec.FinishCapture(); 276 return true; 277 } 278 279 // Don't filter diagnostics anymore. 280 Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 281 282 ASTContext &Ctx = Unit->getASTContext(); 283 284 if (Diags->hasFatalErrorOccurred()) { 285 Diags->Reset(); 286 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 287 capturedDiags.reportDiagnostics(*Diags); 288 DiagClient->EndSourceFile(); 289 errRec.FinishCapture(); 290 return true; 291 } 292 293 if (emitPremigrationARCErrors) 294 emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), 295 Unit->getPreprocessor()); 296 if (!plistOut.empty()) { 297 SmallVector<StoredDiagnostic, 8> arcDiags; 298 for (CapturedDiagList::iterator 299 I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) 300 arcDiags.push_back(*I); 301 writeARCDiagsToPlist(plistOut, arcDiags, 302 Ctx.getSourceManager(), Ctx.getLangOpts()); 303 } 304 305 // After parsing of source files ended, we want to reuse the 306 // diagnostics objects to emit further diagnostics. 307 // We call BeginSourceFile because DiagnosticConsumer requires that 308 // diagnostics with source range information are emitted only in between 309 // BeginSourceFile() and EndSourceFile(). 310 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 311 312 // No macros will be added since we are just checking and we won't modify 313 // source code. 314 std::vector<SourceLocation> ARCMTMacroLocs; 315 316 TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 317 MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, 318 ARCMTMacroLocs); 319 pass.setNoFinalizeRemoval(NoFinalizeRemoval); 320 if (!NoNSAllocReallocError) 321 Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error, 322 SourceLocation()); 323 324 for (unsigned i=0, e = transforms.size(); i != e; ++i) 325 transforms[i](pass); 326 327 capturedDiags.reportDiagnostics(*Diags); 328 329 DiagClient->EndSourceFile(); 330 errRec.FinishCapture(); 331 332 return capturedDiags.hasErrors() || testAct.hasReportedErrors(); 333} 334 335//===----------------------------------------------------------------------===// 336// applyTransformations. 337//===----------------------------------------------------------------------===// 338 339static bool 340applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, 341 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 342 DiagnosticConsumer *DiagClient, StringRef outputDir, 343 bool emitPremigrationARCErrors, StringRef plistOut) { 344 if (!origCI.getLangOpts()->ObjC1) 345 return false; 346 347 LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 348 349 // Make sure checking is successful first. 350 CompilerInvocation CInvokForCheck(origCI); 351 if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps, 352 DiagClient, emitPremigrationARCErrors, 353 plistOut)) 354 return true; 355 356 CompilerInvocation CInvok(origCI); 357 CInvok.getFrontendOpts().Inputs.clear(); 358 CInvok.getFrontendOpts().Inputs.push_back(Input); 359 360 MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir); 361 bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 362 363 std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 364 NoFinalizeRemoval); 365 assert(!transforms.empty()); 366 367 for (unsigned i=0, e = transforms.size(); i != e; ++i) { 368 bool err = migration.applyTransform(transforms[i]); 369 if (err) return true; 370 } 371 372 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 373 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 374 new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 375 DiagClient, /*ShouldOwnClient=*/false)); 376 377 if (outputDir.empty()) { 378 origCI.getLangOpts()->ObjCAutoRefCount = true; 379 return migration.getRemapper().overwriteOriginal(*Diags); 380 } else { 381 return migration.getRemapper().flushToDisk(outputDir, *Diags); 382 } 383} 384 385bool arcmt::applyTransformations( 386 CompilerInvocation &origCI, const FrontendInputFile &Input, 387 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 388 DiagnosticConsumer *DiagClient) { 389 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, 390 StringRef(), false, StringRef()); 391} 392 393bool arcmt::migrateWithTemporaryFiles( 394 CompilerInvocation &origCI, const FrontendInputFile &Input, 395 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 396 DiagnosticConsumer *DiagClient, StringRef outputDir, 397 bool emitPremigrationARCErrors, StringRef plistOut) { 398 assert(!outputDir.empty() && "Expected output directory path"); 399 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir, 400 emitPremigrationARCErrors, plistOut); 401} 402 403bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 404 remap, 405 StringRef outputDir, 406 DiagnosticConsumer *DiagClient) { 407 assert(!outputDir.empty()); 408 409 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 410 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 411 new DiagnosticsEngine(DiagID, new DiagnosticOptions, 412 DiagClient, /*ShouldOwnClient=*/false)); 413 414 FileRemapper remapper; 415 bool err = remapper.initFromDisk(outputDir, *Diags, 416 /*ignoreIfFilesChanged=*/true); 417 if (err) 418 return true; 419 420 PreprocessorOptions PPOpts; 421 remapper.applyMappings(PPOpts); 422 remap = PPOpts.RemappedFiles; 423 424 return false; 425} 426 427 428//===----------------------------------------------------------------------===// 429// CollectTransformActions. 430//===----------------------------------------------------------------------===// 431 432namespace { 433 434class ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 435 std::vector<SourceLocation> &ARCMTMacroLocs; 436 437public: 438 ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 439 : ARCMTMacroLocs(ARCMTMacroLocs) { } 440 441 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 442 SourceRange Range, const MacroArgs *Args) override { 443 if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 444 ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 445 } 446}; 447 448class ARCMTMacroTrackerAction : public ASTFrontendAction { 449 std::vector<SourceLocation> &ARCMTMacroLocs; 450 451public: 452 ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 453 : ARCMTMacroLocs(ARCMTMacroLocs) { } 454 455 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 456 StringRef InFile) override { 457 CI.getPreprocessor().addPPCallbacks( 458 llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs)); 459 return llvm::make_unique<ASTConsumer>(); 460 } 461}; 462 463class RewritesApplicator : public TransformActions::RewriteReceiver { 464 Rewriter &rewriter; 465 MigrationProcess::RewriteListener *Listener; 466 467public: 468 RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 469 MigrationProcess::RewriteListener *listener) 470 : rewriter(rewriter), Listener(listener) { 471 if (Listener) 472 Listener->start(ctx); 473 } 474 ~RewritesApplicator() override { 475 if (Listener) 476 Listener->finish(); 477 } 478 479 void insert(SourceLocation loc, StringRef text) override { 480 bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 481 /*indentNewLines=*/true); 482 if (!err && Listener) 483 Listener->insert(loc, text); 484 } 485 486 void remove(CharSourceRange range) override { 487 Rewriter::RewriteOptions removeOpts; 488 removeOpts.IncludeInsertsAtBeginOfRange = false; 489 removeOpts.IncludeInsertsAtEndOfRange = false; 490 removeOpts.RemoveLineIfEmpty = true; 491 492 bool err = rewriter.RemoveText(range, removeOpts); 493 if (!err && Listener) 494 Listener->remove(range); 495 } 496 497 void increaseIndentation(CharSourceRange range, 498 SourceLocation parentIndent) override { 499 rewriter.IncreaseIndentation(range, parentIndent); 500 } 501}; 502 503} // end anonymous namespace. 504 505/// \brief Anchor for VTable. 506MigrationProcess::RewriteListener::~RewriteListener() { } 507 508MigrationProcess::MigrationProcess( 509 const CompilerInvocation &CI, 510 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 511 DiagnosticConsumer *diagClient, StringRef outputDir) 512 : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)), 513 DiagClient(diagClient), HadARCErrors(false) { 514 if (!outputDir.empty()) { 515 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 516 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 517 new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), 518 DiagClient, /*ShouldOwnClient=*/false)); 519 Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); 520 } 521} 522 523bool MigrationProcess::applyTransform(TransformFn trans, 524 RewriteListener *listener) { 525 std::unique_ptr<CompilerInvocation> CInvok; 526 CInvok.reset( 527 createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader())); 528 CInvok->getDiagnosticOpts().IgnoreWarnings = true; 529 530 Remapper.applyMappings(CInvok->getPreprocessorOpts()); 531 532 CapturedDiagList capturedDiags; 533 std::vector<SourceLocation> ARCMTMacroLocs; 534 535 assert(DiagClient); 536 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 537 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 538 new DiagnosticsEngine(DiagID, new DiagnosticOptions, 539 DiagClient, /*ShouldOwnClient=*/false)); 540 541 // Filter of all diagnostics. 542 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 543 Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 544 545 std::unique_ptr<ARCMTMacroTrackerAction> ASTAction; 546 ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 547 548 std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( 549 CInvok.release(), PCHContainerOps, Diags, ASTAction.get())); 550 if (!Unit) { 551 errRec.FinishCapture(); 552 return true; 553 } 554 Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 555 556 HadARCErrors = HadARCErrors || capturedDiags.hasErrors(); 557 558 // Don't filter diagnostics anymore. 559 Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 560 561 ASTContext &Ctx = Unit->getASTContext(); 562 563 if (Diags->hasFatalErrorOccurred()) { 564 Diags->Reset(); 565 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 566 capturedDiags.reportDiagnostics(*Diags); 567 DiagClient->EndSourceFile(); 568 errRec.FinishCapture(); 569 return true; 570 } 571 572 // After parsing of source files ended, we want to reuse the 573 // diagnostics objects to emit further diagnostics. 574 // We call BeginSourceFile because DiagnosticConsumer requires that 575 // diagnostics with source range information are emitted only in between 576 // BeginSourceFile() and EndSourceFile(). 577 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 578 579 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 580 TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 581 MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), 582 Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); 583 584 trans(pass); 585 586 { 587 RewritesApplicator applicator(rewriter, Ctx, listener); 588 TA.applyRewrites(applicator); 589 } 590 591 DiagClient->EndSourceFile(); 592 errRec.FinishCapture(); 593 594 if (DiagClient->getNumErrors()) 595 return true; 596 597 for (Rewriter::buffer_iterator 598 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 599 FileID FID = I->first; 600 RewriteBuffer &buf = I->second; 601 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 602 assert(file); 603 std::string newFname = file->getName(); 604 newFname += "-trans"; 605 SmallString<512> newText; 606 llvm::raw_svector_ostream vecOS(newText); 607 buf.write(vecOS); 608 std::unique_ptr<llvm::MemoryBuffer> memBuf( 609 llvm::MemoryBuffer::getMemBufferCopy( 610 StringRef(newText.data(), newText.size()), newFname)); 611 SmallString<64> filePath(file->getName()); 612 Unit->getFileManager().FixupRelativePath(filePath); 613 Remapper.remap(filePath.str(), std::move(memBuf)); 614 } 615 616 return false; 617} 618