xref: /freebsd/contrib/llvm-project/clang/lib/ARCMigrate/ARCMT.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
95ffd83dbSDimitry Andric #include "clang/ARCMigrate/ARCMT.h"
1006c3fb27SDimitry Andric #include "Internals.h"
110b57cec5SDimitry Andric #include "clang/AST/ASTConsumer.h"
120b57cec5SDimitry Andric #include "clang/Basic/DiagnosticCategories.h"
130b57cec5SDimitry Andric #include "clang/Frontend/ASTUnit.h"
140b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
150b57cec5SDimitry Andric #include "clang/Frontend/FrontendAction.h"
160b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
170b57cec5SDimitry Andric #include "clang/Frontend/Utils.h"
180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
190b57cec5SDimitry Andric #include "clang/Lex/PreprocessorOptions.h"
200b57cec5SDimitry Andric #include "clang/Rewrite/Core/Rewriter.h"
210b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
220b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h"
230b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
2406c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
250b57cec5SDimitry Andric #include <utility>
260b57cec5SDimitry Andric using namespace clang;
270b57cec5SDimitry Andric using namespace arcmt;
280b57cec5SDimitry Andric 
clearDiagnostic(ArrayRef<unsigned> IDs,SourceRange range)290b57cec5SDimitry Andric bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
300b57cec5SDimitry Andric                                        SourceRange range) {
310b57cec5SDimitry Andric   if (range.isInvalid())
320b57cec5SDimitry Andric     return false;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   bool cleared = false;
350b57cec5SDimitry Andric   ListTy::iterator I = List.begin();
360b57cec5SDimitry Andric   while (I != List.end()) {
370b57cec5SDimitry Andric     FullSourceLoc diagLoc = I->getLocation();
380b57cec5SDimitry Andric     if ((IDs.empty() || // empty means clear all diagnostics in the range.
390b57cec5SDimitry Andric          llvm::is_contained(IDs, I->getID())) &&
400b57cec5SDimitry Andric         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
410b57cec5SDimitry Andric         (diagLoc == range.getEnd() ||
420b57cec5SDimitry Andric          diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
430b57cec5SDimitry Andric       cleared = true;
440b57cec5SDimitry Andric       ListTy::iterator eraseS = I++;
450b57cec5SDimitry Andric       if (eraseS->getLevel() != DiagnosticsEngine::Note)
460b57cec5SDimitry Andric         while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
470b57cec5SDimitry Andric           ++I;
480b57cec5SDimitry Andric       // Clear the diagnostic and any notes following it.
490b57cec5SDimitry Andric       I = List.erase(eraseS, I);
500b57cec5SDimitry Andric       continue;
510b57cec5SDimitry Andric     }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric     ++I;
540b57cec5SDimitry Andric   }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   return cleared;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
hasDiagnostic(ArrayRef<unsigned> IDs,SourceRange range) const590b57cec5SDimitry Andric bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
600b57cec5SDimitry Andric                                      SourceRange range) const {
610b57cec5SDimitry Andric   if (range.isInvalid())
620b57cec5SDimitry Andric     return false;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   ListTy::const_iterator I = List.begin();
650b57cec5SDimitry Andric   while (I != List.end()) {
660b57cec5SDimitry Andric     FullSourceLoc diagLoc = I->getLocation();
670b57cec5SDimitry Andric     if ((IDs.empty() || // empty means any diagnostic in the range.
68349cc55cSDimitry Andric          llvm::is_contained(IDs, I->getID())) &&
690b57cec5SDimitry Andric         !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
700b57cec5SDimitry Andric         (diagLoc == range.getEnd() ||
710b57cec5SDimitry Andric          diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
720b57cec5SDimitry Andric       return true;
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     ++I;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   return false;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
reportDiagnostics(DiagnosticsEngine & Diags) const810b57cec5SDimitry Andric void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
820b57cec5SDimitry Andric   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
830b57cec5SDimitry Andric     Diags.Report(*I);
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
hasErrors() const860b57cec5SDimitry Andric bool CapturedDiagList::hasErrors() const {
870b57cec5SDimitry Andric   for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
880b57cec5SDimitry Andric     if (I->getLevel() >= DiagnosticsEngine::Error)
890b57cec5SDimitry Andric       return true;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   return false;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric namespace {
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric class CaptureDiagnosticConsumer : public DiagnosticConsumer {
970b57cec5SDimitry Andric   DiagnosticsEngine &Diags;
980b57cec5SDimitry Andric   DiagnosticConsumer &DiagClient;
990b57cec5SDimitry Andric   CapturedDiagList &CapturedDiags;
1000b57cec5SDimitry Andric   bool HasBegunSourceFile;
1010b57cec5SDimitry Andric public:
CaptureDiagnosticConsumer(DiagnosticsEngine & diags,DiagnosticConsumer & client,CapturedDiagList & capturedDiags)1020b57cec5SDimitry Andric   CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
1030b57cec5SDimitry Andric                             DiagnosticConsumer &client,
1040b57cec5SDimitry Andric                             CapturedDiagList &capturedDiags)
1050b57cec5SDimitry Andric     : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
1060b57cec5SDimitry Andric       HasBegunSourceFile(false) { }
1070b57cec5SDimitry Andric 
BeginSourceFile(const LangOptions & Opts,const Preprocessor * PP)1080b57cec5SDimitry Andric   void BeginSourceFile(const LangOptions &Opts,
1090b57cec5SDimitry Andric                        const Preprocessor *PP) override {
1100b57cec5SDimitry Andric     // Pass BeginSourceFile message onto DiagClient on first call.
1110b57cec5SDimitry Andric     // The corresponding EndSourceFile call will be made from an
1120b57cec5SDimitry Andric     // explicit call to FinishCapture.
1130b57cec5SDimitry Andric     if (!HasBegunSourceFile) {
1140b57cec5SDimitry Andric       DiagClient.BeginSourceFile(Opts, PP);
1150b57cec5SDimitry Andric       HasBegunSourceFile = true;
1160b57cec5SDimitry Andric     }
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
FinishCapture()1190b57cec5SDimitry Andric   void FinishCapture() {
1200b57cec5SDimitry Andric     // Call EndSourceFile on DiagClient on completion of capture to
1210b57cec5SDimitry Andric     // enable VerifyDiagnosticConsumer to check diagnostics *after*
1220b57cec5SDimitry Andric     // it has received the diagnostic list.
1230b57cec5SDimitry Andric     if (HasBegunSourceFile) {
1240b57cec5SDimitry Andric       DiagClient.EndSourceFile();
1250b57cec5SDimitry Andric       HasBegunSourceFile = false;
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric 
~CaptureDiagnosticConsumer()1290b57cec5SDimitry Andric   ~CaptureDiagnosticConsumer() override {
1300b57cec5SDimitry Andric     assert(!HasBegunSourceFile && "FinishCapture not called!");
1310b57cec5SDimitry Andric   }
1320b57cec5SDimitry Andric 
HandleDiagnostic(DiagnosticsEngine::Level level,const Diagnostic & Info)1330b57cec5SDimitry Andric   void HandleDiagnostic(DiagnosticsEngine::Level level,
1340b57cec5SDimitry Andric                         const Diagnostic &Info) override {
1350b57cec5SDimitry Andric     if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
1360b57cec5SDimitry Andric         level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
1370b57cec5SDimitry Andric       if (Info.getLocation().isValid())
1380b57cec5SDimitry Andric         CapturedDiags.push_back(StoredDiagnostic(level, Info));
1390b57cec5SDimitry Andric       return;
1400b57cec5SDimitry Andric     }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     // Non-ARC warnings are ignored.
143a7dea167SDimitry Andric     Diags.setLastDiagnosticIgnored(true);
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric };
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric } // end anonymous namespace
1480b57cec5SDimitry Andric 
HasARCRuntime(CompilerInvocation & origCI)1490b57cec5SDimitry Andric static bool HasARCRuntime(CompilerInvocation &origCI) {
1500b57cec5SDimitry Andric   // This duplicates some functionality from Darwin::AddDeploymentTarget
1510b57cec5SDimitry Andric   // but this function is well defined, so keep it decoupled from the driver
1520b57cec5SDimitry Andric   // and avoid unrelated complications.
1530b57cec5SDimitry Andric   llvm::Triple triple(origCI.getTargetOpts().Triple);
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   if (triple.isiOS())
1560b57cec5SDimitry Andric     return triple.getOSMajorVersion() >= 5;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   if (triple.isWatchOS())
1590b57cec5SDimitry Andric     return true;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   if (triple.getOS() == llvm::Triple::Darwin)
1620b57cec5SDimitry Andric     return triple.getOSMajorVersion() >= 11;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   if (triple.getOS() == llvm::Triple::MacOSX) {
1650eae32dcSDimitry Andric     return triple.getOSVersion() >= VersionTuple(10, 7);
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   return false;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric static CompilerInvocation *
createInvocationForMigration(CompilerInvocation & origCI,const PCHContainerReader & PCHContainerRdr)1720b57cec5SDimitry Andric createInvocationForMigration(CompilerInvocation &origCI,
1730b57cec5SDimitry Andric                              const PCHContainerReader &PCHContainerRdr) {
1740b57cec5SDimitry Andric   std::unique_ptr<CompilerInvocation> CInvok;
1750b57cec5SDimitry Andric   CInvok.reset(new CompilerInvocation(origCI));
1760b57cec5SDimitry Andric   PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
1770b57cec5SDimitry Andric   if (!PPOpts.ImplicitPCHInclude.empty()) {
1780b57cec5SDimitry Andric     // We can't use a PCH because it was likely built in non-ARC mode and we
1790b57cec5SDimitry Andric     // want to parse in ARC. Include the original header.
1800b57cec5SDimitry Andric     FileManager FileMgr(origCI.getFileSystemOpts());
1810b57cec5SDimitry Andric     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
1820b57cec5SDimitry Andric     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
1830b57cec5SDimitry Andric         new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
1840b57cec5SDimitry Andric                               new IgnoringDiagConsumer()));
1850b57cec5SDimitry Andric     std::string OriginalFile = ASTReader::getOriginalSourceFile(
1860b57cec5SDimitry Andric         PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
1870b57cec5SDimitry Andric     if (!OriginalFile.empty())
1880b57cec5SDimitry Andric       PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
1890b57cec5SDimitry Andric     PPOpts.ImplicitPCHInclude.clear();
1900b57cec5SDimitry Andric   }
1915ffd83dbSDimitry Andric   std::string define = std::string(getARCMTMacroName());
1920b57cec5SDimitry Andric   define += '=';
1930b57cec5SDimitry Andric   CInvok->getPreprocessorOpts().addMacroDef(define);
1945f757f3fSDimitry Andric   CInvok->getLangOpts().ObjCAutoRefCount = true;
1955f757f3fSDimitry Andric   CInvok->getLangOpts().setGC(LangOptions::NonGC);
1960b57cec5SDimitry Andric   CInvok->getDiagnosticOpts().ErrorLimit = 0;
1970b57cec5SDimitry Andric   CInvok->getDiagnosticOpts().PedanticErrors = 0;
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   // Ignore -Werror flags when migrating.
2000b57cec5SDimitry Andric   std::vector<std::string> WarnOpts;
2010b57cec5SDimitry Andric   for (std::vector<std::string>::iterator
2020b57cec5SDimitry Andric          I = CInvok->getDiagnosticOpts().Warnings.begin(),
2030b57cec5SDimitry Andric          E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
2045f757f3fSDimitry Andric     if (!StringRef(*I).starts_with("error"))
2050b57cec5SDimitry Andric       WarnOpts.push_back(*I);
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric   WarnOpts.push_back("error=arc-unsafe-retained-assign");
2080b57cec5SDimitry Andric   CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
2090b57cec5SDimitry Andric 
2105f757f3fSDimitry Andric   CInvok->getLangOpts().ObjCWeakRuntime = HasARCRuntime(origCI);
2115f757f3fSDimitry Andric   CInvok->getLangOpts().ObjCWeak = CInvok->getLangOpts().ObjCWeakRuntime;
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   return CInvok.release();
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
emitPremigrationErrors(const CapturedDiagList & arcDiags,DiagnosticOptions * diagOpts,Preprocessor & PP)2160b57cec5SDimitry Andric static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
2170b57cec5SDimitry Andric                                    DiagnosticOptions *diagOpts,
2180b57cec5SDimitry Andric                                    Preprocessor &PP) {
2190b57cec5SDimitry Andric   TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
2200b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
2210b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
2220b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, diagOpts, &printer,
2230b57cec5SDimitry Andric                             /*ShouldOwnClient=*/false));
2240b57cec5SDimitry Andric   Diags->setSourceManager(&PP.getSourceManager());
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   printer.BeginSourceFile(PP.getLangOpts(), &PP);
2270b57cec5SDimitry Andric   arcDiags.reportDiagnostics(*Diags);
2280b57cec5SDimitry Andric   printer.EndSourceFile();
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2320b57cec5SDimitry Andric // checkForManualIssues.
2330b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2340b57cec5SDimitry Andric 
checkForManualIssues(CompilerInvocation & origCI,const FrontendInputFile & Input,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * DiagClient,bool emitPremigrationARCErrors,StringRef plistOut)2350b57cec5SDimitry Andric bool arcmt::checkForManualIssues(
2360b57cec5SDimitry Andric     CompilerInvocation &origCI, const FrontendInputFile &Input,
2370b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
2380b57cec5SDimitry Andric     DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
2390b57cec5SDimitry Andric     StringRef plistOut) {
2405f757f3fSDimitry Andric   if (!origCI.getLangOpts().ObjC)
2410b57cec5SDimitry Andric     return false;
2420b57cec5SDimitry Andric 
2435f757f3fSDimitry Andric   LangOptions::GCMode OrigGCMode = origCI.getLangOpts().getGC();
2440b57cec5SDimitry Andric   bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
2450b57cec5SDimitry Andric   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
2480b57cec5SDimitry Andric                                                                      NoFinalizeRemoval);
2490b57cec5SDimitry Andric   assert(!transforms.empty());
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   std::unique_ptr<CompilerInvocation> CInvok;
2520b57cec5SDimitry Andric   CInvok.reset(
2530b57cec5SDimitry Andric       createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
2540b57cec5SDimitry Andric   CInvok->getFrontendOpts().Inputs.clear();
2550b57cec5SDimitry Andric   CInvok->getFrontendOpts().Inputs.push_back(Input);
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   CapturedDiagList capturedDiags;
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   assert(DiagClient);
2600b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
2610b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
2620b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
2630b57cec5SDimitry Andric                             DiagClient, /*ShouldOwnClient=*/false));
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   // Filter of all diagnostics.
2660b57cec5SDimitry Andric   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
2670b57cec5SDimitry Andric   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
2700b57cec5SDimitry Andric       std::move(CInvok), PCHContainerOps, Diags));
2710b57cec5SDimitry Andric   if (!Unit) {
2720b57cec5SDimitry Andric     errRec.FinishCapture();
2730b57cec5SDimitry Andric     return true;
2740b57cec5SDimitry Andric   }
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   // Don't filter diagnostics anymore.
2770b57cec5SDimitry Andric   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   ASTContext &Ctx = Unit->getASTContext();
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   if (Diags->hasFatalErrorOccurred()) {
2820b57cec5SDimitry Andric     Diags->Reset();
2830b57cec5SDimitry Andric     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
2840b57cec5SDimitry Andric     capturedDiags.reportDiagnostics(*Diags);
2850b57cec5SDimitry Andric     DiagClient->EndSourceFile();
2860b57cec5SDimitry Andric     errRec.FinishCapture();
2870b57cec5SDimitry Andric     return true;
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   if (emitPremigrationARCErrors)
2910b57cec5SDimitry Andric     emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
2920b57cec5SDimitry Andric                            Unit->getPreprocessor());
2930b57cec5SDimitry Andric   if (!plistOut.empty()) {
2940b57cec5SDimitry Andric     SmallVector<StoredDiagnostic, 8> arcDiags;
2950b57cec5SDimitry Andric     for (CapturedDiagList::iterator
2960b57cec5SDimitry Andric            I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
2970b57cec5SDimitry Andric       arcDiags.push_back(*I);
2985ffd83dbSDimitry Andric     writeARCDiagsToPlist(std::string(plistOut), arcDiags,
2990b57cec5SDimitry Andric                          Ctx.getSourceManager(), Ctx.getLangOpts());
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   // After parsing of source files ended, we want to reuse the
3030b57cec5SDimitry Andric   // diagnostics objects to emit further diagnostics.
3040b57cec5SDimitry Andric   // We call BeginSourceFile because DiagnosticConsumer requires that
3050b57cec5SDimitry Andric   // diagnostics with source range information are emitted only in between
3060b57cec5SDimitry Andric   // BeginSourceFile() and EndSourceFile().
3070b57cec5SDimitry Andric   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   // No macros will be added since we are just checking and we won't modify
3100b57cec5SDimitry Andric   // source code.
3110b57cec5SDimitry Andric   std::vector<SourceLocation> ARCMTMacroLocs;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
3140b57cec5SDimitry Andric   MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
3150b57cec5SDimitry Andric                      ARCMTMacroLocs);
3160b57cec5SDimitry Andric   pass.setNoFinalizeRemoval(NoFinalizeRemoval);
3170b57cec5SDimitry Andric   if (!NoNSAllocReallocError)
3180b57cec5SDimitry Andric     Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
3190b57cec5SDimitry Andric                        SourceLocation());
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   for (unsigned i=0, e = transforms.size(); i != e; ++i)
3220b57cec5SDimitry Andric     transforms[i](pass);
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   capturedDiags.reportDiagnostics(*Diags);
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   DiagClient->EndSourceFile();
3270b57cec5SDimitry Andric   errRec.FinishCapture();
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   return capturedDiags.hasErrors() || testAct.hasReportedErrors();
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3330b57cec5SDimitry Andric // applyTransformations.
3340b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric static bool
applyTransforms(CompilerInvocation & origCI,const FrontendInputFile & Input,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * DiagClient,StringRef outputDir,bool emitPremigrationARCErrors,StringRef plistOut)3370b57cec5SDimitry Andric applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
3380b57cec5SDimitry Andric                 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
3390b57cec5SDimitry Andric                 DiagnosticConsumer *DiagClient, StringRef outputDir,
3400b57cec5SDimitry Andric                 bool emitPremigrationARCErrors, StringRef plistOut) {
3415f757f3fSDimitry Andric   if (!origCI.getLangOpts().ObjC)
3420b57cec5SDimitry Andric     return false;
3430b57cec5SDimitry Andric 
3445f757f3fSDimitry Andric   LangOptions::GCMode OrigGCMode = origCI.getLangOpts().getGC();
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   // Make sure checking is successful first.
3470b57cec5SDimitry Andric   CompilerInvocation CInvokForCheck(origCI);
3480b57cec5SDimitry Andric   if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
3490b57cec5SDimitry Andric                                   DiagClient, emitPremigrationARCErrors,
3500b57cec5SDimitry Andric                                   plistOut))
3510b57cec5SDimitry Andric     return true;
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   CompilerInvocation CInvok(origCI);
3540b57cec5SDimitry Andric   CInvok.getFrontendOpts().Inputs.clear();
3550b57cec5SDimitry Andric   CInvok.getFrontendOpts().Inputs.push_back(Input);
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
3580b57cec5SDimitry Andric   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
3610b57cec5SDimitry Andric                                                                      NoFinalizeRemoval);
3620b57cec5SDimitry Andric   assert(!transforms.empty());
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   for (unsigned i=0, e = transforms.size(); i != e; ++i) {
3650b57cec5SDimitry Andric     bool err = migration.applyTransform(transforms[i]);
3660b57cec5SDimitry Andric     if (err) return true;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
3700b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
3710b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
3720b57cec5SDimitry Andric                             DiagClient, /*ShouldOwnClient=*/false));
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   if (outputDir.empty()) {
3755f757f3fSDimitry Andric     origCI.getLangOpts().ObjCAutoRefCount = true;
3760b57cec5SDimitry Andric     return migration.getRemapper().overwriteOriginal(*Diags);
3770b57cec5SDimitry Andric   } else {
3780b57cec5SDimitry Andric     return migration.getRemapper().flushToDisk(outputDir, *Diags);
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric 
applyTransformations(CompilerInvocation & origCI,const FrontendInputFile & Input,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * DiagClient)3820b57cec5SDimitry Andric bool arcmt::applyTransformations(
3830b57cec5SDimitry Andric     CompilerInvocation &origCI, const FrontendInputFile &Input,
3840b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
3850b57cec5SDimitry Andric     DiagnosticConsumer *DiagClient) {
3860b57cec5SDimitry Andric   return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
3870b57cec5SDimitry Andric                          StringRef(), false, StringRef());
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric 
migrateWithTemporaryFiles(CompilerInvocation & origCI,const FrontendInputFile & Input,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * DiagClient,StringRef outputDir,bool emitPremigrationARCErrors,StringRef plistOut)3900b57cec5SDimitry Andric bool arcmt::migrateWithTemporaryFiles(
3910b57cec5SDimitry Andric     CompilerInvocation &origCI, const FrontendInputFile &Input,
3920b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
3930b57cec5SDimitry Andric     DiagnosticConsumer *DiagClient, StringRef outputDir,
3940b57cec5SDimitry Andric     bool emitPremigrationARCErrors, StringRef plistOut) {
3950b57cec5SDimitry Andric   assert(!outputDir.empty() && "Expected output directory path");
3960b57cec5SDimitry Andric   return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
3970b57cec5SDimitry Andric                          emitPremigrationARCErrors, plistOut);
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric 
getFileRemappings(std::vector<std::pair<std::string,std::string>> & remap,StringRef outputDir,DiagnosticConsumer * DiagClient)4000b57cec5SDimitry Andric bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
4010b57cec5SDimitry Andric                                   remap,
4020b57cec5SDimitry Andric                               StringRef outputDir,
4030b57cec5SDimitry Andric                               DiagnosticConsumer *DiagClient) {
4040b57cec5SDimitry Andric   assert(!outputDir.empty());
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
4070b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
4080b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
4090b57cec5SDimitry Andric                             DiagClient, /*ShouldOwnClient=*/false));
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   FileRemapper remapper;
4120b57cec5SDimitry Andric   bool err = remapper.initFromDisk(outputDir, *Diags,
4130b57cec5SDimitry Andric                                    /*ignoreIfFilesChanged=*/true);
4140b57cec5SDimitry Andric   if (err)
4150b57cec5SDimitry Andric     return true;
4160b57cec5SDimitry Andric 
417e8d8bef9SDimitry Andric   remapper.forEachMapping(
418e8d8bef9SDimitry Andric       [&](StringRef From, StringRef To) {
419e8d8bef9SDimitry Andric         remap.push_back(std::make_pair(From.str(), To.str()));
420e8d8bef9SDimitry Andric       },
421e8d8bef9SDimitry Andric       [](StringRef, const llvm::MemoryBufferRef &) {});
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   return false;
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4280b57cec5SDimitry Andric // CollectTransformActions.
4290b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric namespace {
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
4340b57cec5SDimitry Andric   std::vector<SourceLocation> &ARCMTMacroLocs;
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric public:
ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> & ARCMTMacroLocs)4370b57cec5SDimitry Andric   ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
4380b57cec5SDimitry Andric     : ARCMTMacroLocs(ARCMTMacroLocs) { }
4390b57cec5SDimitry Andric 
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange Range,const MacroArgs * Args)4400b57cec5SDimitry Andric   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
4410b57cec5SDimitry Andric                     SourceRange Range, const MacroArgs *Args) override {
4420b57cec5SDimitry Andric     if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
4430b57cec5SDimitry Andric       ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
4440b57cec5SDimitry Andric   }
4450b57cec5SDimitry Andric };
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric class ARCMTMacroTrackerAction : public ASTFrontendAction {
4480b57cec5SDimitry Andric   std::vector<SourceLocation> &ARCMTMacroLocs;
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric public:
ARCMTMacroTrackerAction(std::vector<SourceLocation> & ARCMTMacroLocs)4510b57cec5SDimitry Andric   ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
4520b57cec5SDimitry Andric     : ARCMTMacroLocs(ARCMTMacroLocs) { }
4530b57cec5SDimitry Andric 
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)4540b57cec5SDimitry Andric   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
4550b57cec5SDimitry Andric                                                  StringRef InFile) override {
4560b57cec5SDimitry Andric     CI.getPreprocessor().addPPCallbacks(
457a7dea167SDimitry Andric                std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
458a7dea167SDimitry Andric     return std::make_unique<ASTConsumer>();
4590b57cec5SDimitry Andric   }
4600b57cec5SDimitry Andric };
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric class RewritesApplicator : public TransformActions::RewriteReceiver {
4630b57cec5SDimitry Andric   Rewriter &rewriter;
4640b57cec5SDimitry Andric   MigrationProcess::RewriteListener *Listener;
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric public:
RewritesApplicator(Rewriter & rewriter,ASTContext & ctx,MigrationProcess::RewriteListener * listener)4670b57cec5SDimitry Andric   RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
4680b57cec5SDimitry Andric                      MigrationProcess::RewriteListener *listener)
4690b57cec5SDimitry Andric     : rewriter(rewriter), Listener(listener) {
4700b57cec5SDimitry Andric     if (Listener)
4710b57cec5SDimitry Andric       Listener->start(ctx);
4720b57cec5SDimitry Andric   }
~RewritesApplicator()4730b57cec5SDimitry Andric   ~RewritesApplicator() override {
4740b57cec5SDimitry Andric     if (Listener)
4750b57cec5SDimitry Andric       Listener->finish();
4760b57cec5SDimitry Andric   }
4770b57cec5SDimitry Andric 
insert(SourceLocation loc,StringRef text)4780b57cec5SDimitry Andric   void insert(SourceLocation loc, StringRef text) override {
4790b57cec5SDimitry Andric     bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
4800b57cec5SDimitry Andric                                    /*indentNewLines=*/true);
4810b57cec5SDimitry Andric     if (!err && Listener)
4820b57cec5SDimitry Andric       Listener->insert(loc, text);
4830b57cec5SDimitry Andric   }
4840b57cec5SDimitry Andric 
remove(CharSourceRange range)4850b57cec5SDimitry Andric   void remove(CharSourceRange range) override {
4860b57cec5SDimitry Andric     Rewriter::RewriteOptions removeOpts;
4870b57cec5SDimitry Andric     removeOpts.IncludeInsertsAtBeginOfRange = false;
4880b57cec5SDimitry Andric     removeOpts.IncludeInsertsAtEndOfRange = false;
4890b57cec5SDimitry Andric     removeOpts.RemoveLineIfEmpty = true;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric     bool err = rewriter.RemoveText(range, removeOpts);
4920b57cec5SDimitry Andric     if (!err && Listener)
4930b57cec5SDimitry Andric       Listener->remove(range);
4940b57cec5SDimitry Andric   }
4950b57cec5SDimitry Andric 
increaseIndentation(CharSourceRange range,SourceLocation parentIndent)4960b57cec5SDimitry Andric   void increaseIndentation(CharSourceRange range,
4970b57cec5SDimitry Andric                             SourceLocation parentIndent) override {
4980b57cec5SDimitry Andric     rewriter.IncreaseIndentation(range, parentIndent);
4990b57cec5SDimitry Andric   }
5000b57cec5SDimitry Andric };
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric } // end anonymous namespace.
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric /// Anchor for VTable.
~RewriteListener()5050b57cec5SDimitry Andric MigrationProcess::RewriteListener::~RewriteListener() { }
5060b57cec5SDimitry Andric 
MigrationProcess(CompilerInvocation & CI,std::shared_ptr<PCHContainerOperations> PCHContainerOps,DiagnosticConsumer * diagClient,StringRef outputDir)5070b57cec5SDimitry Andric MigrationProcess::MigrationProcess(
5085f757f3fSDimitry Andric     CompilerInvocation &CI,
5090b57cec5SDimitry Andric     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
5100b57cec5SDimitry Andric     DiagnosticConsumer *diagClient, StringRef outputDir)
5110b57cec5SDimitry Andric     : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
5120b57cec5SDimitry Andric       DiagClient(diagClient), HadARCErrors(false) {
5130b57cec5SDimitry Andric   if (!outputDir.empty()) {
5140b57cec5SDimitry Andric     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
5150b57cec5SDimitry Andric     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
5160b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
5170b57cec5SDimitry Andric                             DiagClient, /*ShouldOwnClient=*/false));
5180b57cec5SDimitry Andric     Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanged=*/true);
5190b57cec5SDimitry Andric   }
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric 
applyTransform(TransformFn trans,RewriteListener * listener)5220b57cec5SDimitry Andric bool MigrationProcess::applyTransform(TransformFn trans,
5230b57cec5SDimitry Andric                                       RewriteListener *listener) {
5240b57cec5SDimitry Andric   std::unique_ptr<CompilerInvocation> CInvok;
5250b57cec5SDimitry Andric   CInvok.reset(
5260b57cec5SDimitry Andric       createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
5270b57cec5SDimitry Andric   CInvok->getDiagnosticOpts().IgnoreWarnings = true;
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric   Remapper.applyMappings(CInvok->getPreprocessorOpts());
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric   CapturedDiagList capturedDiags;
5320b57cec5SDimitry Andric   std::vector<SourceLocation> ARCMTMacroLocs;
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   assert(DiagClient);
5350b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
5360b57cec5SDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
5370b57cec5SDimitry Andric       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
5380b57cec5SDimitry Andric                             DiagClient, /*ShouldOwnClient=*/false));
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   // Filter of all diagnostics.
5410b57cec5SDimitry Andric   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
5420b57cec5SDimitry Andric   Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
5450b57cec5SDimitry Andric   ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
5480b57cec5SDimitry Andric       std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));
5490b57cec5SDimitry Andric   if (!Unit) {
5500b57cec5SDimitry Andric     errRec.FinishCapture();
5510b57cec5SDimitry Andric     return true;
5520b57cec5SDimitry Andric   }
5530b57cec5SDimitry Andric   Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric   // Don't filter diagnostics anymore.
5580b57cec5SDimitry Andric   Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   ASTContext &Ctx = Unit->getASTContext();
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric   if (Diags->hasFatalErrorOccurred()) {
5630b57cec5SDimitry Andric     Diags->Reset();
5640b57cec5SDimitry Andric     DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
5650b57cec5SDimitry Andric     capturedDiags.reportDiagnostics(*Diags);
5660b57cec5SDimitry Andric     DiagClient->EndSourceFile();
5670b57cec5SDimitry Andric     errRec.FinishCapture();
5680b57cec5SDimitry Andric     return true;
5690b57cec5SDimitry Andric   }
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric   // After parsing of source files ended, we want to reuse the
5720b57cec5SDimitry Andric   // diagnostics objects to emit further diagnostics.
5730b57cec5SDimitry Andric   // We call BeginSourceFile because DiagnosticConsumer requires that
5740b57cec5SDimitry Andric   // diagnostics with source range information are emitted only in between
5750b57cec5SDimitry Andric   // BeginSourceFile() and EndSourceFile().
5760b57cec5SDimitry Andric   DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric   Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
5790b57cec5SDimitry Andric   TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
5805f757f3fSDimitry Andric   MigrationPass pass(Ctx, OrigCI.getLangOpts().getGC(),
5810b57cec5SDimitry Andric                      Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric   trans(pass);
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   {
5860b57cec5SDimitry Andric     RewritesApplicator applicator(rewriter, Ctx, listener);
5870b57cec5SDimitry Andric     TA.applyRewrites(applicator);
5880b57cec5SDimitry Andric   }
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric   DiagClient->EndSourceFile();
5910b57cec5SDimitry Andric   errRec.FinishCapture();
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric   if (DiagClient->getNumErrors())
5940b57cec5SDimitry Andric     return true;
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   for (Rewriter::buffer_iterator
5970b57cec5SDimitry Andric         I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
5980b57cec5SDimitry Andric     FileID FID = I->first;
5990b57cec5SDimitry Andric     RewriteBuffer &buf = I->second;
6005f757f3fSDimitry Andric     OptionalFileEntryRef file =
6015f757f3fSDimitry Andric         Ctx.getSourceManager().getFileEntryRefForID(FID);
6020b57cec5SDimitry Andric     assert(file);
6035ffd83dbSDimitry Andric     std::string newFname = std::string(file->getName());
6040b57cec5SDimitry Andric     newFname += "-trans";
6050b57cec5SDimitry Andric     SmallString<512> newText;
6060b57cec5SDimitry Andric     llvm::raw_svector_ostream vecOS(newText);
6070b57cec5SDimitry Andric     buf.write(vecOS);
6080b57cec5SDimitry Andric     std::unique_ptr<llvm::MemoryBuffer> memBuf(
609*0fca6ea1SDimitry Andric         llvm::MemoryBuffer::getMemBufferCopy(newText.str(), newFname));
6100b57cec5SDimitry Andric     SmallString<64> filePath(file->getName());
6110b57cec5SDimitry Andric     Unit->getFileManager().FixupRelativePath(filePath);
6120b57cec5SDimitry Andric     Remapper.remap(filePath.str(), std::move(memBuf));
6130b57cec5SDimitry Andric   }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric   return false;
6160b57cec5SDimitry Andric }
617