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