1 //===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "clang/ARCMigrate/ARCMT.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/Basic/DiagnosticCategories.h"
13 #include "clang/Frontend/ASTUnit.h"
14 #include "clang/Frontend/CompilerInstance.h"
15 #include "clang/Frontend/FrontendAction.h"
16 #include "clang/Frontend/TextDiagnosticPrinter.h"
17 #include "clang/Frontend/Utils.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "clang/Lex/PreprocessorOptions.h"
20 #include "clang/Rewrite/Core/Rewriter.h"
21 #include "clang/Sema/SemaDiagnostic.h"
22 #include "clang/Serialization/ASTReader.h"
23 #include "llvm/ADT/Triple.h"
24 #include "llvm/Support/MemoryBuffer.h"
26 using namespace clang
;
27 using namespace arcmt
;
29 bool CapturedDiagList::clearDiagnostic(ArrayRef
<unsigned> IDs
,
31 if (range
.isInvalid())
35 ListTy::iterator I
= List
.begin();
36 while (I
!= List
.end()) {
37 FullSourceLoc diagLoc
= I
->getLocation();
38 if ((IDs
.empty() || // empty means clear all diagnostics in the range.
39 llvm::is_contained(IDs
, I
->getID())) &&
40 !diagLoc
.isBeforeInTranslationUnitThan(range
.getBegin()) &&
41 (diagLoc
== range
.getEnd() ||
42 diagLoc
.isBeforeInTranslationUnitThan(range
.getEnd()))) {
44 ListTy::iterator eraseS
= I
++;
45 if (eraseS
->getLevel() != DiagnosticsEngine::Note
)
46 while (I
!= List
.end() && I
->getLevel() == DiagnosticsEngine::Note
)
48 // Clear the diagnostic and any notes following it.
49 I
= List
.erase(eraseS
, I
);
59 bool CapturedDiagList::hasDiagnostic(ArrayRef
<unsigned> IDs
,
60 SourceRange range
) const {
61 if (range
.isInvalid())
64 ListTy::const_iterator I
= List
.begin();
65 while (I
!= List
.end()) {
66 FullSourceLoc diagLoc
= I
->getLocation();
67 if ((IDs
.empty() || // empty means any diagnostic in the range.
68 llvm::is_contained(IDs
, I
->getID())) &&
69 !diagLoc
.isBeforeInTranslationUnitThan(range
.getBegin()) &&
70 (diagLoc
== range
.getEnd() ||
71 diagLoc
.isBeforeInTranslationUnitThan(range
.getEnd()))) {
81 void CapturedDiagList::reportDiagnostics(DiagnosticsEngine
&Diags
) const {
82 for (ListTy::const_iterator I
= List
.begin(), E
= List
.end(); I
!= E
; ++I
)
86 bool CapturedDiagList::hasErrors() const {
87 for (ListTy::const_iterator I
= List
.begin(), E
= List
.end(); I
!= E
; ++I
)
88 if (I
->getLevel() >= DiagnosticsEngine::Error
)
96 class CaptureDiagnosticConsumer
: public DiagnosticConsumer
{
97 DiagnosticsEngine
&Diags
;
98 DiagnosticConsumer
&DiagClient
;
99 CapturedDiagList
&CapturedDiags
;
100 bool HasBegunSourceFile
;
102 CaptureDiagnosticConsumer(DiagnosticsEngine
&diags
,
103 DiagnosticConsumer
&client
,
104 CapturedDiagList
&capturedDiags
)
105 : Diags(diags
), DiagClient(client
), CapturedDiags(capturedDiags
),
106 HasBegunSourceFile(false) { }
108 void BeginSourceFile(const LangOptions
&Opts
,
109 const Preprocessor
*PP
) override
{
110 // Pass BeginSourceFile message onto DiagClient on first call.
111 // The corresponding EndSourceFile call will be made from an
112 // explicit call to FinishCapture.
113 if (!HasBegunSourceFile
) {
114 DiagClient
.BeginSourceFile(Opts
, PP
);
115 HasBegunSourceFile
= true;
119 void FinishCapture() {
120 // Call EndSourceFile on DiagClient on completion of capture to
121 // enable VerifyDiagnosticConsumer to check diagnostics *after*
122 // it has received the diagnostic list.
123 if (HasBegunSourceFile
) {
124 DiagClient
.EndSourceFile();
125 HasBegunSourceFile
= false;
129 ~CaptureDiagnosticConsumer() override
{
130 assert(!HasBegunSourceFile
&& "FinishCapture not called!");
133 void HandleDiagnostic(DiagnosticsEngine::Level level
,
134 const Diagnostic
&Info
) override
{
135 if (DiagnosticIDs::isARCDiagnostic(Info
.getID()) ||
136 level
>= DiagnosticsEngine::Error
|| level
== DiagnosticsEngine::Note
) {
137 if (Info
.getLocation().isValid())
138 CapturedDiags
.push_back(StoredDiagnostic(level
, Info
));
142 // Non-ARC warnings are ignored.
143 Diags
.setLastDiagnosticIgnored(true);
147 } // end anonymous namespace
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 llvm::Triple
triple(origCI
.getTargetOpts().Triple
);
156 return triple
.getOSMajorVersion() >= 5;
158 if (triple
.isWatchOS())
161 if (triple
.getOS() == llvm::Triple::Darwin
)
162 return triple
.getOSMajorVersion() >= 11;
164 if (triple
.getOS() == llvm::Triple::MacOSX
) {
165 return triple
.getOSVersion() >= VersionTuple(10, 7);
171 static CompilerInvocation
*
172 createInvocationForMigration(CompilerInvocation
&origCI
,
173 const PCHContainerReader
&PCHContainerRdr
) {
174 std::unique_ptr
<CompilerInvocation
> CInvok
;
175 CInvok
.reset(new CompilerInvocation(origCI
));
176 PreprocessorOptions
&PPOpts
= CInvok
->getPreprocessorOpts();
177 if (!PPOpts
.ImplicitPCHInclude
.empty()) {
178 // We can't use a PCH because it was likely built in non-ARC mode and we
179 // want to parse in ARC. Include the original header.
180 FileManager
FileMgr(origCI
.getFileSystemOpts());
181 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
182 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
183 new DiagnosticsEngine(DiagID
, &origCI
.getDiagnosticOpts(),
184 new IgnoringDiagConsumer()));
185 std::string OriginalFile
= ASTReader::getOriginalSourceFile(
186 PPOpts
.ImplicitPCHInclude
, FileMgr
, PCHContainerRdr
, *Diags
);
187 if (!OriginalFile
.empty())
188 PPOpts
.Includes
.insert(PPOpts
.Includes
.begin(), OriginalFile
);
189 PPOpts
.ImplicitPCHInclude
.clear();
191 std::string define
= std::string(getARCMTMacroName());
193 CInvok
->getPreprocessorOpts().addMacroDef(define
);
194 CInvok
->getLangOpts()->ObjCAutoRefCount
= true;
195 CInvok
->getLangOpts()->setGC(LangOptions::NonGC
);
196 CInvok
->getDiagnosticOpts().ErrorLimit
= 0;
197 CInvok
->getDiagnosticOpts().PedanticErrors
= 0;
199 // Ignore -Werror flags when migrating.
200 std::vector
<std::string
> WarnOpts
;
201 for (std::vector
<std::string
>::iterator
202 I
= CInvok
->getDiagnosticOpts().Warnings
.begin(),
203 E
= CInvok
->getDiagnosticOpts().Warnings
.end(); I
!= E
; ++I
) {
204 if (!StringRef(*I
).startswith("error"))
205 WarnOpts
.push_back(*I
);
207 WarnOpts
.push_back("error=arc-unsafe-retained-assign");
208 CInvok
->getDiagnosticOpts().Warnings
= std::move(WarnOpts
);
210 CInvok
->getLangOpts()->ObjCWeakRuntime
= HasARCRuntime(origCI
);
211 CInvok
->getLangOpts()->ObjCWeak
= CInvok
->getLangOpts()->ObjCWeakRuntime
;
213 return CInvok
.release();
216 static void emitPremigrationErrors(const CapturedDiagList
&arcDiags
,
217 DiagnosticOptions
*diagOpts
,
219 TextDiagnosticPrinter
printer(llvm::errs(), diagOpts
);
220 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
221 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
222 new DiagnosticsEngine(DiagID
, diagOpts
, &printer
,
223 /*ShouldOwnClient=*/false));
224 Diags
->setSourceManager(&PP
.getSourceManager());
226 printer
.BeginSourceFile(PP
.getLangOpts(), &PP
);
227 arcDiags
.reportDiagnostics(*Diags
);
228 printer
.EndSourceFile();
231 //===----------------------------------------------------------------------===//
232 // checkForManualIssues.
233 //===----------------------------------------------------------------------===//
235 bool arcmt::checkForManualIssues(
236 CompilerInvocation
&origCI
, const FrontendInputFile
&Input
,
237 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
238 DiagnosticConsumer
*DiagClient
, bool emitPremigrationARCErrors
,
239 StringRef plistOut
) {
240 if (!origCI
.getLangOpts()->ObjC
)
243 LangOptions::GCMode OrigGCMode
= origCI
.getLangOpts()->getGC();
244 bool NoNSAllocReallocError
= origCI
.getMigratorOpts().NoNSAllocReallocError
;
245 bool NoFinalizeRemoval
= origCI
.getMigratorOpts().NoFinalizeRemoval
;
247 std::vector
<TransformFn
> transforms
= arcmt::getAllTransformations(OrigGCMode
,
249 assert(!transforms
.empty());
251 std::unique_ptr
<CompilerInvocation
> CInvok
;
253 createInvocationForMigration(origCI
, PCHContainerOps
->getRawReader()));
254 CInvok
->getFrontendOpts().Inputs
.clear();
255 CInvok
->getFrontendOpts().Inputs
.push_back(Input
);
257 CapturedDiagList capturedDiags
;
260 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
261 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
262 new DiagnosticsEngine(DiagID
, &origCI
.getDiagnosticOpts(),
263 DiagClient
, /*ShouldOwnClient=*/false));
265 // Filter of all diagnostics.
266 CaptureDiagnosticConsumer
errRec(*Diags
, *DiagClient
, capturedDiags
);
267 Diags
->setClient(&errRec
, /*ShouldOwnClient=*/false);
269 std::unique_ptr
<ASTUnit
> Unit(ASTUnit::LoadFromCompilerInvocationAction(
270 std::move(CInvok
), PCHContainerOps
, Diags
));
272 errRec
.FinishCapture();
276 // Don't filter diagnostics anymore.
277 Diags
->setClient(DiagClient
, /*ShouldOwnClient=*/false);
279 ASTContext
&Ctx
= Unit
->getASTContext();
281 if (Diags
->hasFatalErrorOccurred()) {
283 DiagClient
->BeginSourceFile(Ctx
.getLangOpts(), &Unit
->getPreprocessor());
284 capturedDiags
.reportDiagnostics(*Diags
);
285 DiagClient
->EndSourceFile();
286 errRec
.FinishCapture();
290 if (emitPremigrationARCErrors
)
291 emitPremigrationErrors(capturedDiags
, &origCI
.getDiagnosticOpts(),
292 Unit
->getPreprocessor());
293 if (!plistOut
.empty()) {
294 SmallVector
<StoredDiagnostic
, 8> arcDiags
;
295 for (CapturedDiagList::iterator
296 I
= capturedDiags
.begin(), E
= capturedDiags
.end(); I
!= E
; ++I
)
297 arcDiags
.push_back(*I
);
298 writeARCDiagsToPlist(std::string(plistOut
), arcDiags
,
299 Ctx
.getSourceManager(), Ctx
.getLangOpts());
302 // After parsing of source files ended, we want to reuse the
303 // diagnostics objects to emit further diagnostics.
304 // We call BeginSourceFile because DiagnosticConsumer requires that
305 // diagnostics with source range information are emitted only in between
306 // BeginSourceFile() and EndSourceFile().
307 DiagClient
->BeginSourceFile(Ctx
.getLangOpts(), &Unit
->getPreprocessor());
309 // No macros will be added since we are just checking and we won't modify
311 std::vector
<SourceLocation
> ARCMTMacroLocs
;
313 TransformActions
testAct(*Diags
, capturedDiags
, Ctx
, Unit
->getPreprocessor());
314 MigrationPass
pass(Ctx
, OrigGCMode
, Unit
->getSema(), testAct
, capturedDiags
,
316 pass
.setNoFinalizeRemoval(NoFinalizeRemoval
);
317 if (!NoNSAllocReallocError
)
318 Diags
->setSeverity(diag::warn_arcmt_nsalloc_realloc
, diag::Severity::Error
,
321 for (unsigned i
=0, e
= transforms
.size(); i
!= e
; ++i
)
324 capturedDiags
.reportDiagnostics(*Diags
);
326 DiagClient
->EndSourceFile();
327 errRec
.FinishCapture();
329 return capturedDiags
.hasErrors() || testAct
.hasReportedErrors();
332 //===----------------------------------------------------------------------===//
333 // applyTransformations.
334 //===----------------------------------------------------------------------===//
337 applyTransforms(CompilerInvocation
&origCI
, const FrontendInputFile
&Input
,
338 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
339 DiagnosticConsumer
*DiagClient
, StringRef outputDir
,
340 bool emitPremigrationARCErrors
, StringRef plistOut
) {
341 if (!origCI
.getLangOpts()->ObjC
)
344 LangOptions::GCMode OrigGCMode
= origCI
.getLangOpts()->getGC();
346 // Make sure checking is successful first.
347 CompilerInvocation
CInvokForCheck(origCI
);
348 if (arcmt::checkForManualIssues(CInvokForCheck
, Input
, PCHContainerOps
,
349 DiagClient
, emitPremigrationARCErrors
,
353 CompilerInvocation
CInvok(origCI
);
354 CInvok
.getFrontendOpts().Inputs
.clear();
355 CInvok
.getFrontendOpts().Inputs
.push_back(Input
);
357 MigrationProcess
migration(CInvok
, PCHContainerOps
, DiagClient
, outputDir
);
358 bool NoFinalizeRemoval
= origCI
.getMigratorOpts().NoFinalizeRemoval
;
360 std::vector
<TransformFn
> transforms
= arcmt::getAllTransformations(OrigGCMode
,
362 assert(!transforms
.empty());
364 for (unsigned i
=0, e
= transforms
.size(); i
!= e
; ++i
) {
365 bool err
= migration
.applyTransform(transforms
[i
]);
366 if (err
) return true;
369 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
370 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
371 new DiagnosticsEngine(DiagID
, &origCI
.getDiagnosticOpts(),
372 DiagClient
, /*ShouldOwnClient=*/false));
374 if (outputDir
.empty()) {
375 origCI
.getLangOpts()->ObjCAutoRefCount
= true;
376 return migration
.getRemapper().overwriteOriginal(*Diags
);
378 return migration
.getRemapper().flushToDisk(outputDir
, *Diags
);
382 bool arcmt::applyTransformations(
383 CompilerInvocation
&origCI
, const FrontendInputFile
&Input
,
384 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
385 DiagnosticConsumer
*DiagClient
) {
386 return applyTransforms(origCI
, Input
, PCHContainerOps
, DiagClient
,
387 StringRef(), false, StringRef());
390 bool arcmt::migrateWithTemporaryFiles(
391 CompilerInvocation
&origCI
, const FrontendInputFile
&Input
,
392 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
393 DiagnosticConsumer
*DiagClient
, StringRef outputDir
,
394 bool emitPremigrationARCErrors
, StringRef plistOut
) {
395 assert(!outputDir
.empty() && "Expected output directory path");
396 return applyTransforms(origCI
, Input
, PCHContainerOps
, DiagClient
, outputDir
,
397 emitPremigrationARCErrors
, plistOut
);
400 bool arcmt::getFileRemappings(std::vector
<std::pair
<std::string
,std::string
> > &
403 DiagnosticConsumer
*DiagClient
) {
404 assert(!outputDir
.empty());
406 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
407 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
408 new DiagnosticsEngine(DiagID
, new DiagnosticOptions
,
409 DiagClient
, /*ShouldOwnClient=*/false));
411 FileRemapper remapper
;
412 bool err
= remapper
.initFromDisk(outputDir
, *Diags
,
413 /*ignoreIfFilesChanged=*/true);
417 remapper
.forEachMapping(
418 [&](StringRef From
, StringRef To
) {
419 remap
.push_back(std::make_pair(From
.str(), To
.str()));
421 [](StringRef
, const llvm::MemoryBufferRef
&) {});
427 //===----------------------------------------------------------------------===//
428 // CollectTransformActions.
429 //===----------------------------------------------------------------------===//
433 class ARCMTMacroTrackerPPCallbacks
: public PPCallbacks
{
434 std::vector
<SourceLocation
> &ARCMTMacroLocs
;
437 ARCMTMacroTrackerPPCallbacks(std::vector
<SourceLocation
> &ARCMTMacroLocs
)
438 : ARCMTMacroLocs(ARCMTMacroLocs
) { }
440 void MacroExpands(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
441 SourceRange Range
, const MacroArgs
*Args
) override
{
442 if (MacroNameTok
.getIdentifierInfo()->getName() == getARCMTMacroName())
443 ARCMTMacroLocs
.push_back(MacroNameTok
.getLocation());
447 class ARCMTMacroTrackerAction
: public ASTFrontendAction
{
448 std::vector
<SourceLocation
> &ARCMTMacroLocs
;
451 ARCMTMacroTrackerAction(std::vector
<SourceLocation
> &ARCMTMacroLocs
)
452 : ARCMTMacroLocs(ARCMTMacroLocs
) { }
454 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
455 StringRef InFile
) override
{
456 CI
.getPreprocessor().addPPCallbacks(
457 std::make_unique
<ARCMTMacroTrackerPPCallbacks
>(ARCMTMacroLocs
));
458 return std::make_unique
<ASTConsumer
>();
462 class RewritesApplicator
: public TransformActions::RewriteReceiver
{
464 MigrationProcess::RewriteListener
*Listener
;
467 RewritesApplicator(Rewriter
&rewriter
, ASTContext
&ctx
,
468 MigrationProcess::RewriteListener
*listener
)
469 : rewriter(rewriter
), Listener(listener
) {
471 Listener
->start(ctx
);
473 ~RewritesApplicator() override
{
478 void insert(SourceLocation loc
, StringRef text
) override
{
479 bool err
= rewriter
.InsertText(loc
, text
, /*InsertAfter=*/true,
480 /*indentNewLines=*/true);
481 if (!err
&& Listener
)
482 Listener
->insert(loc
, text
);
485 void remove(CharSourceRange range
) override
{
486 Rewriter::RewriteOptions removeOpts
;
487 removeOpts
.IncludeInsertsAtBeginOfRange
= false;
488 removeOpts
.IncludeInsertsAtEndOfRange
= false;
489 removeOpts
.RemoveLineIfEmpty
= true;
491 bool err
= rewriter
.RemoveText(range
, removeOpts
);
492 if (!err
&& Listener
)
493 Listener
->remove(range
);
496 void increaseIndentation(CharSourceRange range
,
497 SourceLocation parentIndent
) override
{
498 rewriter
.IncreaseIndentation(range
, parentIndent
);
502 } // end anonymous namespace.
504 /// Anchor for VTable.
505 MigrationProcess::RewriteListener::~RewriteListener() { }
507 MigrationProcess::MigrationProcess(
508 const CompilerInvocation
&CI
,
509 std::shared_ptr
<PCHContainerOperations
> PCHContainerOps
,
510 DiagnosticConsumer
*diagClient
, StringRef outputDir
)
511 : OrigCI(CI
), PCHContainerOps(std::move(PCHContainerOps
)),
512 DiagClient(diagClient
), HadARCErrors(false) {
513 if (!outputDir
.empty()) {
514 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
515 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
516 new DiagnosticsEngine(DiagID
, &CI
.getDiagnosticOpts(),
517 DiagClient
, /*ShouldOwnClient=*/false));
518 Remapper
.initFromDisk(outputDir
, *Diags
, /*ignoreIfFilesChanged=*/true);
522 bool MigrationProcess::applyTransform(TransformFn trans
,
523 RewriteListener
*listener
) {
524 std::unique_ptr
<CompilerInvocation
> CInvok
;
526 createInvocationForMigration(OrigCI
, PCHContainerOps
->getRawReader()));
527 CInvok
->getDiagnosticOpts().IgnoreWarnings
= true;
529 Remapper
.applyMappings(CInvok
->getPreprocessorOpts());
531 CapturedDiagList capturedDiags
;
532 std::vector
<SourceLocation
> ARCMTMacroLocs
;
535 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID(new DiagnosticIDs());
536 IntrusiveRefCntPtr
<DiagnosticsEngine
> Diags(
537 new DiagnosticsEngine(DiagID
, new DiagnosticOptions
,
538 DiagClient
, /*ShouldOwnClient=*/false));
540 // Filter of all diagnostics.
541 CaptureDiagnosticConsumer
errRec(*Diags
, *DiagClient
, capturedDiags
);
542 Diags
->setClient(&errRec
, /*ShouldOwnClient=*/false);
544 std::unique_ptr
<ARCMTMacroTrackerAction
> ASTAction
;
545 ASTAction
.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs
));
547 std::unique_ptr
<ASTUnit
> Unit(ASTUnit::LoadFromCompilerInvocationAction(
548 std::move(CInvok
), PCHContainerOps
, Diags
, ASTAction
.get()));
550 errRec
.FinishCapture();
553 Unit
->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
555 HadARCErrors
= HadARCErrors
|| capturedDiags
.hasErrors();
557 // Don't filter diagnostics anymore.
558 Diags
->setClient(DiagClient
, /*ShouldOwnClient=*/false);
560 ASTContext
&Ctx
= Unit
->getASTContext();
562 if (Diags
->hasFatalErrorOccurred()) {
564 DiagClient
->BeginSourceFile(Ctx
.getLangOpts(), &Unit
->getPreprocessor());
565 capturedDiags
.reportDiagnostics(*Diags
);
566 DiagClient
->EndSourceFile();
567 errRec
.FinishCapture();
571 // After parsing of source files ended, we want to reuse the
572 // diagnostics objects to emit further diagnostics.
573 // We call BeginSourceFile because DiagnosticConsumer requires that
574 // diagnostics with source range information are emitted only in between
575 // BeginSourceFile() and EndSourceFile().
576 DiagClient
->BeginSourceFile(Ctx
.getLangOpts(), &Unit
->getPreprocessor());
578 Rewriter
rewriter(Ctx
.getSourceManager(), Ctx
.getLangOpts());
579 TransformActions
TA(*Diags
, capturedDiags
, Ctx
, Unit
->getPreprocessor());
580 MigrationPass
pass(Ctx
, OrigCI
.getLangOpts()->getGC(),
581 Unit
->getSema(), TA
, capturedDiags
, ARCMTMacroLocs
);
586 RewritesApplicator
applicator(rewriter
, Ctx
, listener
);
587 TA
.applyRewrites(applicator
);
590 DiagClient
->EndSourceFile();
591 errRec
.FinishCapture();
593 if (DiagClient
->getNumErrors())
596 for (Rewriter::buffer_iterator
597 I
= rewriter
.buffer_begin(), E
= rewriter
.buffer_end(); I
!= E
; ++I
) {
598 FileID FID
= I
->first
;
599 RewriteBuffer
&buf
= I
->second
;
600 const FileEntry
*file
= Ctx
.getSourceManager().getFileEntryForID(FID
);
602 std::string newFname
= std::string(file
->getName());
603 newFname
+= "-trans";
604 SmallString
<512> newText
;
605 llvm::raw_svector_ostream
vecOS(newText
);
607 std::unique_ptr
<llvm::MemoryBuffer
> memBuf(
608 llvm::MemoryBuffer::getMemBufferCopy(
609 StringRef(newText
.data(), newText
.size()), newFname
));
610 SmallString
<64> filePath(file
->getName());
611 Unit
->getFileManager().FixupRelativePath(filePath
);
612 Remapper
.remap(filePath
.str(), std::move(memBuf
));