aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-03-13 13:58:24 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-03-13 14:11:53 +0300
commit11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch)
treefabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp
parent9685917341315774aad5733b1793b1e533a88bbb (diff)
downloadydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp')
-rw-r--r--contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp616
1 files changed, 616 insertions, 0 deletions
diff --git a/contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp b/contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp
new file mode 100644
index 0000000000..68ee7c5927
--- /dev/null
+++ b/contrib/libs/clang16/lib/ARCMigrate/ARCMT.cpp
@@ -0,0 +1,616 @@
+//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Internals.h"
+#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/DiagnosticCategories.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <utility>
+using namespace clang;
+using namespace arcmt;
+
+bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
+ SourceRange range) {
+ if (range.isInvalid())
+ return false;
+
+ bool cleared = false;
+ ListTy::iterator I = List.begin();
+ while (I != List.end()) {
+ FullSourceLoc diagLoc = I->getLocation();
+ if ((IDs.empty() || // empty means clear all diagnostics in the range.
+ llvm::is_contained(IDs, I->getID())) &&
+ !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+ (diagLoc == range.getEnd() ||
+ diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+ cleared = true;
+ ListTy::iterator eraseS = I++;
+ if (eraseS->getLevel() != DiagnosticsEngine::Note)
+ while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
+ ++I;
+ // Clear the diagnostic and any notes following it.
+ I = List.erase(eraseS, I);
+ continue;
+ }
+
+ ++I;
+ }
+
+ return cleared;
+}
+
+bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
+ SourceRange range) const {
+ if (range.isInvalid())
+ return false;
+
+ ListTy::const_iterator I = List.begin();
+ while (I != List.end()) {
+ FullSourceLoc diagLoc = I->getLocation();
+ if ((IDs.empty() || // empty means any diagnostic in the range.
+ llvm::is_contained(IDs, I->getID())) &&
+ !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+ (diagLoc == range.getEnd() ||
+ diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+ return true;
+ }
+
+ ++I;
+ }
+
+ return false;
+}
+
+void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
+ for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
+ Diags.Report(*I);
+}
+
+bool CapturedDiagList::hasErrors() const {
+ for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
+ if (I->getLevel() >= DiagnosticsEngine::Error)
+ return true;
+
+ return false;
+}
+
+namespace {
+
+class CaptureDiagnosticConsumer : public DiagnosticConsumer {
+ DiagnosticsEngine &Diags;
+ DiagnosticConsumer &DiagClient;
+ CapturedDiagList &CapturedDiags;
+ bool HasBegunSourceFile;
+public:
+ CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
+ DiagnosticConsumer &client,
+ CapturedDiagList &capturedDiags)
+ : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
+ HasBegunSourceFile(false) { }
+
+ void BeginSourceFile(const LangOptions &Opts,
+ const Preprocessor *PP) override {
+ // Pass BeginSourceFile message onto DiagClient on first call.
+ // The corresponding EndSourceFile call will be made from an
+ // explicit call to FinishCapture.
+ if (!HasBegunSourceFile) {
+ DiagClient.BeginSourceFile(Opts, PP);
+ HasBegunSourceFile = true;
+ }
+ }
+
+ void FinishCapture() {
+ // Call EndSourceFile on DiagClient on completion of capture to
+ // enable VerifyDiagnosticConsumer to check diagnostics *after*
+ // it has received the diagnostic list.
+ if (HasBegunSourceFile) {
+ DiagClient.EndSourceFile();
+ HasBegunSourceFile = false;
+ }
+ }
+
+ ~CaptureDiagnosticConsumer() override {
+ assert(!HasBegunSourceFile && "FinishCapture not called!");
+ }
+
+ void HandleDiagnostic(DiagnosticsEngine::Level level,
+ const Diagnostic &Info) override {
+ if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
+ level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
+ if (Info.getLocation().isValid())
+ CapturedDiags.push_back(StoredDiagnostic(level, Info));
+ return;
+ }
+
+ // Non-ARC warnings are ignored.
+ Diags.setLastDiagnosticIgnored(true);
+ }
+};
+
+} // end anonymous namespace
+
+static bool HasARCRuntime(CompilerInvocation &origCI) {
+ // This duplicates some functionality from Darwin::AddDeploymentTarget
+ // but this function is well defined, so keep it decoupled from the driver
+ // and avoid unrelated complications.
+ llvm::Triple triple(origCI.getTargetOpts().Triple);
+
+ if (triple.isiOS())
+ return triple.getOSMajorVersion() >= 5;
+
+ if (triple.isWatchOS())
+ return true;
+
+ if (triple.getOS() == llvm::Triple::Darwin)
+ return triple.getOSMajorVersion() >= 11;
+
+ if (triple.getOS() == llvm::Triple::MacOSX) {
+ return triple.getOSVersion() >= VersionTuple(10, 7);
+ }
+
+ return false;
+}
+
+static CompilerInvocation *
+createInvocationForMigration(CompilerInvocation &origCI,
+ const PCHContainerReader &PCHContainerRdr) {
+ std::unique_ptr<CompilerInvocation> CInvok;
+ CInvok.reset(new CompilerInvocation(origCI));
+ PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
+ if (!PPOpts.ImplicitPCHInclude.empty()) {
+ // We can't use a PCH because it was likely built in non-ARC mode and we
+ // want to parse in ARC. Include the original header.
+ FileManager FileMgr(origCI.getFileSystemOpts());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ new IgnoringDiagConsumer()));
+ std::string OriginalFile = ASTReader::getOriginalSourceFile(
+ PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
+ if (!OriginalFile.empty())
+ PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
+ PPOpts.ImplicitPCHInclude.clear();
+ }
+ std::string define = std::string(getARCMTMacroName());
+ define += '=';
+ CInvok->getPreprocessorOpts().addMacroDef(define);
+ CInvok->getLangOpts()->ObjCAutoRefCount = true;
+ CInvok->getLangOpts()->setGC(LangOptions::NonGC);
+ CInvok->getDiagnosticOpts().ErrorLimit = 0;
+ CInvok->getDiagnosticOpts().PedanticErrors = 0;
+
+ // Ignore -Werror flags when migrating.
+ std::vector<std::string> WarnOpts;
+ for (std::vector<std::string>::iterator
+ I = CInvok->getDiagnosticOpts().Warnings.begin(),
+ E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
+ if (!StringRef(*I).startswith("error"))
+ WarnOpts.push_back(*I);
+ }
+ WarnOpts.push_back("error=arc-unsafe-retained-assign");
+ CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
+
+ CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI);
+ CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime;
+
+ return CInvok.release();
+}
+
+static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
+ DiagnosticOptions *diagOpts,
+ Preprocessor &PP) {
+ TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, diagOpts, &printer,
+ /*ShouldOwnClient=*/false));
+ Diags->setSourceManager(&PP.getSourceManager());
+
+ printer.BeginSourceFile(PP.getLangOpts(), &PP);
+ arcDiags.reportDiagnostics(*Diags);
+ printer.EndSourceFile();
+}
+
+//===----------------------------------------------------------------------===//
+// checkForManualIssues.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::checkForManualIssues(
+ CompilerInvocation &origCI, const FrontendInputFile &Input,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
+ StringRef plistOut) {
+ if (!origCI.getLangOpts()->ObjC)
+ return false;
+
+ LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
+ bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
+ bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
+
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
+ assert(!transforms.empty());
+
+ std::unique_ptr<CompilerInvocation> CInvok;
+ CInvok.reset(
+ createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
+ CInvok->getFrontendOpts().Inputs.clear();
+ CInvok->getFrontendOpts().Inputs.push_back(Input);
+
+ CapturedDiagList capturedDiags;
+
+ assert(DiagClient);
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
+
+ // Filter of all diagnostics.
+ CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
+ Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+ std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
+ std::move(CInvok), PCHContainerOps, Diags));
+ if (!Unit) {
+ errRec.FinishCapture();
+ return true;
+ }
+
+ // Don't filter diagnostics anymore.
+ Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
+
+ ASTContext &Ctx = Unit->getASTContext();
+
+ if (Diags->hasFatalErrorOccurred()) {
+ Diags->Reset();
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
+ capturedDiags.reportDiagnostics(*Diags);
+ DiagClient->EndSourceFile();
+ errRec.FinishCapture();
+ return true;
+ }
+
+ if (emitPremigrationARCErrors)
+ emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
+ Unit->getPreprocessor());
+ if (!plistOut.empty()) {
+ SmallVector<StoredDiagnostic, 8> arcDiags;
+ for (CapturedDiagList::iterator
+ I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
+ arcDiags.push_back(*I);
+ writeARCDiagsToPlist(std::string(plistOut), arcDiags,
+ Ctx.getSourceManager(), Ctx.getLangOpts());
+ }
+
+ // After parsing of source files ended, we want to reuse the
+ // diagnostics objects to emit further diagnostics.
+ // We call BeginSourceFile because DiagnosticConsumer requires that
+ // diagnostics with source range information are emitted only in between
+ // BeginSourceFile() and EndSourceFile().
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
+
+ // No macros will be added since we are just checking and we won't modify
+ // source code.
+ std::vector<SourceLocation> ARCMTMacroLocs;
+
+ TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
+ MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
+ ARCMTMacroLocs);
+ pass.setNoFinalizeRemoval(NoFinalizeRemoval);
+ if (!NoNSAllocReallocError)
+ Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
+ SourceLocation());
+
+ for (unsigned i=0, e = transforms.size(); i != e; ++i)
+ transforms[i](pass);
+
+ capturedDiags.reportDiagnostics(*Diags);
+
+ DiagClient->EndSourceFile();
+ errRec.FinishCapture();
+
+ return capturedDiags.hasErrors() || testAct.hasReportedErrors();
+}
+
+//===----------------------------------------------------------------------===//
+// applyTransformations.
+//===----------------------------------------------------------------------===//
+
+static bool
+applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagClient, StringRef outputDir,
+ bool emitPremigrationARCErrors, StringRef plistOut) {
+ if (!origCI.getLangOpts()->ObjC)
+ return false;
+
+ LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
+
+ // Make sure checking is successful first.
+ CompilerInvocation CInvokForCheck(origCI);
+ if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
+ DiagClient, emitPremigrationARCErrors,
+ plistOut))
+ return true;
+
+ CompilerInvocation CInvok(origCI);
+ CInvok.getFrontendOpts().Inputs.clear();
+ CInvok.getFrontendOpts().Inputs.push_back(Input);
+
+ MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
+ bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
+
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
+ assert(!transforms.empty());
+
+ for (unsigned i=0, e = transforms.size(); i != e; ++i) {
+ bool err = migration.applyTransform(transforms[i]);
+ if (err) return true;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
+
+ if (outputDir.empty()) {
+ origCI.getLangOpts()->ObjCAutoRefCount = true;
+ return migration.getRemapper().overwriteOriginal(*Diags);
+ } else {
+ return migration.getRemapper().flushToDisk(outputDir, *Diags);
+ }
+}
+
+bool arcmt::applyTransformations(
+ CompilerInvocation &origCI, const FrontendInputFile &Input,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagClient) {
+ return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
+ StringRef(), false, StringRef());
+}
+
+bool arcmt::migrateWithTemporaryFiles(
+ CompilerInvocation &origCI, const FrontendInputFile &Input,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagClient, StringRef outputDir,
+ bool emitPremigrationARCErrors, StringRef plistOut) {
+ assert(!outputDir.empty() && "Expected output directory path");
+ return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
+ emitPremigrationARCErrors, plistOut);
+}
+
+bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
+ remap,
+ StringRef outputDir,
+ DiagnosticConsumer *DiagClient) {
+ assert(!outputDir.empty());
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
+
+ FileRemapper remapper;
+ bool err = remapper.initFromDisk(outputDir, *Diags,
+ /*ignoreIfFilesChanged=*/true);
+ if (err)
+ return true;
+
+ remapper.forEachMapping(
+ [&](StringRef From, StringRef To) {
+ remap.push_back(std::make_pair(From.str(), To.str()));
+ },
+ [](StringRef, const llvm::MemoryBufferRef &) {});
+
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// CollectTransformActions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
+ std::vector<SourceLocation> &ARCMTMacroLocs;
+
+public:
+ ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
+ : ARCMTMacroLocs(ARCMTMacroLocs) { }
+
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range, const MacroArgs *Args) override {
+ if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
+ ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
+ }
+};
+
+class ARCMTMacroTrackerAction : public ASTFrontendAction {
+ std::vector<SourceLocation> &ARCMTMacroLocs;
+
+public:
+ ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
+ : ARCMTMacroLocs(ARCMTMacroLocs) { }
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
+ CI.getPreprocessor().addPPCallbacks(
+ std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
+ return std::make_unique<ASTConsumer>();
+ }
+};
+
+class RewritesApplicator : public TransformActions::RewriteReceiver {
+ Rewriter &rewriter;
+ MigrationProcess::RewriteListener *Listener;
+
+public:
+ RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
+ MigrationProcess::RewriteListener *listener)
+ : rewriter(rewriter), Listener(listener) {
+ if (Listener)
+ Listener->start(ctx);
+ }
+ ~RewritesApplicator() override {
+ if (Listener)
+ Listener->finish();
+ }
+
+ void insert(SourceLocation loc, StringRef text) override {
+ bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
+ /*indentNewLines=*/true);
+ if (!err && Listener)
+ Listener->insert(loc, text);
+ }
+
+ void remove(CharSourceRange range) override {
+ Rewriter::RewriteOptions removeOpts;
+ removeOpts.IncludeInsertsAtBeginOfRange = false;
+ removeOpts.IncludeInsertsAtEndOfRange = false;
+ removeOpts.RemoveLineIfEmpty = true;
+
+ bool err = rewriter.RemoveText(range, removeOpts);
+ if (!err && Listener)
+ Listener->remove(range);
+ }
+
+ void increaseIndentation(CharSourceRange range,
+ SourceLocation parentIndent) override {
+ rewriter.IncreaseIndentation(range, parentIndent);
+ }
+};
+
+} // end anonymous namespace.
+
+/// Anchor for VTable.
+MigrationProcess::RewriteListener::~RewriteListener() { }
+
+MigrationProcess::MigrationProcess(
+ const CompilerInvocation &CI,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *diagClient, StringRef outputDir)
+ : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
+ DiagClient(diagClient), HadARCErrors(false) {
+ if (!outputDir.empty()) {
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
+ DiagClient, /*ShouldOwnClient=*/false));
+ Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanged=*/true);
+ }
+}
+
+bool MigrationProcess::applyTransform(TransformFn trans,
+ RewriteListener *listener) {
+ std::unique_ptr<CompilerInvocation> CInvok;
+ CInvok.reset(
+ createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
+ CInvok->getDiagnosticOpts().IgnoreWarnings = true;
+
+ Remapper.applyMappings(CInvok->getPreprocessorOpts());
+
+ CapturedDiagList capturedDiags;
+ std::vector<SourceLocation> ARCMTMacroLocs;
+
+ assert(DiagClient);
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
+
+ // Filter of all diagnostics.
+ CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
+ Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+ std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
+ ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
+
+ std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
+ std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));
+ if (!Unit) {
+ errRec.FinishCapture();
+ return true;
+ }
+ Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
+
+ HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
+
+ // Don't filter diagnostics anymore.
+ Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
+
+ ASTContext &Ctx = Unit->getASTContext();
+
+ if (Diags->hasFatalErrorOccurred()) {
+ Diags->Reset();
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
+ capturedDiags.reportDiagnostics(*Diags);
+ DiagClient->EndSourceFile();
+ errRec.FinishCapture();
+ return true;
+ }
+
+ // After parsing of source files ended, we want to reuse the
+ // diagnostics objects to emit further diagnostics.
+ // We call BeginSourceFile because DiagnosticConsumer requires that
+ // diagnostics with source range information are emitted only in between
+ // BeginSourceFile() and EndSourceFile().
+ DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
+
+ Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
+ TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
+ MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
+ Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
+
+ trans(pass);
+
+ {
+ RewritesApplicator applicator(rewriter, Ctx, listener);
+ TA.applyRewrites(applicator);
+ }
+
+ DiagClient->EndSourceFile();
+ errRec.FinishCapture();
+
+ if (DiagClient->getNumErrors())
+ return true;
+
+ for (Rewriter::buffer_iterator
+ I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
+ FileID FID = I->first;
+ RewriteBuffer &buf = I->second;
+ const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
+ assert(file);
+ std::string newFname = std::string(file->getName());
+ newFname += "-trans";
+ SmallString<512> newText;
+ llvm::raw_svector_ostream vecOS(newText);
+ buf.write(vecOS);
+ std::unique_ptr<llvm::MemoryBuffer> memBuf(
+ llvm::MemoryBuffer::getMemBufferCopy(
+ StringRef(newText.data(), newText.size()), newFname));
+ SmallString<64> filePath(file->getName());
+ Unit->getFileManager().FixupRelativePath(filePath);
+ Remapper.remap(filePath.str(), std::move(memBuf));
+ }
+
+ return false;
+}