xref: /aosp_15_r20/external/clang/lib/ARCMigrate/Transforms.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- Transforms.cpp - Transformations 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 "Transforms.h"
11*67e74705SXin Li #include "Internals.h"
12*67e74705SXin Li #include "clang/AST/ASTContext.h"
13*67e74705SXin Li #include "clang/AST/RecursiveASTVisitor.h"
14*67e74705SXin Li #include "clang/AST/StmtVisitor.h"
15*67e74705SXin Li #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16*67e74705SXin Li #include "clang/Basic/SourceManager.h"
17*67e74705SXin Li #include "clang/Basic/TargetInfo.h"
18*67e74705SXin Li #include "clang/Lex/Lexer.h"
19*67e74705SXin Li #include "clang/Lex/Preprocessor.h"
20*67e74705SXin Li #include "clang/Sema/Sema.h"
21*67e74705SXin Li #include "clang/Sema/SemaDiagnostic.h"
22*67e74705SXin Li #include "llvm/ADT/DenseSet.h"
23*67e74705SXin Li #include "llvm/ADT/StringSwitch.h"
24*67e74705SXin Li #include <map>
25*67e74705SXin Li 
26*67e74705SXin Li using namespace clang;
27*67e74705SXin Li using namespace arcmt;
28*67e74705SXin Li using namespace trans;
29*67e74705SXin Li 
~ASTTraverser()30*67e74705SXin Li ASTTraverser::~ASTTraverser() { }
31*67e74705SXin Li 
CFBridgingFunctionsDefined()32*67e74705SXin Li bool MigrationPass::CFBridgingFunctionsDefined() {
33*67e74705SXin Li   if (!EnableCFBridgeFns.hasValue())
34*67e74705SXin Li     EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
35*67e74705SXin Li                         SemaRef.isKnownName("CFBridgingRelease");
36*67e74705SXin Li   return *EnableCFBridgeFns;
37*67e74705SXin Li }
38*67e74705SXin Li 
39*67e74705SXin Li //===----------------------------------------------------------------------===//
40*67e74705SXin Li // Helpers.
41*67e74705SXin Li //===----------------------------------------------------------------------===//
42*67e74705SXin Li 
canApplyWeak(ASTContext & Ctx,QualType type,bool AllowOnUnknownClass)43*67e74705SXin Li bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
44*67e74705SXin Li                          bool AllowOnUnknownClass) {
45*67e74705SXin Li   if (!Ctx.getLangOpts().ObjCWeakRuntime)
46*67e74705SXin Li     return false;
47*67e74705SXin Li 
48*67e74705SXin Li   QualType T = type;
49*67e74705SXin Li   if (T.isNull())
50*67e74705SXin Li     return false;
51*67e74705SXin Li 
52*67e74705SXin Li   // iOS is always safe to use 'weak'.
53*67e74705SXin Li   if (Ctx.getTargetInfo().getTriple().isiOS() ||
54*67e74705SXin Li       Ctx.getTargetInfo().getTriple().isWatchOS())
55*67e74705SXin Li     AllowOnUnknownClass = true;
56*67e74705SXin Li 
57*67e74705SXin Li   while (const PointerType *ptr = T->getAs<PointerType>())
58*67e74705SXin Li     T = ptr->getPointeeType();
59*67e74705SXin Li   if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
60*67e74705SXin Li     ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
61*67e74705SXin Li     if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
62*67e74705SXin Li       return false; // id/NSObject is not safe for weak.
63*67e74705SXin Li     if (!AllowOnUnknownClass && !Class->hasDefinition())
64*67e74705SXin Li       return false; // forward classes are not verifiable, therefore not safe.
65*67e74705SXin Li     if (Class && Class->isArcWeakrefUnavailable())
66*67e74705SXin Li       return false;
67*67e74705SXin Li   }
68*67e74705SXin Li 
69*67e74705SXin Li   return true;
70*67e74705SXin Li }
71*67e74705SXin Li 
isPlusOneAssign(const BinaryOperator * E)72*67e74705SXin Li bool trans::isPlusOneAssign(const BinaryOperator *E) {
73*67e74705SXin Li   if (E->getOpcode() != BO_Assign)
74*67e74705SXin Li     return false;
75*67e74705SXin Li 
76*67e74705SXin Li   return isPlusOne(E->getRHS());
77*67e74705SXin Li }
78*67e74705SXin Li 
isPlusOne(const Expr * E)79*67e74705SXin Li bool trans::isPlusOne(const Expr *E) {
80*67e74705SXin Li   if (!E)
81*67e74705SXin Li     return false;
82*67e74705SXin Li   if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
83*67e74705SXin Li     E = EWC->getSubExpr();
84*67e74705SXin Li 
85*67e74705SXin Li   if (const ObjCMessageExpr *
86*67e74705SXin Li         ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
87*67e74705SXin Li     if (ME->getMethodFamily() == OMF_retain)
88*67e74705SXin Li       return true;
89*67e74705SXin Li 
90*67e74705SXin Li   if (const CallExpr *
91*67e74705SXin Li         callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
92*67e74705SXin Li     if (const FunctionDecl *FD = callE->getDirectCallee()) {
93*67e74705SXin Li       if (FD->hasAttr<CFReturnsRetainedAttr>())
94*67e74705SXin Li         return true;
95*67e74705SXin Li 
96*67e74705SXin Li       if (FD->isGlobal() &&
97*67e74705SXin Li           FD->getIdentifier() &&
98*67e74705SXin Li           FD->getParent()->isTranslationUnit() &&
99*67e74705SXin Li           FD->isExternallyVisible() &&
100*67e74705SXin Li           ento::cocoa::isRefType(callE->getType(), "CF",
101*67e74705SXin Li                                  FD->getIdentifier()->getName())) {
102*67e74705SXin Li         StringRef fname = FD->getIdentifier()->getName();
103*67e74705SXin Li         if (fname.endswith("Retain") ||
104*67e74705SXin Li             fname.find("Create") != StringRef::npos ||
105*67e74705SXin Li             fname.find("Copy") != StringRef::npos) {
106*67e74705SXin Li           return true;
107*67e74705SXin Li         }
108*67e74705SXin Li       }
109*67e74705SXin Li     }
110*67e74705SXin Li   }
111*67e74705SXin Li 
112*67e74705SXin Li   const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
113*67e74705SXin Li   while (implCE && implCE->getCastKind() ==  CK_BitCast)
114*67e74705SXin Li     implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
115*67e74705SXin Li 
116*67e74705SXin Li   return implCE && implCE->getCastKind() == CK_ARCConsumeObject;
117*67e74705SXin Li }
118*67e74705SXin Li 
119*67e74705SXin Li /// \brief 'Loc' is the end of a statement range. This returns the location
120*67e74705SXin Li /// immediately after the semicolon following the statement.
121*67e74705SXin Li /// If no semicolon is found or the location is inside a macro, the returned
122*67e74705SXin Li /// source location will be invalid.
findLocationAfterSemi(SourceLocation loc,ASTContext & Ctx,bool IsDecl)123*67e74705SXin Li SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
124*67e74705SXin Li                                             ASTContext &Ctx, bool IsDecl) {
125*67e74705SXin Li   SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
126*67e74705SXin Li   if (SemiLoc.isInvalid())
127*67e74705SXin Li     return SourceLocation();
128*67e74705SXin Li   return SemiLoc.getLocWithOffset(1);
129*67e74705SXin Li }
130*67e74705SXin Li 
131*67e74705SXin Li /// \brief \arg Loc is the end of a statement range. This returns the location
132*67e74705SXin Li /// of the semicolon following the statement.
133*67e74705SXin Li /// If no semicolon is found or the location is inside a macro, the returned
134*67e74705SXin Li /// source location will be invalid.
findSemiAfterLocation(SourceLocation loc,ASTContext & Ctx,bool IsDecl)135*67e74705SXin Li SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
136*67e74705SXin Li                                             ASTContext &Ctx,
137*67e74705SXin Li                                             bool IsDecl) {
138*67e74705SXin Li   SourceManager &SM = Ctx.getSourceManager();
139*67e74705SXin Li   if (loc.isMacroID()) {
140*67e74705SXin Li     if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
141*67e74705SXin Li       return SourceLocation();
142*67e74705SXin Li   }
143*67e74705SXin Li   loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
144*67e74705SXin Li 
145*67e74705SXin Li   // Break down the source location.
146*67e74705SXin Li   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
147*67e74705SXin Li 
148*67e74705SXin Li   // Try to load the file buffer.
149*67e74705SXin Li   bool invalidTemp = false;
150*67e74705SXin Li   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
151*67e74705SXin Li   if (invalidTemp)
152*67e74705SXin Li     return SourceLocation();
153*67e74705SXin Li 
154*67e74705SXin Li   const char *tokenBegin = file.data() + locInfo.second;
155*67e74705SXin Li 
156*67e74705SXin Li   // Lex from the start of the given location.
157*67e74705SXin Li   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
158*67e74705SXin Li               Ctx.getLangOpts(),
159*67e74705SXin Li               file.begin(), tokenBegin, file.end());
160*67e74705SXin Li   Token tok;
161*67e74705SXin Li   lexer.LexFromRawLexer(tok);
162*67e74705SXin Li   if (tok.isNot(tok::semi)) {
163*67e74705SXin Li     if (!IsDecl)
164*67e74705SXin Li       return SourceLocation();
165*67e74705SXin Li     // Declaration may be followed with other tokens; such as an __attribute,
166*67e74705SXin Li     // before ending with a semicolon.
167*67e74705SXin Li     return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
168*67e74705SXin Li   }
169*67e74705SXin Li 
170*67e74705SXin Li   return tok.getLocation();
171*67e74705SXin Li }
172*67e74705SXin Li 
hasSideEffects(Expr * E,ASTContext & Ctx)173*67e74705SXin Li bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
174*67e74705SXin Li   if (!E || !E->HasSideEffects(Ctx))
175*67e74705SXin Li     return false;
176*67e74705SXin Li 
177*67e74705SXin Li   E = E->IgnoreParenCasts();
178*67e74705SXin Li   ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
179*67e74705SXin Li   if (!ME)
180*67e74705SXin Li     return true;
181*67e74705SXin Li   switch (ME->getMethodFamily()) {
182*67e74705SXin Li   case OMF_autorelease:
183*67e74705SXin Li   case OMF_dealloc:
184*67e74705SXin Li   case OMF_release:
185*67e74705SXin Li   case OMF_retain:
186*67e74705SXin Li     switch (ME->getReceiverKind()) {
187*67e74705SXin Li     case ObjCMessageExpr::SuperInstance:
188*67e74705SXin Li       return false;
189*67e74705SXin Li     case ObjCMessageExpr::Instance:
190*67e74705SXin Li       return hasSideEffects(ME->getInstanceReceiver(), Ctx);
191*67e74705SXin Li     default:
192*67e74705SXin Li       break;
193*67e74705SXin Li     }
194*67e74705SXin Li     break;
195*67e74705SXin Li   default:
196*67e74705SXin Li     break;
197*67e74705SXin Li   }
198*67e74705SXin Li 
199*67e74705SXin Li   return true;
200*67e74705SXin Li }
201*67e74705SXin Li 
isGlobalVar(Expr * E)202*67e74705SXin Li bool trans::isGlobalVar(Expr *E) {
203*67e74705SXin Li   E = E->IgnoreParenCasts();
204*67e74705SXin Li   if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
205*67e74705SXin Li     return DRE->getDecl()->getDeclContext()->isFileContext() &&
206*67e74705SXin Li            DRE->getDecl()->isExternallyVisible();
207*67e74705SXin Li   if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
208*67e74705SXin Li     return isGlobalVar(condOp->getTrueExpr()) &&
209*67e74705SXin Li            isGlobalVar(condOp->getFalseExpr());
210*67e74705SXin Li 
211*67e74705SXin Li   return false;
212*67e74705SXin Li }
213*67e74705SXin Li 
getNilString(MigrationPass & Pass)214*67e74705SXin Li StringRef trans::getNilString(MigrationPass &Pass) {
215*67e74705SXin Li   return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0";
216*67e74705SXin Li }
217*67e74705SXin Li 
218*67e74705SXin Li namespace {
219*67e74705SXin Li 
220*67e74705SXin Li class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
221*67e74705SXin Li   ExprSet &Refs;
222*67e74705SXin Li public:
ReferenceClear(ExprSet & refs)223*67e74705SXin Li   ReferenceClear(ExprSet &refs) : Refs(refs) { }
VisitDeclRefExpr(DeclRefExpr * E)224*67e74705SXin Li   bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
225*67e74705SXin Li };
226*67e74705SXin Li 
227*67e74705SXin Li class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
228*67e74705SXin Li   ValueDecl *Dcl;
229*67e74705SXin Li   ExprSet &Refs;
230*67e74705SXin Li 
231*67e74705SXin Li public:
ReferenceCollector(ValueDecl * D,ExprSet & refs)232*67e74705SXin Li   ReferenceCollector(ValueDecl *D, ExprSet &refs)
233*67e74705SXin Li     : Dcl(D), Refs(refs) { }
234*67e74705SXin Li 
VisitDeclRefExpr(DeclRefExpr * E)235*67e74705SXin Li   bool VisitDeclRefExpr(DeclRefExpr *E) {
236*67e74705SXin Li     if (E->getDecl() == Dcl)
237*67e74705SXin Li       Refs.insert(E);
238*67e74705SXin Li     return true;
239*67e74705SXin Li   }
240*67e74705SXin Li };
241*67e74705SXin Li 
242*67e74705SXin Li class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
243*67e74705SXin Li   ExprSet &Removables;
244*67e74705SXin Li 
245*67e74705SXin Li public:
RemovablesCollector(ExprSet & removables)246*67e74705SXin Li   RemovablesCollector(ExprSet &removables)
247*67e74705SXin Li   : Removables(removables) { }
248*67e74705SXin Li 
shouldWalkTypesOfTypeLocs() const249*67e74705SXin Li   bool shouldWalkTypesOfTypeLocs() const { return false; }
250*67e74705SXin Li 
TraverseStmtExpr(StmtExpr * E)251*67e74705SXin Li   bool TraverseStmtExpr(StmtExpr *E) {
252*67e74705SXin Li     CompoundStmt *S = E->getSubStmt();
253*67e74705SXin Li     for (CompoundStmt::body_iterator
254*67e74705SXin Li         I = S->body_begin(), E = S->body_end(); I != E; ++I) {
255*67e74705SXin Li       if (I != E - 1)
256*67e74705SXin Li         mark(*I);
257*67e74705SXin Li       TraverseStmt(*I);
258*67e74705SXin Li     }
259*67e74705SXin Li     return true;
260*67e74705SXin Li   }
261*67e74705SXin Li 
VisitCompoundStmt(CompoundStmt * S)262*67e74705SXin Li   bool VisitCompoundStmt(CompoundStmt *S) {
263*67e74705SXin Li     for (auto *I : S->body())
264*67e74705SXin Li       mark(I);
265*67e74705SXin Li     return true;
266*67e74705SXin Li   }
267*67e74705SXin Li 
VisitIfStmt(IfStmt * S)268*67e74705SXin Li   bool VisitIfStmt(IfStmt *S) {
269*67e74705SXin Li     mark(S->getThen());
270*67e74705SXin Li     mark(S->getElse());
271*67e74705SXin Li     return true;
272*67e74705SXin Li   }
273*67e74705SXin Li 
VisitWhileStmt(WhileStmt * S)274*67e74705SXin Li   bool VisitWhileStmt(WhileStmt *S) {
275*67e74705SXin Li     mark(S->getBody());
276*67e74705SXin Li     return true;
277*67e74705SXin Li   }
278*67e74705SXin Li 
VisitDoStmt(DoStmt * S)279*67e74705SXin Li   bool VisitDoStmt(DoStmt *S) {
280*67e74705SXin Li     mark(S->getBody());
281*67e74705SXin Li     return true;
282*67e74705SXin Li   }
283*67e74705SXin Li 
VisitForStmt(ForStmt * S)284*67e74705SXin Li   bool VisitForStmt(ForStmt *S) {
285*67e74705SXin Li     mark(S->getInit());
286*67e74705SXin Li     mark(S->getInc());
287*67e74705SXin Li     mark(S->getBody());
288*67e74705SXin Li     return true;
289*67e74705SXin Li   }
290*67e74705SXin Li 
291*67e74705SXin Li private:
mark(Stmt * S)292*67e74705SXin Li   void mark(Stmt *S) {
293*67e74705SXin Li     if (!S) return;
294*67e74705SXin Li 
295*67e74705SXin Li     while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
296*67e74705SXin Li       S = Label->getSubStmt();
297*67e74705SXin Li     S = S->IgnoreImplicit();
298*67e74705SXin Li     if (Expr *E = dyn_cast<Expr>(S))
299*67e74705SXin Li       Removables.insert(E);
300*67e74705SXin Li   }
301*67e74705SXin Li };
302*67e74705SXin Li 
303*67e74705SXin Li } // end anonymous namespace
304*67e74705SXin Li 
clearRefsIn(Stmt * S,ExprSet & refs)305*67e74705SXin Li void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
306*67e74705SXin Li   ReferenceClear(refs).TraverseStmt(S);
307*67e74705SXin Li }
308*67e74705SXin Li 
collectRefs(ValueDecl * D,Stmt * S,ExprSet & refs)309*67e74705SXin Li void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
310*67e74705SXin Li   ReferenceCollector(D, refs).TraverseStmt(S);
311*67e74705SXin Li }
312*67e74705SXin Li 
collectRemovables(Stmt * S,ExprSet & exprs)313*67e74705SXin Li void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
314*67e74705SXin Li   RemovablesCollector(exprs).TraverseStmt(S);
315*67e74705SXin Li }
316*67e74705SXin Li 
317*67e74705SXin Li //===----------------------------------------------------------------------===//
318*67e74705SXin Li // MigrationContext
319*67e74705SXin Li //===----------------------------------------------------------------------===//
320*67e74705SXin Li 
321*67e74705SXin Li namespace {
322*67e74705SXin Li 
323*67e74705SXin Li class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
324*67e74705SXin Li   MigrationContext &MigrateCtx;
325*67e74705SXin Li   typedef RecursiveASTVisitor<ASTTransform> base;
326*67e74705SXin Li 
327*67e74705SXin Li public:
ASTTransform(MigrationContext & MigrateCtx)328*67e74705SXin Li   ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
329*67e74705SXin Li 
shouldWalkTypesOfTypeLocs() const330*67e74705SXin Li   bool shouldWalkTypesOfTypeLocs() const { return false; }
331*67e74705SXin Li 
TraverseObjCImplementationDecl(ObjCImplementationDecl * D)332*67e74705SXin Li   bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
333*67e74705SXin Li     ObjCImplementationContext ImplCtx(MigrateCtx, D);
334*67e74705SXin Li     for (MigrationContext::traverser_iterator
335*67e74705SXin Li            I = MigrateCtx.traversers_begin(),
336*67e74705SXin Li            E = MigrateCtx.traversers_end(); I != E; ++I)
337*67e74705SXin Li       (*I)->traverseObjCImplementation(ImplCtx);
338*67e74705SXin Li 
339*67e74705SXin Li     return base::TraverseObjCImplementationDecl(D);
340*67e74705SXin Li   }
341*67e74705SXin Li 
TraverseStmt(Stmt * rootS)342*67e74705SXin Li   bool TraverseStmt(Stmt *rootS) {
343*67e74705SXin Li     if (!rootS)
344*67e74705SXin Li       return true;
345*67e74705SXin Li 
346*67e74705SXin Li     BodyContext BodyCtx(MigrateCtx, rootS);
347*67e74705SXin Li     for (MigrationContext::traverser_iterator
348*67e74705SXin Li            I = MigrateCtx.traversers_begin(),
349*67e74705SXin Li            E = MigrateCtx.traversers_end(); I != E; ++I)
350*67e74705SXin Li       (*I)->traverseBody(BodyCtx);
351*67e74705SXin Li 
352*67e74705SXin Li     return true;
353*67e74705SXin Li   }
354*67e74705SXin Li };
355*67e74705SXin Li 
356*67e74705SXin Li }
357*67e74705SXin Li 
~MigrationContext()358*67e74705SXin Li MigrationContext::~MigrationContext() {
359*67e74705SXin Li   for (traverser_iterator
360*67e74705SXin Li          I = traversers_begin(), E = traversers_end(); I != E; ++I)
361*67e74705SXin Li     delete *I;
362*67e74705SXin Li }
363*67e74705SXin Li 
isGCOwnedNonObjC(QualType T)364*67e74705SXin Li bool MigrationContext::isGCOwnedNonObjC(QualType T) {
365*67e74705SXin Li   while (!T.isNull()) {
366*67e74705SXin Li     if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
367*67e74705SXin Li       if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
368*67e74705SXin Li         return !AttrT->getModifiedType()->isObjCRetainableType();
369*67e74705SXin Li     }
370*67e74705SXin Li 
371*67e74705SXin Li     if (T->isArrayType())
372*67e74705SXin Li       T = Pass.Ctx.getBaseElementType(T);
373*67e74705SXin Li     else if (const PointerType *PT = T->getAs<PointerType>())
374*67e74705SXin Li       T = PT->getPointeeType();
375*67e74705SXin Li     else if (const ReferenceType *RT = T->getAs<ReferenceType>())
376*67e74705SXin Li       T = RT->getPointeeType();
377*67e74705SXin Li     else
378*67e74705SXin Li       break;
379*67e74705SXin Li   }
380*67e74705SXin Li 
381*67e74705SXin Li   return false;
382*67e74705SXin Li }
383*67e74705SXin Li 
rewritePropertyAttribute(StringRef fromAttr,StringRef toAttr,SourceLocation atLoc)384*67e74705SXin Li bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
385*67e74705SXin Li                                                 StringRef toAttr,
386*67e74705SXin Li                                                 SourceLocation atLoc) {
387*67e74705SXin Li   if (atLoc.isMacroID())
388*67e74705SXin Li     return false;
389*67e74705SXin Li 
390*67e74705SXin Li   SourceManager &SM = Pass.Ctx.getSourceManager();
391*67e74705SXin Li 
392*67e74705SXin Li   // Break down the source location.
393*67e74705SXin Li   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
394*67e74705SXin Li 
395*67e74705SXin Li   // Try to load the file buffer.
396*67e74705SXin Li   bool invalidTemp = false;
397*67e74705SXin Li   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
398*67e74705SXin Li   if (invalidTemp)
399*67e74705SXin Li     return false;
400*67e74705SXin Li 
401*67e74705SXin Li   const char *tokenBegin = file.data() + locInfo.second;
402*67e74705SXin Li 
403*67e74705SXin Li   // Lex from the start of the given location.
404*67e74705SXin Li   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
405*67e74705SXin Li               Pass.Ctx.getLangOpts(),
406*67e74705SXin Li               file.begin(), tokenBegin, file.end());
407*67e74705SXin Li   Token tok;
408*67e74705SXin Li   lexer.LexFromRawLexer(tok);
409*67e74705SXin Li   if (tok.isNot(tok::at)) return false;
410*67e74705SXin Li   lexer.LexFromRawLexer(tok);
411*67e74705SXin Li   if (tok.isNot(tok::raw_identifier)) return false;
412*67e74705SXin Li   if (tok.getRawIdentifier() != "property")
413*67e74705SXin Li     return false;
414*67e74705SXin Li   lexer.LexFromRawLexer(tok);
415*67e74705SXin Li   if (tok.isNot(tok::l_paren)) return false;
416*67e74705SXin Li 
417*67e74705SXin Li   Token BeforeTok = tok;
418*67e74705SXin Li   Token AfterTok;
419*67e74705SXin Li   AfterTok.startToken();
420*67e74705SXin Li   SourceLocation AttrLoc;
421*67e74705SXin Li 
422*67e74705SXin Li   lexer.LexFromRawLexer(tok);
423*67e74705SXin Li   if (tok.is(tok::r_paren))
424*67e74705SXin Li     return false;
425*67e74705SXin Li 
426*67e74705SXin Li   while (1) {
427*67e74705SXin Li     if (tok.isNot(tok::raw_identifier)) return false;
428*67e74705SXin Li     if (tok.getRawIdentifier() == fromAttr) {
429*67e74705SXin Li       if (!toAttr.empty()) {
430*67e74705SXin Li         Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
431*67e74705SXin Li         return true;
432*67e74705SXin Li       }
433*67e74705SXin Li       // We want to remove the attribute.
434*67e74705SXin Li       AttrLoc = tok.getLocation();
435*67e74705SXin Li     }
436*67e74705SXin Li 
437*67e74705SXin Li     do {
438*67e74705SXin Li       lexer.LexFromRawLexer(tok);
439*67e74705SXin Li       if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
440*67e74705SXin Li         AfterTok = tok;
441*67e74705SXin Li     } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
442*67e74705SXin Li     if (tok.is(tok::r_paren))
443*67e74705SXin Li       break;
444*67e74705SXin Li     if (AttrLoc.isInvalid())
445*67e74705SXin Li       BeforeTok = tok;
446*67e74705SXin Li     lexer.LexFromRawLexer(tok);
447*67e74705SXin Li   }
448*67e74705SXin Li 
449*67e74705SXin Li   if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
450*67e74705SXin Li     // We want to remove the attribute.
451*67e74705SXin Li     if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
452*67e74705SXin Li       Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
453*67e74705SXin Li                                  AfterTok.getLocation()));
454*67e74705SXin Li     } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
455*67e74705SXin Li       Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
456*67e74705SXin Li     } else {
457*67e74705SXin Li       Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
458*67e74705SXin Li     }
459*67e74705SXin Li 
460*67e74705SXin Li     return true;
461*67e74705SXin Li   }
462*67e74705SXin Li 
463*67e74705SXin Li   return false;
464*67e74705SXin Li }
465*67e74705SXin Li 
addPropertyAttribute(StringRef attr,SourceLocation atLoc)466*67e74705SXin Li bool MigrationContext::addPropertyAttribute(StringRef attr,
467*67e74705SXin Li                                             SourceLocation atLoc) {
468*67e74705SXin Li   if (atLoc.isMacroID())
469*67e74705SXin Li     return false;
470*67e74705SXin Li 
471*67e74705SXin Li   SourceManager &SM = Pass.Ctx.getSourceManager();
472*67e74705SXin Li 
473*67e74705SXin Li   // Break down the source location.
474*67e74705SXin Li   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
475*67e74705SXin Li 
476*67e74705SXin Li   // Try to load the file buffer.
477*67e74705SXin Li   bool invalidTemp = false;
478*67e74705SXin Li   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
479*67e74705SXin Li   if (invalidTemp)
480*67e74705SXin Li     return false;
481*67e74705SXin Li 
482*67e74705SXin Li   const char *tokenBegin = file.data() + locInfo.second;
483*67e74705SXin Li 
484*67e74705SXin Li   // Lex from the start of the given location.
485*67e74705SXin Li   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
486*67e74705SXin Li               Pass.Ctx.getLangOpts(),
487*67e74705SXin Li               file.begin(), tokenBegin, file.end());
488*67e74705SXin Li   Token tok;
489*67e74705SXin Li   lexer.LexFromRawLexer(tok);
490*67e74705SXin Li   if (tok.isNot(tok::at)) return false;
491*67e74705SXin Li   lexer.LexFromRawLexer(tok);
492*67e74705SXin Li   if (tok.isNot(tok::raw_identifier)) return false;
493*67e74705SXin Li   if (tok.getRawIdentifier() != "property")
494*67e74705SXin Li     return false;
495*67e74705SXin Li   lexer.LexFromRawLexer(tok);
496*67e74705SXin Li 
497*67e74705SXin Li   if (tok.isNot(tok::l_paren)) {
498*67e74705SXin Li     Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
499*67e74705SXin Li     return true;
500*67e74705SXin Li   }
501*67e74705SXin Li 
502*67e74705SXin Li   lexer.LexFromRawLexer(tok);
503*67e74705SXin Li   if (tok.is(tok::r_paren)) {
504*67e74705SXin Li     Pass.TA.insert(tok.getLocation(), attr);
505*67e74705SXin Li     return true;
506*67e74705SXin Li   }
507*67e74705SXin Li 
508*67e74705SXin Li   if (tok.isNot(tok::raw_identifier)) return false;
509*67e74705SXin Li 
510*67e74705SXin Li   Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
511*67e74705SXin Li   return true;
512*67e74705SXin Li }
513*67e74705SXin Li 
traverse(TranslationUnitDecl * TU)514*67e74705SXin Li void MigrationContext::traverse(TranslationUnitDecl *TU) {
515*67e74705SXin Li   for (traverser_iterator
516*67e74705SXin Li          I = traversers_begin(), E = traversers_end(); I != E; ++I)
517*67e74705SXin Li     (*I)->traverseTU(*this);
518*67e74705SXin Li 
519*67e74705SXin Li   ASTTransform(*this).TraverseDecl(TU);
520*67e74705SXin Li }
521*67e74705SXin Li 
GCRewriteFinalize(MigrationPass & pass)522*67e74705SXin Li static void GCRewriteFinalize(MigrationPass &pass) {
523*67e74705SXin Li   ASTContext &Ctx = pass.Ctx;
524*67e74705SXin Li   TransformActions &TA = pass.TA;
525*67e74705SXin Li   DeclContext *DC = Ctx.getTranslationUnitDecl();
526*67e74705SXin Li   Selector FinalizeSel =
527*67e74705SXin Li    Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
528*67e74705SXin Li 
529*67e74705SXin Li   typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
530*67e74705SXin Li   impl_iterator;
531*67e74705SXin Li   for (impl_iterator I = impl_iterator(DC->decls_begin()),
532*67e74705SXin Li        E = impl_iterator(DC->decls_end()); I != E; ++I) {
533*67e74705SXin Li     for (const auto *MD : I->instance_methods()) {
534*67e74705SXin Li       if (!MD->hasBody())
535*67e74705SXin Li         continue;
536*67e74705SXin Li 
537*67e74705SXin Li       if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
538*67e74705SXin Li         const ObjCMethodDecl *FinalizeM = MD;
539*67e74705SXin Li         Transaction Trans(TA);
540*67e74705SXin Li         TA.insert(FinalizeM->getSourceRange().getBegin(),
541*67e74705SXin Li                   "#if !__has_feature(objc_arc)\n");
542*67e74705SXin Li         CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
543*67e74705SXin Li         const SourceManager &SM = pass.Ctx.getSourceManager();
544*67e74705SXin Li         const LangOptions &LangOpts = pass.Ctx.getLangOpts();
545*67e74705SXin Li         bool Invalid;
546*67e74705SXin Li         std::string str = "\n#endif\n";
547*67e74705SXin Li         str += Lexer::getSourceText(
548*67e74705SXin Li                   CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
549*67e74705SXin Li                                     SM, LangOpts, &Invalid);
550*67e74705SXin Li         TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
551*67e74705SXin Li 
552*67e74705SXin Li         break;
553*67e74705SXin Li       }
554*67e74705SXin Li     }
555*67e74705SXin Li   }
556*67e74705SXin Li }
557*67e74705SXin Li 
558*67e74705SXin Li //===----------------------------------------------------------------------===//
559*67e74705SXin Li // getAllTransformations.
560*67e74705SXin Li //===----------------------------------------------------------------------===//
561*67e74705SXin Li 
traverseAST(MigrationPass & pass)562*67e74705SXin Li static void traverseAST(MigrationPass &pass) {
563*67e74705SXin Li   MigrationContext MigrateCtx(pass);
564*67e74705SXin Li 
565*67e74705SXin Li   if (pass.isGCMigration()) {
566*67e74705SXin Li     MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
567*67e74705SXin Li     MigrateCtx.addTraverser(new GCAttrsTraverser());
568*67e74705SXin Li   }
569*67e74705SXin Li   MigrateCtx.addTraverser(new PropertyRewriteTraverser());
570*67e74705SXin Li   MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
571*67e74705SXin Li   MigrateCtx.addTraverser(new ProtectedScopeTraverser());
572*67e74705SXin Li 
573*67e74705SXin Li   MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
574*67e74705SXin Li }
575*67e74705SXin Li 
independentTransforms(MigrationPass & pass)576*67e74705SXin Li static void independentTransforms(MigrationPass &pass) {
577*67e74705SXin Li   rewriteAutoreleasePool(pass);
578*67e74705SXin Li   removeRetainReleaseDeallocFinalize(pass);
579*67e74705SXin Li   rewriteUnusedInitDelegate(pass);
580*67e74705SXin Li   removeZeroOutPropsInDeallocFinalize(pass);
581*67e74705SXin Li   makeAssignARCSafe(pass);
582*67e74705SXin Li   rewriteUnbridgedCasts(pass);
583*67e74705SXin Li   checkAPIUses(pass);
584*67e74705SXin Li   traverseAST(pass);
585*67e74705SXin Li }
586*67e74705SXin Li 
getAllTransformations(LangOptions::GCMode OrigGCMode,bool NoFinalizeRemoval)587*67e74705SXin Li std::vector<TransformFn> arcmt::getAllTransformations(
588*67e74705SXin Li                                                LangOptions::GCMode OrigGCMode,
589*67e74705SXin Li                                                bool NoFinalizeRemoval) {
590*67e74705SXin Li   std::vector<TransformFn> transforms;
591*67e74705SXin Li 
592*67e74705SXin Li   if (OrigGCMode ==  LangOptions::GCOnly && NoFinalizeRemoval)
593*67e74705SXin Li     transforms.push_back(GCRewriteFinalize);
594*67e74705SXin Li   transforms.push_back(independentTransforms);
595*67e74705SXin Li   // This depends on previous transformations removing various expressions.
596*67e74705SXin Li   transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
597*67e74705SXin Li 
598*67e74705SXin Li   return transforms;
599*67e74705SXin Li }
600