ARCMT.cpp 22 KB

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