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