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