ARCMT.cpp 22 KB

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