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