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