ARCMT.cpp revision 360784
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>
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         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
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         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
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(true);
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  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
217static 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
236bool 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
337static bool
338applyTransforms(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
383bool 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
391bool 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
401bool 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
430namespace {
431
432class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
433  std::vector<SourceLocation> &ARCMTMacroLocs;
434
435public:
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
446class ARCMTMacroTrackerAction : public ASTFrontendAction {
447  std::vector<SourceLocation> &ARCMTMacroLocs;
448
449public:
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
461class RewritesApplicator : public TransformActions::RewriteReceiver {
462  Rewriter &rewriter;
463  MigrationProcess::RewriteListener *Listener;
464
465public:
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.
504MigrationProcess::RewriteListener::~RewriteListener() { }
505
506MigrationProcess::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
521bool 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