xref: /freebsd/contrib/llvm-project/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // rewriteUnbridgedCasts:
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
12*0b57cec5SDimitry Andric // is from a file-level variable, __bridge cast is used to convert it.
13*0b57cec5SDimitry Andric // For the result of a function call that we know is +1/+0,
14*0b57cec5SDimitry Andric // __bridge/CFBridgingRelease is used.
15*0b57cec5SDimitry Andric //
16*0b57cec5SDimitry Andric //  NSString *str = (NSString *)kUTTypePlainText;
17*0b57cec5SDimitry Andric //  str = b ? kUTTypeRTF : kUTTypePlainText;
18*0b57cec5SDimitry Andric //  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
19*0b57cec5SDimitry Andric //                                                         _uuid);
20*0b57cec5SDimitry Andric // ---->
21*0b57cec5SDimitry Andric //  NSString *str = (__bridge NSString *)kUTTypePlainText;
22*0b57cec5SDimitry Andric //  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
23*0b57cec5SDimitry Andric // NSString *_uuidString = (NSString *)
24*0b57cec5SDimitry Andric //            CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
25*0b57cec5SDimitry Andric //
26*0b57cec5SDimitry Andric // For a C pointer to ObjC, for casting 'self', __bridge is used.
27*0b57cec5SDimitry Andric //
28*0b57cec5SDimitry Andric //  CFStringRef str = (CFStringRef)self;
29*0b57cec5SDimitry Andric // ---->
30*0b57cec5SDimitry Andric //  CFStringRef str = (__bridge CFStringRef)self;
31*0b57cec5SDimitry Andric //
32*0b57cec5SDimitry Andric // Uses of Block_copy/Block_release macros are rewritten:
33*0b57cec5SDimitry Andric //
34*0b57cec5SDimitry Andric //  c = Block_copy(b);
35*0b57cec5SDimitry Andric //  Block_release(c);
36*0b57cec5SDimitry Andric // ---->
37*0b57cec5SDimitry Andric //  c = [b copy];
38*0b57cec5SDimitry Andric //  <removed>
39*0b57cec5SDimitry Andric //
40*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric #include "Transforms.h"
43*0b57cec5SDimitry Andric #include "Internals.h"
44*0b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
45*0b57cec5SDimitry Andric #include "clang/AST/Attr.h"
46*0b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
47*0b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
48*0b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
49*0b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
50*0b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
51*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric using namespace clang;
54*0b57cec5SDimitry Andric using namespace arcmt;
55*0b57cec5SDimitry Andric using namespace trans;
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric namespace {
58*0b57cec5SDimitry Andric 
59*0b57cec5SDimitry Andric class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
60*0b57cec5SDimitry Andric   MigrationPass &Pass;
61*0b57cec5SDimitry Andric   IdentifierInfo *SelfII;
62*0b57cec5SDimitry Andric   std::unique_ptr<ParentMap> StmtMap;
63*0b57cec5SDimitry Andric   Decl *ParentD;
64*0b57cec5SDimitry Andric   Stmt *Body;
65*0b57cec5SDimitry Andric   mutable std::unique_ptr<ExprSet> Removables;
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric public:
68*0b57cec5SDimitry Andric   UnbridgedCastRewriter(MigrationPass &pass)
69*0b57cec5SDimitry Andric     : Pass(pass), ParentD(nullptr), Body(nullptr) {
70*0b57cec5SDimitry Andric     SelfII = &Pass.Ctx.Idents.get("self");
71*0b57cec5SDimitry Andric   }
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   void transformBody(Stmt *body, Decl *ParentD) {
74*0b57cec5SDimitry Andric     this->ParentD = ParentD;
75*0b57cec5SDimitry Andric     Body = body;
76*0b57cec5SDimitry Andric     StmtMap.reset(new ParentMap(body));
77*0b57cec5SDimitry Andric     TraverseStmt(body);
78*0b57cec5SDimitry Andric   }
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   bool TraverseBlockDecl(BlockDecl *D) {
81*0b57cec5SDimitry Andric     // ParentMap does not enter into a BlockDecl to record its stmts, so use a
82*0b57cec5SDimitry Andric     // new UnbridgedCastRewriter to handle the block.
83*0b57cec5SDimitry Andric     UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
84*0b57cec5SDimitry Andric     return true;
85*0b57cec5SDimitry Andric   }
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric   bool VisitCastExpr(CastExpr *E) {
88*0b57cec5SDimitry Andric     if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
89*0b57cec5SDimitry Andric         E->getCastKind() != CK_BitCast &&
90*0b57cec5SDimitry Andric         E->getCastKind() != CK_AnyPointerToBlockPointerCast)
91*0b57cec5SDimitry Andric       return true;
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric     QualType castType = E->getType();
94*0b57cec5SDimitry Andric     Expr *castExpr = E->getSubExpr();
95*0b57cec5SDimitry Andric     QualType castExprType = castExpr->getType();
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric     if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
98*0b57cec5SDimitry Andric       return true;
99*0b57cec5SDimitry Andric 
100*0b57cec5SDimitry Andric     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
101*0b57cec5SDimitry Andric     bool castRetainable = castType->isObjCIndirectLifetimeType();
102*0b57cec5SDimitry Andric     if (exprRetainable == castRetainable) return true;
103*0b57cec5SDimitry Andric 
104*0b57cec5SDimitry Andric     if (castExpr->isNullPointerConstant(Pass.Ctx,
105*0b57cec5SDimitry Andric                                         Expr::NPC_ValueDependentIsNull))
106*0b57cec5SDimitry Andric       return true;
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric     SourceLocation loc = castExpr->getExprLoc();
109*0b57cec5SDimitry Andric     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
110*0b57cec5SDimitry Andric       return true;
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric     if (castType->isObjCRetainableType())
113*0b57cec5SDimitry Andric       transformNonObjCToObjCCast(E);
114*0b57cec5SDimitry Andric     else
115*0b57cec5SDimitry Andric       transformObjCToNonObjCCast(E);
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric     return true;
118*0b57cec5SDimitry Andric   }
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric private:
121*0b57cec5SDimitry Andric   void transformNonObjCToObjCCast(CastExpr *E) {
122*0b57cec5SDimitry Andric     if (!E) return;
123*0b57cec5SDimitry Andric 
124*0b57cec5SDimitry Andric     // Global vars are assumed that are cast as unretained.
125*0b57cec5SDimitry Andric     if (isGlobalVar(E))
126*0b57cec5SDimitry Andric       if (E->getSubExpr()->getType()->isPointerType()) {
127*0b57cec5SDimitry Andric         castToObjCObject(E, /*retained=*/false);
128*0b57cec5SDimitry Andric         return;
129*0b57cec5SDimitry Andric       }
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric     // If the cast is directly over the result of a Core Foundation function
132*0b57cec5SDimitry Andric     // try to figure out whether it should be cast as retained or unretained.
133*0b57cec5SDimitry Andric     Expr *inner = E->IgnoreParenCasts();
134*0b57cec5SDimitry Andric     if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
135*0b57cec5SDimitry Andric       if (FunctionDecl *FD = callE->getDirectCallee()) {
136*0b57cec5SDimitry Andric         if (FD->hasAttr<CFReturnsRetainedAttr>()) {
137*0b57cec5SDimitry Andric           castToObjCObject(E, /*retained=*/true);
138*0b57cec5SDimitry Andric           return;
139*0b57cec5SDimitry Andric         }
140*0b57cec5SDimitry Andric         if (FD->hasAttr<CFReturnsNotRetainedAttr>()) {
141*0b57cec5SDimitry Andric           castToObjCObject(E, /*retained=*/false);
142*0b57cec5SDimitry Andric           return;
143*0b57cec5SDimitry Andric         }
144*0b57cec5SDimitry Andric         if (FD->isGlobal() &&
145*0b57cec5SDimitry Andric             FD->getIdentifier() &&
146*0b57cec5SDimitry Andric             ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
147*0b57cec5SDimitry Andric                                    FD->getIdentifier()->getName())) {
148*0b57cec5SDimitry Andric           StringRef fname = FD->getIdentifier()->getName();
149*0b57cec5SDimitry Andric           if (fname.endswith("Retain") ||
150*0b57cec5SDimitry Andric               fname.find("Create") != StringRef::npos ||
151*0b57cec5SDimitry Andric               fname.find("Copy") != StringRef::npos) {
152*0b57cec5SDimitry Andric             // Do not migrate to couple of bridge transfer casts which
153*0b57cec5SDimitry Andric             // cancel each other out. Leave it unchanged so error gets user
154*0b57cec5SDimitry Andric             // attention instead.
155*0b57cec5SDimitry Andric             if (FD->getName() == "CFRetain" &&
156*0b57cec5SDimitry Andric                 FD->getNumParams() == 1 &&
157*0b57cec5SDimitry Andric                 FD->getParent()->isTranslationUnit() &&
158*0b57cec5SDimitry Andric                 FD->isExternallyVisible()) {
159*0b57cec5SDimitry Andric               Expr *Arg = callE->getArg(0);
160*0b57cec5SDimitry Andric               if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
161*0b57cec5SDimitry Andric                 const Expr *sub = ICE->getSubExpr();
162*0b57cec5SDimitry Andric                 QualType T = sub->getType();
163*0b57cec5SDimitry Andric                 if (T->isObjCObjectPointerType())
164*0b57cec5SDimitry Andric                   return;
165*0b57cec5SDimitry Andric               }
166*0b57cec5SDimitry Andric             }
167*0b57cec5SDimitry Andric             castToObjCObject(E, /*retained=*/true);
168*0b57cec5SDimitry Andric             return;
169*0b57cec5SDimitry Andric           }
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric           if (fname.find("Get") != StringRef::npos) {
172*0b57cec5SDimitry Andric             castToObjCObject(E, /*retained=*/false);
173*0b57cec5SDimitry Andric             return;
174*0b57cec5SDimitry Andric           }
175*0b57cec5SDimitry Andric         }
176*0b57cec5SDimitry Andric       }
177*0b57cec5SDimitry Andric     }
178*0b57cec5SDimitry Andric 
179*0b57cec5SDimitry Andric     // If returning an ivar or a member of an ivar from a +0 method, use
180*0b57cec5SDimitry Andric     // a __bridge cast.
181*0b57cec5SDimitry Andric     Expr *base = inner->IgnoreParenImpCasts();
182*0b57cec5SDimitry Andric     while (isa<MemberExpr>(base))
183*0b57cec5SDimitry Andric       base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
184*0b57cec5SDimitry Andric     if (isa<ObjCIvarRefExpr>(base) &&
185*0b57cec5SDimitry Andric         isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
186*0b57cec5SDimitry Andric       if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
187*0b57cec5SDimitry Andric         if (!method->hasAttr<NSReturnsRetainedAttr>()) {
188*0b57cec5SDimitry Andric           castToObjCObject(E, /*retained=*/false);
189*0b57cec5SDimitry Andric           return;
190*0b57cec5SDimitry Andric         }
191*0b57cec5SDimitry Andric       }
192*0b57cec5SDimitry Andric     }
193*0b57cec5SDimitry Andric   }
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric   void castToObjCObject(CastExpr *E, bool retained) {
196*0b57cec5SDimitry Andric     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
197*0b57cec5SDimitry Andric   }
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
200*0b57cec5SDimitry Andric     Transaction Trans(Pass.TA);
201*0b57cec5SDimitry Andric     rewriteToBridgedCast(E, Kind, Trans);
202*0b57cec5SDimitry Andric   }
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
205*0b57cec5SDimitry Andric                             Transaction &Trans) {
206*0b57cec5SDimitry Andric     TransformActions &TA = Pass.TA;
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric     // We will remove the compiler diagnostic.
209*0b57cec5SDimitry Andric     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
210*0b57cec5SDimitry Andric                           diag::err_arc_cast_requires_bridge,
211*0b57cec5SDimitry Andric                           E->getBeginLoc())) {
212*0b57cec5SDimitry Andric       Trans.abort();
213*0b57cec5SDimitry Andric       return;
214*0b57cec5SDimitry Andric     }
215*0b57cec5SDimitry Andric 
216*0b57cec5SDimitry Andric     StringRef bridge;
217*0b57cec5SDimitry Andric     switch(Kind) {
218*0b57cec5SDimitry Andric     case OBC_Bridge:
219*0b57cec5SDimitry Andric       bridge = "__bridge "; break;
220*0b57cec5SDimitry Andric     case OBC_BridgeTransfer:
221*0b57cec5SDimitry Andric       bridge = "__bridge_transfer "; break;
222*0b57cec5SDimitry Andric     case OBC_BridgeRetained:
223*0b57cec5SDimitry Andric       bridge = "__bridge_retained "; break;
224*0b57cec5SDimitry Andric     }
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
227*0b57cec5SDimitry Andric                        diag::err_arc_cast_requires_bridge, E->getBeginLoc());
228*0b57cec5SDimitry Andric     if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
229*0b57cec5SDimitry Andric       if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
230*0b57cec5SDimitry Andric         TA.insertAfterToken(CCE->getLParenLoc(), bridge);
231*0b57cec5SDimitry Andric       } else {
232*0b57cec5SDimitry Andric         SourceLocation insertLoc = E->getSubExpr()->getBeginLoc();
233*0b57cec5SDimitry Andric         SmallString<128> newCast;
234*0b57cec5SDimitry Andric         newCast += '(';
235*0b57cec5SDimitry Andric         newCast += bridge;
236*0b57cec5SDimitry Andric         newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
237*0b57cec5SDimitry Andric         newCast += ')';
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric         if (isa<ParenExpr>(E->getSubExpr())) {
240*0b57cec5SDimitry Andric           TA.insert(insertLoc, newCast.str());
241*0b57cec5SDimitry Andric         } else {
242*0b57cec5SDimitry Andric           newCast += '(';
243*0b57cec5SDimitry Andric           TA.insert(insertLoc, newCast.str());
244*0b57cec5SDimitry Andric           TA.insertAfterToken(E->getEndLoc(), ")");
245*0b57cec5SDimitry Andric         }
246*0b57cec5SDimitry Andric       }
247*0b57cec5SDimitry Andric     } else {
248*0b57cec5SDimitry Andric       assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
249*0b57cec5SDimitry Andric       SmallString<32> BridgeCall;
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric       Expr *WrapE = E->getSubExpr();
252*0b57cec5SDimitry Andric       SourceLocation InsertLoc = WrapE->getBeginLoc();
253*0b57cec5SDimitry Andric 
254*0b57cec5SDimitry Andric       SourceManager &SM = Pass.Ctx.getSourceManager();
255*0b57cec5SDimitry Andric       char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
256*0b57cec5SDimitry Andric       if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
257*0b57cec5SDimitry Andric         BridgeCall += ' ';
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric       if (Kind == OBC_BridgeTransfer)
260*0b57cec5SDimitry Andric         BridgeCall += "CFBridgingRelease";
261*0b57cec5SDimitry Andric       else
262*0b57cec5SDimitry Andric         BridgeCall += "CFBridgingRetain";
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric       if (isa<ParenExpr>(WrapE)) {
265*0b57cec5SDimitry Andric         TA.insert(InsertLoc, BridgeCall);
266*0b57cec5SDimitry Andric       } else {
267*0b57cec5SDimitry Andric         BridgeCall += '(';
268*0b57cec5SDimitry Andric         TA.insert(InsertLoc, BridgeCall);
269*0b57cec5SDimitry Andric         TA.insertAfterToken(WrapE->getEndLoc(), ")");
270*0b57cec5SDimitry Andric       }
271*0b57cec5SDimitry Andric     }
272*0b57cec5SDimitry Andric   }
273*0b57cec5SDimitry Andric 
274*0b57cec5SDimitry Andric   void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
275*0b57cec5SDimitry Andric     Transaction Trans(Pass.TA);
276*0b57cec5SDimitry Andric     Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
277*0b57cec5SDimitry Andric     rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
278*0b57cec5SDimitry Andric   }
279*0b57cec5SDimitry Andric 
280*0b57cec5SDimitry Andric   void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
281*0b57cec5SDimitry Andric     SourceManager &SM = Pass.Ctx.getSourceManager();
282*0b57cec5SDimitry Andric     SourceLocation Loc = E->getExprLoc();
283*0b57cec5SDimitry Andric     assert(Loc.isMacroID());
284*0b57cec5SDimitry Andric     CharSourceRange MacroRange = SM.getImmediateExpansionRange(Loc);
285*0b57cec5SDimitry Andric     SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
286*0b57cec5SDimitry Andric     SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
287*0b57cec5SDimitry Andric     SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
288*0b57cec5SDimitry Andric 
289*0b57cec5SDimitry Andric     Outer = MacroRange.getAsRange();
290*0b57cec5SDimitry Andric     Inner = SourceRange(InnerBegin, InnerEnd);
291*0b57cec5SDimitry Andric   }
292*0b57cec5SDimitry Andric 
293*0b57cec5SDimitry Andric   void rewriteBlockCopyMacro(CastExpr *E) {
294*0b57cec5SDimitry Andric     SourceRange OuterRange, InnerRange;
295*0b57cec5SDimitry Andric     getBlockMacroRanges(E, OuterRange, InnerRange);
296*0b57cec5SDimitry Andric 
297*0b57cec5SDimitry Andric     Transaction Trans(Pass.TA);
298*0b57cec5SDimitry Andric     Pass.TA.replace(OuterRange, InnerRange);
299*0b57cec5SDimitry Andric     Pass.TA.insert(InnerRange.getBegin(), "[");
300*0b57cec5SDimitry Andric     Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
301*0b57cec5SDimitry Andric     Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
302*0b57cec5SDimitry Andric                             diag::err_arc_cast_requires_bridge,
303*0b57cec5SDimitry Andric                             OuterRange);
304*0b57cec5SDimitry Andric   }
305*0b57cec5SDimitry Andric 
306*0b57cec5SDimitry Andric   void removeBlockReleaseMacro(CastExpr *E) {
307*0b57cec5SDimitry Andric     SourceRange OuterRange, InnerRange;
308*0b57cec5SDimitry Andric     getBlockMacroRanges(E, OuterRange, InnerRange);
309*0b57cec5SDimitry Andric 
310*0b57cec5SDimitry Andric     Transaction Trans(Pass.TA);
311*0b57cec5SDimitry Andric     Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
312*0b57cec5SDimitry Andric                             diag::err_arc_cast_requires_bridge,
313*0b57cec5SDimitry Andric                             OuterRange);
314*0b57cec5SDimitry Andric     if (!hasSideEffects(E, Pass.Ctx)) {
315*0b57cec5SDimitry Andric       if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
316*0b57cec5SDimitry Andric         return;
317*0b57cec5SDimitry Andric     }
318*0b57cec5SDimitry Andric     Pass.TA.replace(OuterRange, InnerRange);
319*0b57cec5SDimitry Andric   }
320*0b57cec5SDimitry Andric 
321*0b57cec5SDimitry Andric   bool tryRemoving(Expr *E) const {
322*0b57cec5SDimitry Andric     if (!Removables) {
323*0b57cec5SDimitry Andric       Removables.reset(new ExprSet);
324*0b57cec5SDimitry Andric       collectRemovables(Body, *Removables);
325*0b57cec5SDimitry Andric     }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric     if (Removables->count(E)) {
328*0b57cec5SDimitry Andric       Pass.TA.removeStmt(E);
329*0b57cec5SDimitry Andric       return true;
330*0b57cec5SDimitry Andric     }
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric     return false;
333*0b57cec5SDimitry Andric   }
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric   void transformObjCToNonObjCCast(CastExpr *E) {
336*0b57cec5SDimitry Andric     SourceLocation CastLoc = E->getExprLoc();
337*0b57cec5SDimitry Andric     if (CastLoc.isMacroID()) {
338*0b57cec5SDimitry Andric       StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
339*0b57cec5SDimitry Andric                                                     Pass.Ctx.getSourceManager(),
340*0b57cec5SDimitry Andric                                                     Pass.Ctx.getLangOpts());
341*0b57cec5SDimitry Andric       if (MacroName == "Block_copy") {
342*0b57cec5SDimitry Andric         rewriteBlockCopyMacro(E);
343*0b57cec5SDimitry Andric         return;
344*0b57cec5SDimitry Andric       }
345*0b57cec5SDimitry Andric       if (MacroName == "Block_release") {
346*0b57cec5SDimitry Andric         removeBlockReleaseMacro(E);
347*0b57cec5SDimitry Andric         return;
348*0b57cec5SDimitry Andric       }
349*0b57cec5SDimitry Andric     }
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric     if (isSelf(E->getSubExpr()))
352*0b57cec5SDimitry Andric       return rewriteToBridgedCast(E, OBC_Bridge);
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric     CallExpr *callE;
355*0b57cec5SDimitry Andric     if (isPassedToCFRetain(E, callE))
356*0b57cec5SDimitry Andric       return rewriteCastForCFRetain(E, callE);
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric     ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
359*0b57cec5SDimitry Andric     if (family == OMF_retain)
360*0b57cec5SDimitry Andric       return rewriteToBridgedCast(E, OBC_BridgeRetained);
361*0b57cec5SDimitry Andric 
362*0b57cec5SDimitry Andric     if (family == OMF_autorelease || family == OMF_release) {
363*0b57cec5SDimitry Andric       std::string err = "it is not safe to cast to '";
364*0b57cec5SDimitry Andric       err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
365*0b57cec5SDimitry Andric       err += "' the result of '";
366*0b57cec5SDimitry Andric       err += family == OMF_autorelease ? "autorelease" : "release";
367*0b57cec5SDimitry Andric       err += "' message; a __bridge cast may result in a pointer to a "
368*0b57cec5SDimitry Andric           "destroyed object and a __bridge_retained may leak the object";
369*0b57cec5SDimitry Andric       Pass.TA.reportError(err, E->getBeginLoc(),
370*0b57cec5SDimitry Andric                           E->getSubExpr()->getSourceRange());
371*0b57cec5SDimitry Andric       Stmt *parent = E;
372*0b57cec5SDimitry Andric       do {
373*0b57cec5SDimitry Andric         parent = StmtMap->getParentIgnoreParenImpCasts(parent);
374*0b57cec5SDimitry Andric       } while (parent && isa<FullExpr>(parent));
375*0b57cec5SDimitry Andric 
376*0b57cec5SDimitry Andric       if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
377*0b57cec5SDimitry Andric         std::string note = "remove the cast and change return type of function "
378*0b57cec5SDimitry Andric             "to '";
379*0b57cec5SDimitry Andric         note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
380*0b57cec5SDimitry Andric         note += "' to have the object automatically autoreleased";
381*0b57cec5SDimitry Andric         Pass.TA.reportNote(note, retS->getBeginLoc());
382*0b57cec5SDimitry Andric       }
383*0b57cec5SDimitry Andric     }
384*0b57cec5SDimitry Andric 
385*0b57cec5SDimitry Andric     Expr *subExpr = E->getSubExpr();
386*0b57cec5SDimitry Andric 
387*0b57cec5SDimitry Andric     // Look through pseudo-object expressions.
388*0b57cec5SDimitry Andric     if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
389*0b57cec5SDimitry Andric       subExpr = pseudo->getResultExpr();
390*0b57cec5SDimitry Andric       assert(subExpr && "no result for pseudo-object of non-void type?");
391*0b57cec5SDimitry Andric     }
392*0b57cec5SDimitry Andric 
393*0b57cec5SDimitry Andric     if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
394*0b57cec5SDimitry Andric       if (implCE->getCastKind() == CK_ARCConsumeObject)
395*0b57cec5SDimitry Andric         return rewriteToBridgedCast(E, OBC_BridgeRetained);
396*0b57cec5SDimitry Andric       if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
397*0b57cec5SDimitry Andric         return rewriteToBridgedCast(E, OBC_Bridge);
398*0b57cec5SDimitry Andric     }
399*0b57cec5SDimitry Andric 
400*0b57cec5SDimitry Andric     bool isConsumed = false;
401*0b57cec5SDimitry Andric     if (isPassedToCParamWithKnownOwnership(E, isConsumed))
402*0b57cec5SDimitry Andric       return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
403*0b57cec5SDimitry Andric                                                 : OBC_Bridge);
404*0b57cec5SDimitry Andric   }
405*0b57cec5SDimitry Andric 
406*0b57cec5SDimitry Andric   static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
407*0b57cec5SDimitry Andric     E = E->IgnoreParenCasts();
408*0b57cec5SDimitry Andric     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
409*0b57cec5SDimitry Andric       return ME->getMethodFamily();
410*0b57cec5SDimitry Andric 
411*0b57cec5SDimitry Andric     return OMF_None;
412*0b57cec5SDimitry Andric   }
413*0b57cec5SDimitry Andric 
414*0b57cec5SDimitry Andric   bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
415*0b57cec5SDimitry Andric     if ((callE = dyn_cast_or_null<CallExpr>(
416*0b57cec5SDimitry Andric                                      StmtMap->getParentIgnoreParenImpCasts(E))))
417*0b57cec5SDimitry Andric       if (FunctionDecl *
418*0b57cec5SDimitry Andric             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
419*0b57cec5SDimitry Andric         if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
420*0b57cec5SDimitry Andric             FD->getParent()->isTranslationUnit() &&
421*0b57cec5SDimitry Andric             FD->isExternallyVisible())
422*0b57cec5SDimitry Andric           return true;
423*0b57cec5SDimitry Andric 
424*0b57cec5SDimitry Andric     return false;
425*0b57cec5SDimitry Andric   }
426*0b57cec5SDimitry Andric 
427*0b57cec5SDimitry Andric   bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
428*0b57cec5SDimitry Andric     if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
429*0b57cec5SDimitry Andric                                      StmtMap->getParentIgnoreParenImpCasts(E)))
430*0b57cec5SDimitry Andric       if (FunctionDecl *
431*0b57cec5SDimitry Andric             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
432*0b57cec5SDimitry Andric         unsigned i = 0;
433*0b57cec5SDimitry Andric         for (unsigned e = callE->getNumArgs(); i != e; ++i) {
434*0b57cec5SDimitry Andric           Expr *arg = callE->getArg(i);
435*0b57cec5SDimitry Andric           if (arg == E || arg->IgnoreParenImpCasts() == E)
436*0b57cec5SDimitry Andric             break;
437*0b57cec5SDimitry Andric         }
438*0b57cec5SDimitry Andric         if (i < callE->getNumArgs() && i < FD->getNumParams()) {
439*0b57cec5SDimitry Andric           ParmVarDecl *PD = FD->getParamDecl(i);
440*0b57cec5SDimitry Andric           if (PD->hasAttr<CFConsumedAttr>()) {
441*0b57cec5SDimitry Andric             isConsumed = true;
442*0b57cec5SDimitry Andric             return true;
443*0b57cec5SDimitry Andric           }
444*0b57cec5SDimitry Andric         }
445*0b57cec5SDimitry Andric       }
446*0b57cec5SDimitry Andric 
447*0b57cec5SDimitry Andric     return false;
448*0b57cec5SDimitry Andric   }
449*0b57cec5SDimitry Andric 
450*0b57cec5SDimitry Andric   bool isSelf(Expr *E) const {
451*0b57cec5SDimitry Andric     E = E->IgnoreParenLValueCasts();
452*0b57cec5SDimitry Andric     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
453*0b57cec5SDimitry Andric       if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
454*0b57cec5SDimitry Andric         if (IPD->getIdentifier() == SelfII)
455*0b57cec5SDimitry Andric           return true;
456*0b57cec5SDimitry Andric 
457*0b57cec5SDimitry Andric     return false;
458*0b57cec5SDimitry Andric   }
459*0b57cec5SDimitry Andric };
460*0b57cec5SDimitry Andric 
461*0b57cec5SDimitry Andric } // end anonymous namespace
462*0b57cec5SDimitry Andric 
463*0b57cec5SDimitry Andric void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
464*0b57cec5SDimitry Andric   BodyTransform<UnbridgedCastRewriter> trans(pass);
465*0b57cec5SDimitry Andric   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
466*0b57cec5SDimitry Andric }
467