ARCMT.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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. #include "Internals.h"
  9. #include "clang/ARCMigrate/ARCMT.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>
  25. using namespace clang;
  26. using namespace arcmt;
  27. bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
  28. SourceRange range) {
  29. if (range.isInvalid())
  30. return false;
  31. bool cleared = false;
  32. ListTy::iterator I = List.begin();
  33. while (I != List.end()) {
  34. FullSourceLoc diagLoc = I->getLocation();
  35. if ((IDs.empty() || // empty means clear all diagnostics in the range.
  36. llvm::is_contained(IDs, I->getID())) &&
  37. !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
  38. (diagLoc == range.getEnd() ||
  39. diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
  40. cleared = true;
  41. ListTy::iterator eraseS = I++;
  42. if (eraseS->getLevel() != DiagnosticsEngine::Note)
  43. while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
  44. ++I;
  45. // Clear the diagnostic and any notes following it.
  46. I = List.erase(eraseS, I);
  47. continue;
  48. }
  49. ++I;
  50. }
  51. return cleared;
  52. }
  53. bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs,
  54. SourceRange range) const {
  55. if (range.isInvalid())
  56. return false;
  57. ListTy::const_iterator I = List.begin();
  58. while (I != List.end()) {
  59. FullSourceLoc diagLoc = I->getLocation();
  60. if ((IDs.empty() || // empty means any diagnostic in the range.
  61. llvm::is_contained(IDs, I->getID())) &&
  62. !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
  63. (diagLoc == range.getEnd() ||
  64. diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
  65. return true;
  66. }
  67. ++I;
  68. }
  69. return false;
  70. }
  71. void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const {
  72. for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
  73. Diags.Report(*I);
  74. }
  75. bool CapturedDiagList::hasErrors() const {
  76. for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
  77. if (I->getLevel() >= DiagnosticsEngine::Error)
  78. return true;
  79. return false;
  80. }
  81. namespace {
  82. class CaptureDiagnosticConsumer : public DiagnosticConsumer {
  83. DiagnosticsEngine &Diags;
  84. DiagnosticConsumer &DiagClient;
  85. CapturedDiagList &CapturedDiags;
  86. bool HasBegunSourceFile;
  87. public:
  88. CaptureDiagnosticConsumer(DiagnosticsEngine &diags,
  89. DiagnosticConsumer &client,
  90. CapturedDiagList &capturedDiags)
  91. : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
  92. HasBegunSourceFile(false) { }
  93. void BeginSourceFile(const LangOptions &Opts,
  94. const Preprocessor *PP) override {
  95. // Pass BeginSourceFile message onto DiagClient on first call.
  96. // The corresponding EndSourceFile call will be made from an
  97. // explicit call to FinishCapture.
  98. if (!HasBegunSourceFile) {
  99. DiagClient.BeginSourceFile(Opts, PP);
  100. HasBegunSourceFile = true;
  101. }
  102. }
  103. void FinishCapture() {
  104. // Call EndSourceFile on DiagClient on completion of capture to
  105. // enable VerifyDiagnosticConsumer to check diagnostics *after*
  106. // it has received the diagnostic list.
  107. if (HasBegunSourceFile) {
  108. DiagClient.EndSourceFile();
  109. HasBegunSourceFile = false;
  110. }
  111. }
  112. ~CaptureDiagnosticConsumer() override {
  113. assert(!HasBegunSourceFile && "FinishCapture not called!");
  114. }
  115. void HandleDiagnostic(DiagnosticsEngine::Level level,
  116. const Diagnostic &Info) override {
  117. if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
  118. level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
  119. if (Info.getLocation().isValid())
  120. CapturedDiags.push_back(StoredDiagnostic(level, Info));
  121. return;
  122. }
  123. // Non-ARC warnings are ignored.
  124. Diags.setLastDiagnosticIgnored(true);
  125. }
  126. };
  127. } // end anonymous namespace
  128. static bool HasARCRuntime(CompilerInvocation &origCI) {
  129. // This duplicates some functionality from Darwin::AddDeploymentTarget
  130. // but this function is well defined, so keep it decoupled from the driver
  131. // and avoid unrelated complications.
  132. llvm::Triple triple(origCI.getTargetOpts().Triple);
  133. if (triple.isiOS())
  134. return triple.getOSMajorVersion() >= 5;
  135. if (triple.isWatchOS())
  136. return true;
  137. if (triple.getOS() == llvm::Triple::Darwin)
  138. return triple.getOSMajorVersion() >= 11;
  139. if (triple.getOS() == llvm::Triple::MacOSX) {
  140. return triple.getOSVersion() >= VersionTuple(10, 7);
  141. }
  142. return false;
  143. }
  144. static CompilerInvocation *
  145. createInvocationForMigration(CompilerInvocation &origCI,
  146. const PCHContainerReader &PCHContainerRdr) {
  147. std::unique_ptr<CompilerInvocation> CInvok;
  148. CInvok.reset(new CompilerInvocation(origCI));
  149. PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
  150. if (!PPOpts.ImplicitPCHInclude.empty()) {
  151. // We can't use a PCH because it was likely built in non-ARC mode and we
  152. // want to parse in ARC. Include the original header.
  153. FileManager FileMgr(origCI.getFileSystemOpts());
  154. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  155. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  156. new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
  157. new IgnoringDiagConsumer()));
  158. std::string OriginalFile = ASTReader::getOriginalSourceFile(
  159. PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
  160. if (!OriginalFile.empty())
  161. PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
  162. PPOpts.ImplicitPCHInclude.clear();
  163. }
  164. std::string define = std::string(getARCMTMacroName());
  165. define += '=';
  166. CInvok->getPreprocessorOpts().addMacroDef(define);
  167. CInvok->getLangOpts()->ObjCAutoRefCount = true;
  168. CInvok->getLangOpts()->setGC(LangOptions::NonGC);
  169. CInvok->getDiagnosticOpts().ErrorLimit = 0;
  170. CInvok->getDiagnosticOpts().PedanticErrors = 0;
  171. // Ignore -Werror flags when migrating.
  172. std::vector<std::string> WarnOpts;
  173. for (std::vector<std::string>::iterator
  174. I = CInvok->getDiagnosticOpts().Warnings.begin(),
  175. E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
  176. if (!StringRef(*I).startswith("error"))
  177. WarnOpts.push_back(*I);
  178. }
  179. WarnOpts.push_back("error=arc-unsafe-retained-assign");
  180. CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
  181. CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI);
  182. CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime;
  183. return CInvok.release();
  184. }
  185. static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
  186. DiagnosticOptions *diagOpts,
  187. Preprocessor &PP) {
  188. TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
  189. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  190. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  191. new DiagnosticsEngine(DiagID, diagOpts, &printer,
  192. /*ShouldOwnClient=*/false));
  193. Diags->setSourceManager(&PP.getSourceManager());
  194. printer.BeginSourceFile(PP.getLangOpts(), &PP);
  195. arcDiags.reportDiagnostics(*Diags);
  196. printer.EndSourceFile();
  197. }
  198. //===----------------------------------------------------------------------===//
  199. // checkForManualIssues.
  200. //===----------------------------------------------------------------------===//
  201. bool arcmt::checkForManualIssues(
  202. CompilerInvocation &origCI, const FrontendInputFile &Input,
  203. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  204. DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
  205. StringRef plistOut) {
  206. if (!origCI.getLangOpts()->ObjC)
  207. return false;
  208. LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
  209. bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
  210. bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
  211. std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
  212. NoFinalizeRemoval);
  213. assert(!transforms.empty());
  214. std::unique_ptr<CompilerInvocation> CInvok;
  215. CInvok.reset(
  216. createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
  217. CInvok->getFrontendOpts().Inputs.clear();
  218. CInvok->getFrontendOpts().Inputs.push_back(Input);
  219. CapturedDiagList capturedDiags;
  220. assert(DiagClient);
  221. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  222. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  223. new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
  224. DiagClient, /*ShouldOwnClient=*/false));
  225. // Filter of all diagnostics.
  226. CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
  227. Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
  228. std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
  229. std::move(CInvok), PCHContainerOps, Diags));
  230. if (!Unit) {
  231. errRec.FinishCapture();
  232. return true;
  233. }
  234. // Don't filter diagnostics anymore.
  235. Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
  236. ASTContext &Ctx = Unit->getASTContext();
  237. if (Diags->hasFatalErrorOccurred()) {
  238. Diags->Reset();
  239. DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
  240. capturedDiags.reportDiagnostics(*Diags);
  241. DiagClient->EndSourceFile();
  242. errRec.FinishCapture();
  243. return true;
  244. }
  245. if (emitPremigrationARCErrors)
  246. emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(),
  247. Unit->getPreprocessor());
  248. if (!plistOut.empty()) {
  249. SmallVector<StoredDiagnostic, 8> arcDiags;
  250. for (CapturedDiagList::iterator
  251. I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
  252. arcDiags.push_back(*I);
  253. writeARCDiagsToPlist(std::string(plistOut), arcDiags,
  254. Ctx.getSourceManager(), Ctx.getLangOpts());
  255. }
  256. // After parsing of source files ended, we want to reuse the
  257. // diagnostics objects to emit further diagnostics.
  258. // We call BeginSourceFile because DiagnosticConsumer requires that
  259. // diagnostics with source range information are emitted only in between
  260. // BeginSourceFile() and EndSourceFile().
  261. DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
  262. // No macros will be added since we are just checking and we won't modify
  263. // source code.
  264. std::vector<SourceLocation> ARCMTMacroLocs;
  265. TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
  266. MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
  267. ARCMTMacroLocs);
  268. pass.setNoFinalizeRemoval(NoFinalizeRemoval);
  269. if (!NoNSAllocReallocError)
  270. Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
  271. SourceLocation());
  272. for (unsigned i=0, e = transforms.size(); i != e; ++i)
  273. transforms[i](pass);
  274. capturedDiags.reportDiagnostics(*Diags);
  275. DiagClient->EndSourceFile();
  276. errRec.FinishCapture();
  277. return capturedDiags.hasErrors() || testAct.hasReportedErrors();
  278. }
  279. //===----------------------------------------------------------------------===//
  280. // applyTransformations.
  281. //===----------------------------------------------------------------------===//
  282. static bool
  283. applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
  284. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  285. DiagnosticConsumer *DiagClient, StringRef outputDir,
  286. bool emitPremigrationARCErrors, StringRef plistOut) {
  287. if (!origCI.getLangOpts()->ObjC)
  288. return false;
  289. LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
  290. // Make sure checking is successful first.
  291. CompilerInvocation CInvokForCheck(origCI);
  292. if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
  293. DiagClient, emitPremigrationARCErrors,
  294. plistOut))
  295. return true;
  296. CompilerInvocation CInvok(origCI);
  297. CInvok.getFrontendOpts().Inputs.clear();
  298. CInvok.getFrontendOpts().Inputs.push_back(Input);
  299. MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
  300. bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
  301. std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
  302. NoFinalizeRemoval);
  303. assert(!transforms.empty());
  304. for (unsigned i=0, e = transforms.size(); i != e; ++i) {
  305. bool err = migration.applyTransform(transforms[i]);
  306. if (err) return true;
  307. }
  308. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  309. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  310. new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
  311. DiagClient, /*ShouldOwnClient=*/false));
  312. if (outputDir.empty()) {
  313. origCI.getLangOpts()->ObjCAutoRefCount = true;
  314. return migration.getRemapper().overwriteOriginal(*Diags);
  315. } else {
  316. return migration.getRemapper().flushToDisk(outputDir, *Diags);
  317. }
  318. }
  319. bool arcmt::applyTransformations(
  320. CompilerInvocation &origCI, const FrontendInputFile &Input,
  321. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  322. DiagnosticConsumer *DiagClient) {
  323. return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
  324. StringRef(), false, StringRef());
  325. }
  326. bool arcmt::migrateWithTemporaryFiles(
  327. CompilerInvocation &origCI, const FrontendInputFile &Input,
  328. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  329. DiagnosticConsumer *DiagClient, StringRef outputDir,
  330. bool emitPremigrationARCErrors, StringRef plistOut) {
  331. assert(!outputDir.empty() && "Expected output directory path");
  332. return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
  333. emitPremigrationARCErrors, plistOut);
  334. }
  335. bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
  336. remap,
  337. StringRef outputDir,
  338. DiagnosticConsumer *DiagClient) {
  339. assert(!outputDir.empty());
  340. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  341. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  342. new DiagnosticsEngine(DiagID, new DiagnosticOptions,
  343. DiagClient, /*ShouldOwnClient=*/false));
  344. FileRemapper remapper;
  345. bool err = remapper.initFromDisk(outputDir, *Diags,
  346. /*ignoreIfFilesChanged=*/true);
  347. if (err)
  348. return true;
  349. remapper.forEachMapping(
  350. [&](StringRef From, StringRef To) {
  351. remap.push_back(std::make_pair(From.str(), To.str()));
  352. },
  353. [](StringRef, const llvm::MemoryBufferRef &) {});
  354. return false;
  355. }
  356. //===----------------------------------------------------------------------===//
  357. // CollectTransformActions.
  358. //===----------------------------------------------------------------------===//
  359. namespace {
  360. class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
  361. std::vector<SourceLocation> &ARCMTMacroLocs;
  362. public:
  363. ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
  364. : ARCMTMacroLocs(ARCMTMacroLocs) { }
  365. void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
  366. SourceRange Range, const MacroArgs *Args) override {
  367. if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
  368. ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
  369. }
  370. };
  371. class ARCMTMacroTrackerAction : public ASTFrontendAction {
  372. std::vector<SourceLocation> &ARCMTMacroLocs;
  373. public:
  374. ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
  375. : ARCMTMacroLocs(ARCMTMacroLocs) { }
  376. std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
  377. StringRef InFile) override {
  378. CI.getPreprocessor().addPPCallbacks(
  379. std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
  380. return std::make_unique<ASTConsumer>();
  381. }
  382. };
  383. class RewritesApplicator : public TransformActions::RewriteReceiver {
  384. Rewriter &rewriter;
  385. MigrationProcess::RewriteListener *Listener;
  386. public:
  387. RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
  388. MigrationProcess::RewriteListener *listener)
  389. : rewriter(rewriter), Listener(listener) {
  390. if (Listener)
  391. Listener->start(ctx);
  392. }
  393. ~RewritesApplicator() override {
  394. if (Listener)
  395. Listener->finish();
  396. }
  397. void insert(SourceLocation loc, StringRef text) override {
  398. bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
  399. /*indentNewLines=*/true);
  400. if (!err && Listener)
  401. Listener->insert(loc, text);
  402. }
  403. void remove(CharSourceRange range) override {
  404. Rewriter::RewriteOptions removeOpts;
  405. removeOpts.IncludeInsertsAtBeginOfRange = false;
  406. removeOpts.IncludeInsertsAtEndOfRange = false;
  407. removeOpts.RemoveLineIfEmpty = true;
  408. bool err = rewriter.RemoveText(range, removeOpts);
  409. if (!err && Listener)
  410. Listener->remove(range);
  411. }
  412. void increaseIndentation(CharSourceRange range,
  413. SourceLocation parentIndent) override {
  414. rewriter.IncreaseIndentation(range, parentIndent);
  415. }
  416. };
  417. } // end anonymous namespace.
  418. /// Anchor for VTable.
  419. MigrationProcess::RewriteListener::~RewriteListener() { }
  420. MigrationProcess::MigrationProcess(
  421. const CompilerInvocation &CI,
  422. std::shared_ptr<PCHContainerOperations> PCHContainerOps,
  423. DiagnosticConsumer *diagClient, StringRef outputDir)
  424. : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
  425. DiagClient(diagClient), HadARCErrors(false) {
  426. if (!outputDir.empty()) {
  427. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  428. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  429. new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
  430. DiagClient, /*ShouldOwnClient=*/false));
  431. Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanged=*/true);
  432. }
  433. }
  434. bool MigrationProcess::applyTransform(TransformFn trans,
  435. RewriteListener *listener) {
  436. std::unique_ptr<CompilerInvocation> CInvok;
  437. CInvok.reset(
  438. createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
  439. CInvok->getDiagnosticOpts().IgnoreWarnings = true;
  440. Remapper.applyMappings(CInvok->getPreprocessorOpts());
  441. CapturedDiagList capturedDiags;
  442. std::vector<SourceLocation> ARCMTMacroLocs;
  443. assert(DiagClient);
  444. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  445. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  446. new DiagnosticsEngine(DiagID, new DiagnosticOptions,
  447. DiagClient, /*ShouldOwnClient=*/false));
  448. // Filter of all diagnostics.
  449. CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
  450. Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
  451. std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
  452. ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
  453. std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
  454. std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));
  455. if (!Unit) {
  456. errRec.FinishCapture();
  457. return true;
  458. }
  459. Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
  460. HadARCErrors = HadARCErrors || capturedDiags.hasErrors();
  461. // Don't filter diagnostics anymore.
  462. Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
  463. ASTContext &Ctx = Unit->getASTContext();
  464. if (Diags->hasFatalErrorOccurred()) {
  465. Diags->Reset();
  466. DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
  467. capturedDiags.reportDiagnostics(*Diags);
  468. DiagClient->EndSourceFile();
  469. errRec.FinishCapture();
  470. return true;
  471. }
  472. // After parsing of source files ended, we want to reuse the
  473. // diagnostics objects to emit further diagnostics.
  474. // We call BeginSourceFile because DiagnosticConsumer requires that
  475. // diagnostics with source range information are emitted only in between
  476. // BeginSourceFile() and EndSourceFile().
  477. DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor());
  478. Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
  479. TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
  480. MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
  481. Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
  482. trans(pass);
  483. {
  484. RewritesApplicator applicator(rewriter, Ctx, listener);
  485. TA.applyRewrites(applicator);
  486. }
  487. DiagClient->EndSourceFile();
  488. errRec.FinishCapture();
  489. if (DiagClient->getNumErrors())
  490. return true;
  491. for (Rewriter::buffer_iterator
  492. I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
  493. FileID FID = I->first;
  494. RewriteBuffer &buf = I->second;
  495. const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
  496. assert(file);
  497. std::string newFname = std::string(file->getName());
  498. newFname += "-trans";
  499. SmallString<512> newText;
  500. llvm::raw_svector_ostream vecOS(newText);
  501. buf.write(vecOS);
  502. std::unique_ptr<llvm::MemoryBuffer> memBuf(
  503. llvm::MemoryBuffer::getMemBufferCopy(
  504. StringRef(newText.data(), newText.size()), newFname));
  505. SmallString<64> filePath(file->getName());
  506. Unit->getFileManager().FixupRelativePath(filePath);
  507. Remapper.remap(filePath.str(), std::move(memBuf));
  508. }
  509. return false;
  510. }