1 //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Internals.h" 10 #include "clang/AST/ASTConsumer.h" 11 #include "clang/Basic/DiagnosticCategories.h" 12 #include "clang/Frontend/ASTUnit.h" 13 #include "clang/Frontend/CompilerInstance.h" 14 #include "clang/Frontend/FrontendAction.h" 15 #include "clang/Frontend/TextDiagnosticPrinter.h" 16 #include "clang/Frontend/Utils.h" 17 #include "clang/Lex/Preprocessor.h" 18 #include "clang/Lex/PreprocessorOptions.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> 25 using namespace clang; 26 using namespace arcmt; 27 28 bool 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 llvm::is_contained(IDs, I->getID())) && 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 58 bool 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 llvm::find(IDs, 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 80 void 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 85 bool 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 93 namespace { 94 95 class CaptureDiagnosticConsumer : public DiagnosticConsumer { 96 DiagnosticsEngine &Diags; 97 DiagnosticConsumer &DiagClient; 98 CapturedDiagList &CapturedDiags; 99 bool HasBegunSourceFile; 100 public: 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(true); 143 } 144 }; 145 146 } // end anonymous namespace 147 148 static 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 172 static CompilerInvocation * 173 createInvocationForMigration(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 std::string define = getARCMTMacroName(); 193 define += '='; 194 CInvok->getPreprocessorOpts().addMacroDef(define); 195 CInvok->getLangOpts()->ObjCAutoRefCount = true; 196 CInvok->getLangOpts()->setGC(LangOptions::NonGC); 197 CInvok->getDiagnosticOpts().ErrorLimit = 0; 198 CInvok->getDiagnosticOpts().PedanticErrors = 0; 199 200 // Ignore -Werror flags when migrating. 201 std::vector<std::string> WarnOpts; 202 for (std::vector<std::string>::iterator 203 I = CInvok->getDiagnosticOpts().Warnings.begin(), 204 E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { 205 if (!StringRef(*I).startswith("error")) 206 WarnOpts.push_back(*I); 207 } 208 WarnOpts.push_back("error=arc-unsafe-retained-assign"); 209 CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts); 210 211 CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI); 212 CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime; 213 214 return CInvok.release(); 215 } 216 217 static void emitPremigrationErrors(const CapturedDiagList &arcDiags, 218 DiagnosticOptions *diagOpts, 219 Preprocessor &PP) { 220 TextDiagnosticPrinter printer(llvm::errs(), diagOpts); 221 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 222 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 223 new DiagnosticsEngine(DiagID, diagOpts, &printer, 224 /*ShouldOwnClient=*/false)); 225 Diags->setSourceManager(&PP.getSourceManager()); 226 227 printer.BeginSourceFile(PP.getLangOpts(), &PP); 228 arcDiags.reportDiagnostics(*Diags); 229 printer.EndSourceFile(); 230 } 231 232 //===----------------------------------------------------------------------===// 233 // checkForManualIssues. 234 //===----------------------------------------------------------------------===// 235 236 bool arcmt::checkForManualIssues( 237 CompilerInvocation &origCI, const FrontendInputFile &Input, 238 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 239 DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors, 240 StringRef plistOut) { 241 if (!origCI.getLangOpts()->ObjC) 242 return false; 243 244 LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 245 bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; 246 bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 247 248 std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 249 NoFinalizeRemoval); 250 assert(!transforms.empty()); 251 252 std::unique_ptr<CompilerInvocation> CInvok; 253 CInvok.reset( 254 createInvocationForMigration(origCI, PCHContainerOps->getRawReader())); 255 CInvok->getFrontendOpts().Inputs.clear(); 256 CInvok->getFrontendOpts().Inputs.push_back(Input); 257 258 CapturedDiagList capturedDiags; 259 260 assert(DiagClient); 261 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 262 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 263 new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 264 DiagClient, /*ShouldOwnClient=*/false)); 265 266 // Filter of all diagnostics. 267 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 268 Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 269 270 std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( 271 std::move(CInvok), PCHContainerOps, Diags)); 272 if (!Unit) { 273 errRec.FinishCapture(); 274 return true; 275 } 276 277 // Don't filter diagnostics anymore. 278 Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 279 280 ASTContext &Ctx = Unit->getASTContext(); 281 282 if (Diags->hasFatalErrorOccurred()) { 283 Diags->Reset(); 284 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 285 capturedDiags.reportDiagnostics(*Diags); 286 DiagClient->EndSourceFile(); 287 errRec.FinishCapture(); 288 return true; 289 } 290 291 if (emitPremigrationARCErrors) 292 emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), 293 Unit->getPreprocessor()); 294 if (!plistOut.empty()) { 295 SmallVector<StoredDiagnostic, 8> arcDiags; 296 for (CapturedDiagList::iterator 297 I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) 298 arcDiags.push_back(*I); 299 writeARCDiagsToPlist(plistOut, arcDiags, 300 Ctx.getSourceManager(), Ctx.getLangOpts()); 301 } 302 303 // After parsing of source files ended, we want to reuse the 304 // diagnostics objects to emit further diagnostics. 305 // We call BeginSourceFile because DiagnosticConsumer requires that 306 // diagnostics with source range information are emitted only in between 307 // BeginSourceFile() and EndSourceFile(). 308 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 309 310 // No macros will be added since we are just checking and we won't modify 311 // source code. 312 std::vector<SourceLocation> ARCMTMacroLocs; 313 314 TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 315 MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, 316 ARCMTMacroLocs); 317 pass.setNoFinalizeRemoval(NoFinalizeRemoval); 318 if (!NoNSAllocReallocError) 319 Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error, 320 SourceLocation()); 321 322 for (unsigned i=0, e = transforms.size(); i != e; ++i) 323 transforms[i](pass); 324 325 capturedDiags.reportDiagnostics(*Diags); 326 327 DiagClient->EndSourceFile(); 328 errRec.FinishCapture(); 329 330 return capturedDiags.hasErrors() || testAct.hasReportedErrors(); 331 } 332 333 //===----------------------------------------------------------------------===// 334 // applyTransformations. 335 //===----------------------------------------------------------------------===// 336 337 static bool 338 applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, 339 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 340 DiagnosticConsumer *DiagClient, StringRef outputDir, 341 bool emitPremigrationARCErrors, StringRef plistOut) { 342 if (!origCI.getLangOpts()->ObjC) 343 return false; 344 345 LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); 346 347 // Make sure checking is successful first. 348 CompilerInvocation CInvokForCheck(origCI); 349 if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps, 350 DiagClient, emitPremigrationARCErrors, 351 plistOut)) 352 return true; 353 354 CompilerInvocation CInvok(origCI); 355 CInvok.getFrontendOpts().Inputs.clear(); 356 CInvok.getFrontendOpts().Inputs.push_back(Input); 357 358 MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir); 359 bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; 360 361 std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, 362 NoFinalizeRemoval); 363 assert(!transforms.empty()); 364 365 for (unsigned i=0, e = transforms.size(); i != e; ++i) { 366 bool err = migration.applyTransform(transforms[i]); 367 if (err) return true; 368 } 369 370 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 371 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 372 new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), 373 DiagClient, /*ShouldOwnClient=*/false)); 374 375 if (outputDir.empty()) { 376 origCI.getLangOpts()->ObjCAutoRefCount = true; 377 return migration.getRemapper().overwriteOriginal(*Diags); 378 } else { 379 return migration.getRemapper().flushToDisk(outputDir, *Diags); 380 } 381 } 382 383 bool arcmt::applyTransformations( 384 CompilerInvocation &origCI, const FrontendInputFile &Input, 385 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 386 DiagnosticConsumer *DiagClient) { 387 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, 388 StringRef(), false, StringRef()); 389 } 390 391 bool arcmt::migrateWithTemporaryFiles( 392 CompilerInvocation &origCI, const FrontendInputFile &Input, 393 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 394 DiagnosticConsumer *DiagClient, StringRef outputDir, 395 bool emitPremigrationARCErrors, StringRef plistOut) { 396 assert(!outputDir.empty() && "Expected output directory path"); 397 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir, 398 emitPremigrationARCErrors, plistOut); 399 } 400 401 bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & 402 remap, 403 StringRef outputDir, 404 DiagnosticConsumer *DiagClient) { 405 assert(!outputDir.empty()); 406 407 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 408 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 409 new DiagnosticsEngine(DiagID, new DiagnosticOptions, 410 DiagClient, /*ShouldOwnClient=*/false)); 411 412 FileRemapper remapper; 413 bool err = remapper.initFromDisk(outputDir, *Diags, 414 /*ignoreIfFilesChanged=*/true); 415 if (err) 416 return true; 417 418 PreprocessorOptions PPOpts; 419 remapper.applyMappings(PPOpts); 420 remap = PPOpts.RemappedFiles; 421 422 return false; 423 } 424 425 426 //===----------------------------------------------------------------------===// 427 // CollectTransformActions. 428 //===----------------------------------------------------------------------===// 429 430 namespace { 431 432 class ARCMTMacroTrackerPPCallbacks : public PPCallbacks { 433 std::vector<SourceLocation> &ARCMTMacroLocs; 434 435 public: 436 ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) 437 : ARCMTMacroLocs(ARCMTMacroLocs) { } 438 439 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 440 SourceRange Range, const MacroArgs *Args) override { 441 if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) 442 ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); 443 } 444 }; 445 446 class ARCMTMacroTrackerAction : public ASTFrontendAction { 447 std::vector<SourceLocation> &ARCMTMacroLocs; 448 449 public: 450 ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) 451 : ARCMTMacroLocs(ARCMTMacroLocs) { } 452 453 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 454 StringRef InFile) override { 455 CI.getPreprocessor().addPPCallbacks( 456 std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs)); 457 return std::make_unique<ASTConsumer>(); 458 } 459 }; 460 461 class RewritesApplicator : public TransformActions::RewriteReceiver { 462 Rewriter &rewriter; 463 MigrationProcess::RewriteListener *Listener; 464 465 public: 466 RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, 467 MigrationProcess::RewriteListener *listener) 468 : rewriter(rewriter), Listener(listener) { 469 if (Listener) 470 Listener->start(ctx); 471 } 472 ~RewritesApplicator() override { 473 if (Listener) 474 Listener->finish(); 475 } 476 477 void insert(SourceLocation loc, StringRef text) override { 478 bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true, 479 /*indentNewLines=*/true); 480 if (!err && Listener) 481 Listener->insert(loc, text); 482 } 483 484 void remove(CharSourceRange range) override { 485 Rewriter::RewriteOptions removeOpts; 486 removeOpts.IncludeInsertsAtBeginOfRange = false; 487 removeOpts.IncludeInsertsAtEndOfRange = false; 488 removeOpts.RemoveLineIfEmpty = true; 489 490 bool err = rewriter.RemoveText(range, removeOpts); 491 if (!err && Listener) 492 Listener->remove(range); 493 } 494 495 void increaseIndentation(CharSourceRange range, 496 SourceLocation parentIndent) override { 497 rewriter.IncreaseIndentation(range, parentIndent); 498 } 499 }; 500 501 } // end anonymous namespace. 502 503 /// Anchor for VTable. 504 MigrationProcess::RewriteListener::~RewriteListener() { } 505 506 MigrationProcess::MigrationProcess( 507 const CompilerInvocation &CI, 508 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 509 DiagnosticConsumer *diagClient, StringRef outputDir) 510 : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)), 511 DiagClient(diagClient), HadARCErrors(false) { 512 if (!outputDir.empty()) { 513 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 514 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 515 new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), 516 DiagClient, /*ShouldOwnClient=*/false)); 517 Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanged=*/true); 518 } 519 } 520 521 bool MigrationProcess::applyTransform(TransformFn trans, 522 RewriteListener *listener) { 523 std::unique_ptr<CompilerInvocation> CInvok; 524 CInvok.reset( 525 createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader())); 526 CInvok->getDiagnosticOpts().IgnoreWarnings = true; 527 528 Remapper.applyMappings(CInvok->getPreprocessorOpts()); 529 530 CapturedDiagList capturedDiags; 531 std::vector<SourceLocation> ARCMTMacroLocs; 532 533 assert(DiagClient); 534 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 535 IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 536 new DiagnosticsEngine(DiagID, new DiagnosticOptions, 537 DiagClient, /*ShouldOwnClient=*/false)); 538 539 // Filter of all diagnostics. 540 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); 541 Diags->setClient(&errRec, /*ShouldOwnClient=*/false); 542 543 std::unique_ptr<ARCMTMacroTrackerAction> ASTAction; 544 ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); 545 546 std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( 547 std::move(CInvok), PCHContainerOps, Diags, ASTAction.get())); 548 if (!Unit) { 549 errRec.FinishCapture(); 550 return true; 551 } 552 Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that. 553 554 HadARCErrors = HadARCErrors || capturedDiags.hasErrors(); 555 556 // Don't filter diagnostics anymore. 557 Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); 558 559 ASTContext &Ctx = Unit->getASTContext(); 560 561 if (Diags->hasFatalErrorOccurred()) { 562 Diags->Reset(); 563 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 564 capturedDiags.reportDiagnostics(*Diags); 565 DiagClient->EndSourceFile(); 566 errRec.FinishCapture(); 567 return true; 568 } 569 570 // After parsing of source files ended, we want to reuse the 571 // diagnostics objects to emit further diagnostics. 572 // We call BeginSourceFile because DiagnosticConsumer requires that 573 // diagnostics with source range information are emitted only in between 574 // BeginSourceFile() and EndSourceFile(). 575 DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); 576 577 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 578 TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); 579 MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), 580 Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); 581 582 trans(pass); 583 584 { 585 RewritesApplicator applicator(rewriter, Ctx, listener); 586 TA.applyRewrites(applicator); 587 } 588 589 DiagClient->EndSourceFile(); 590 errRec.FinishCapture(); 591 592 if (DiagClient->getNumErrors()) 593 return true; 594 595 for (Rewriter::buffer_iterator 596 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 597 FileID FID = I->first; 598 RewriteBuffer &buf = I->second; 599 const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 600 assert(file); 601 std::string newFname = file->getName(); 602 newFname += "-trans"; 603 SmallString<512> newText; 604 llvm::raw_svector_ostream vecOS(newText); 605 buf.write(vecOS); 606 std::unique_ptr<llvm::MemoryBuffer> memBuf( 607 llvm::MemoryBuffer::getMemBufferCopy( 608 StringRef(newText.data(), newText.size()), newFname)); 609 SmallString<64> filePath(file->getName()); 610 Unit->getFileManager().FixupRelativePath(filePath); 611 Remapper.remap(filePath.str(), std::move(memBuf)); 612 } 613 614 return false; 615 } 616