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