10b57cec5SDimitry Andric //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // rewriteUnbridgedCasts: 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer 120b57cec5SDimitry Andric // is from a file-level variable, __bridge cast is used to convert it. 130b57cec5SDimitry Andric // For the result of a function call that we know is +1/+0, 140b57cec5SDimitry Andric // __bridge/CFBridgingRelease is used. 150b57cec5SDimitry Andric // 160b57cec5SDimitry Andric // NSString *str = (NSString *)kUTTypePlainText; 170b57cec5SDimitry Andric // str = b ? kUTTypeRTF : kUTTypePlainText; 180b57cec5SDimitry Andric // NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, 190b57cec5SDimitry Andric // _uuid); 200b57cec5SDimitry Andric // ----> 210b57cec5SDimitry Andric // NSString *str = (__bridge NSString *)kUTTypePlainText; 220b57cec5SDimitry Andric // str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText); 230b57cec5SDimitry Andric // NSString *_uuidString = (NSString *) 240b57cec5SDimitry Andric // CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid)); 250b57cec5SDimitry Andric // 260b57cec5SDimitry Andric // For a C pointer to ObjC, for casting 'self', __bridge is used. 270b57cec5SDimitry Andric // 280b57cec5SDimitry Andric // CFStringRef str = (CFStringRef)self; 290b57cec5SDimitry Andric // ----> 300b57cec5SDimitry Andric // CFStringRef str = (__bridge CFStringRef)self; 310b57cec5SDimitry Andric // 320b57cec5SDimitry Andric // Uses of Block_copy/Block_release macros are rewritten: 330b57cec5SDimitry Andric // 340b57cec5SDimitry Andric // c = Block_copy(b); 350b57cec5SDimitry Andric // Block_release(c); 360b57cec5SDimitry Andric // ----> 370b57cec5SDimitry Andric // c = [b copy]; 380b57cec5SDimitry Andric // <removed> 390b57cec5SDimitry Andric // 400b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric #include "Transforms.h" 430b57cec5SDimitry Andric #include "Internals.h" 440b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 450b57cec5SDimitry Andric #include "clang/AST/Attr.h" 460b57cec5SDimitry Andric #include "clang/AST/ParentMap.h" 470b57cec5SDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 480b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 490b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 500b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h" 510b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric using namespace clang; 540b57cec5SDimitry Andric using namespace arcmt; 550b57cec5SDimitry Andric using namespace trans; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric namespace { 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ 600b57cec5SDimitry Andric MigrationPass &Pass; 610b57cec5SDimitry Andric IdentifierInfo *SelfII; 620b57cec5SDimitry Andric std::unique_ptr<ParentMap> StmtMap; 630b57cec5SDimitry Andric Decl *ParentD; 640b57cec5SDimitry Andric Stmt *Body; 650b57cec5SDimitry Andric mutable std::unique_ptr<ExprSet> Removables; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric public: 680b57cec5SDimitry Andric UnbridgedCastRewriter(MigrationPass &pass) 690b57cec5SDimitry Andric : Pass(pass), ParentD(nullptr), Body(nullptr) { 700b57cec5SDimitry Andric SelfII = &Pass.Ctx.Idents.get("self"); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void transformBody(Stmt *body, Decl *ParentD) { 740b57cec5SDimitry Andric this->ParentD = ParentD; 750b57cec5SDimitry Andric Body = body; 760b57cec5SDimitry Andric StmtMap.reset(new ParentMap(body)); 770b57cec5SDimitry Andric TraverseStmt(body); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric bool TraverseBlockDecl(BlockDecl *D) { 810b57cec5SDimitry Andric // ParentMap does not enter into a BlockDecl to record its stmts, so use a 820b57cec5SDimitry Andric // new UnbridgedCastRewriter to handle the block. 830b57cec5SDimitry Andric UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D); 840b57cec5SDimitry Andric return true; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool VisitCastExpr(CastExpr *E) { 880b57cec5SDimitry Andric if (E->getCastKind() != CK_CPointerToObjCPointerCast && 890b57cec5SDimitry Andric E->getCastKind() != CK_BitCast && 900b57cec5SDimitry Andric E->getCastKind() != CK_AnyPointerToBlockPointerCast) 910b57cec5SDimitry Andric return true; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric QualType castType = E->getType(); 940b57cec5SDimitry Andric Expr *castExpr = E->getSubExpr(); 950b57cec5SDimitry Andric QualType castExprType = castExpr->getType(); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType()) 980b57cec5SDimitry Andric return true; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); 1010b57cec5SDimitry Andric bool castRetainable = castType->isObjCIndirectLifetimeType(); 1020b57cec5SDimitry Andric if (exprRetainable == castRetainable) return true; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric if (castExpr->isNullPointerConstant(Pass.Ctx, 1050b57cec5SDimitry Andric Expr::NPC_ValueDependentIsNull)) 1060b57cec5SDimitry Andric return true; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric SourceLocation loc = castExpr->getExprLoc(); 1090b57cec5SDimitry Andric if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) 1100b57cec5SDimitry Andric return true; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric if (castType->isObjCRetainableType()) 1130b57cec5SDimitry Andric transformNonObjCToObjCCast(E); 1140b57cec5SDimitry Andric else 1150b57cec5SDimitry Andric transformObjCToNonObjCCast(E); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric return true; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric private: 1210b57cec5SDimitry Andric void transformNonObjCToObjCCast(CastExpr *E) { 1220b57cec5SDimitry Andric if (!E) return; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Global vars are assumed that are cast as unretained. 1250b57cec5SDimitry Andric if (isGlobalVar(E)) 1260b57cec5SDimitry Andric if (E->getSubExpr()->getType()->isPointerType()) { 1270b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/false); 1280b57cec5SDimitry Andric return; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // If the cast is directly over the result of a Core Foundation function 1320b57cec5SDimitry Andric // try to figure out whether it should be cast as retained or unretained. 1330b57cec5SDimitry Andric Expr *inner = E->IgnoreParenCasts(); 1340b57cec5SDimitry Andric if (CallExpr *callE = dyn_cast<CallExpr>(inner)) { 1350b57cec5SDimitry Andric if (FunctionDecl *FD = callE->getDirectCallee()) { 1360b57cec5SDimitry Andric if (FD->hasAttr<CFReturnsRetainedAttr>()) { 1370b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/true); 1380b57cec5SDimitry Andric return; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric if (FD->hasAttr<CFReturnsNotRetainedAttr>()) { 1410b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/false); 1420b57cec5SDimitry Andric return; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric if (FD->isGlobal() && 1450b57cec5SDimitry Andric FD->getIdentifier() && 1460b57cec5SDimitry Andric ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", 1470b57cec5SDimitry Andric FD->getIdentifier()->getName())) { 1480b57cec5SDimitry Andric StringRef fname = FD->getIdentifier()->getName(); 1495f757f3fSDimitry Andric if (fname.ends_with("Retain") || fname.contains("Create") || 150349cc55cSDimitry Andric fname.contains("Copy")) { 1510b57cec5SDimitry Andric // Do not migrate to couple of bridge transfer casts which 1520b57cec5SDimitry Andric // cancel each other out. Leave it unchanged so error gets user 1530b57cec5SDimitry Andric // attention instead. 1540b57cec5SDimitry Andric if (FD->getName() == "CFRetain" && 1550b57cec5SDimitry Andric FD->getNumParams() == 1 && 1560b57cec5SDimitry Andric FD->getParent()->isTranslationUnit() && 1570b57cec5SDimitry Andric FD->isExternallyVisible()) { 1580b57cec5SDimitry Andric Expr *Arg = callE->getArg(0); 1590b57cec5SDimitry Andric if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { 1600b57cec5SDimitry Andric const Expr *sub = ICE->getSubExpr(); 1610b57cec5SDimitry Andric QualType T = sub->getType(); 1620b57cec5SDimitry Andric if (T->isObjCObjectPointerType()) 1630b57cec5SDimitry Andric return; 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/true); 1670b57cec5SDimitry Andric return; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 170349cc55cSDimitry Andric if (fname.contains("Get")) { 1710b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/false); 1720b57cec5SDimitry Andric return; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // If returning an ivar or a member of an ivar from a +0 method, use 1790b57cec5SDimitry Andric // a __bridge cast. 1800b57cec5SDimitry Andric Expr *base = inner->IgnoreParenImpCasts(); 1810b57cec5SDimitry Andric while (isa<MemberExpr>(base)) 1820b57cec5SDimitry Andric base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts(); 1830b57cec5SDimitry Andric if (isa<ObjCIvarRefExpr>(base) && 1840b57cec5SDimitry Andric isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) { 1850b57cec5SDimitry Andric if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) { 1860b57cec5SDimitry Andric if (!method->hasAttr<NSReturnsRetainedAttr>()) { 1870b57cec5SDimitry Andric castToObjCObject(E, /*retained=*/false); 1880b57cec5SDimitry Andric return; 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric void castToObjCObject(CastExpr *E, bool retained) { 1950b57cec5SDimitry Andric rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { 1990b57cec5SDimitry Andric Transaction Trans(Pass.TA); 2000b57cec5SDimitry Andric rewriteToBridgedCast(E, Kind, Trans); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, 2040b57cec5SDimitry Andric Transaction &Trans) { 2050b57cec5SDimitry Andric TransformActions &TA = Pass.TA; 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // We will remove the compiler diagnostic. 2080b57cec5SDimitry Andric if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, 2090b57cec5SDimitry Andric diag::err_arc_cast_requires_bridge, 2100b57cec5SDimitry Andric E->getBeginLoc())) { 2110b57cec5SDimitry Andric Trans.abort(); 2120b57cec5SDimitry Andric return; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric StringRef bridge; 2160b57cec5SDimitry Andric switch(Kind) { 2170b57cec5SDimitry Andric case OBC_Bridge: 2180b57cec5SDimitry Andric bridge = "__bridge "; break; 2190b57cec5SDimitry Andric case OBC_BridgeTransfer: 2200b57cec5SDimitry Andric bridge = "__bridge_transfer "; break; 2210b57cec5SDimitry Andric case OBC_BridgeRetained: 2220b57cec5SDimitry Andric bridge = "__bridge_retained "; break; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric TA.clearDiagnostic(diag::err_arc_mismatched_cast, 2260b57cec5SDimitry Andric diag::err_arc_cast_requires_bridge, E->getBeginLoc()); 2270b57cec5SDimitry Andric if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) { 2280b57cec5SDimitry Andric if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) { 2290b57cec5SDimitry Andric TA.insertAfterToken(CCE->getLParenLoc(), bridge); 2300b57cec5SDimitry Andric } else { 2310b57cec5SDimitry Andric SourceLocation insertLoc = E->getSubExpr()->getBeginLoc(); 2320b57cec5SDimitry Andric SmallString<128> newCast; 2330b57cec5SDimitry Andric newCast += '('; 2340b57cec5SDimitry Andric newCast += bridge; 2350b57cec5SDimitry Andric newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 2360b57cec5SDimitry Andric newCast += ')'; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric if (isa<ParenExpr>(E->getSubExpr())) { 2390b57cec5SDimitry Andric TA.insert(insertLoc, newCast.str()); 2400b57cec5SDimitry Andric } else { 2410b57cec5SDimitry Andric newCast += '('; 2420b57cec5SDimitry Andric TA.insert(insertLoc, newCast.str()); 2430b57cec5SDimitry Andric TA.insertAfterToken(E->getEndLoc(), ")"); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric } else { 2470b57cec5SDimitry Andric assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained); 2480b57cec5SDimitry Andric SmallString<32> BridgeCall; 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric Expr *WrapE = E->getSubExpr(); 2510b57cec5SDimitry Andric SourceLocation InsertLoc = WrapE->getBeginLoc(); 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric SourceManager &SM = Pass.Ctx.getSourceManager(); 2540b57cec5SDimitry Andric char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1)); 255349cc55cSDimitry Andric if (Lexer::isAsciiIdentifierContinueChar(PrevChar, 256349cc55cSDimitry Andric Pass.Ctx.getLangOpts())) 2570b57cec5SDimitry Andric BridgeCall += ' '; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric if (Kind == OBC_BridgeTransfer) 2600b57cec5SDimitry Andric BridgeCall += "CFBridgingRelease"; 2610b57cec5SDimitry Andric else 2620b57cec5SDimitry Andric BridgeCall += "CFBridgingRetain"; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric if (isa<ParenExpr>(WrapE)) { 2650b57cec5SDimitry Andric TA.insert(InsertLoc, BridgeCall); 2660b57cec5SDimitry Andric } else { 2670b57cec5SDimitry Andric BridgeCall += '('; 2680b57cec5SDimitry Andric TA.insert(InsertLoc, BridgeCall); 2690b57cec5SDimitry Andric TA.insertAfterToken(WrapE->getEndLoc(), ")"); 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { 2750b57cec5SDimitry Andric Transaction Trans(Pass.TA); 2760b57cec5SDimitry Andric Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); 2770b57cec5SDimitry Andric rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) { 2810b57cec5SDimitry Andric SourceManager &SM = Pass.Ctx.getSourceManager(); 2820b57cec5SDimitry Andric SourceLocation Loc = E->getExprLoc(); 2830b57cec5SDimitry Andric assert(Loc.isMacroID()); 2840b57cec5SDimitry Andric CharSourceRange MacroRange = SM.getImmediateExpansionRange(Loc); 2850b57cec5SDimitry Andric SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange(); 2860b57cec5SDimitry Andric SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin()); 2870b57cec5SDimitry Andric SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd()); 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric Outer = MacroRange.getAsRange(); 2900b57cec5SDimitry Andric Inner = SourceRange(InnerBegin, InnerEnd); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric void rewriteBlockCopyMacro(CastExpr *E) { 2940b57cec5SDimitry Andric SourceRange OuterRange, InnerRange; 2950b57cec5SDimitry Andric getBlockMacroRanges(E, OuterRange, InnerRange); 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric Transaction Trans(Pass.TA); 2980b57cec5SDimitry Andric Pass.TA.replace(OuterRange, InnerRange); 2990b57cec5SDimitry Andric Pass.TA.insert(InnerRange.getBegin(), "["); 3000b57cec5SDimitry Andric Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]"); 3010b57cec5SDimitry Andric Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, 3020b57cec5SDimitry Andric diag::err_arc_cast_requires_bridge, 3030b57cec5SDimitry Andric OuterRange); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric void removeBlockReleaseMacro(CastExpr *E) { 3070b57cec5SDimitry Andric SourceRange OuterRange, InnerRange; 3080b57cec5SDimitry Andric getBlockMacroRanges(E, OuterRange, InnerRange); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric Transaction Trans(Pass.TA); 3110b57cec5SDimitry Andric Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, 3120b57cec5SDimitry Andric diag::err_arc_cast_requires_bridge, 3130b57cec5SDimitry Andric OuterRange); 3140b57cec5SDimitry Andric if (!hasSideEffects(E, Pass.Ctx)) { 3150b57cec5SDimitry Andric if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E)))) 3160b57cec5SDimitry Andric return; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric Pass.TA.replace(OuterRange, InnerRange); 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric bool tryRemoving(Expr *E) const { 3220b57cec5SDimitry Andric if (!Removables) { 3230b57cec5SDimitry Andric Removables.reset(new ExprSet); 3240b57cec5SDimitry Andric collectRemovables(Body, *Removables); 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric if (Removables->count(E)) { 3280b57cec5SDimitry Andric Pass.TA.removeStmt(E); 3290b57cec5SDimitry Andric return true; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric return false; 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric void transformObjCToNonObjCCast(CastExpr *E) { 3360b57cec5SDimitry Andric SourceLocation CastLoc = E->getExprLoc(); 3370b57cec5SDimitry Andric if (CastLoc.isMacroID()) { 3380b57cec5SDimitry Andric StringRef MacroName = Lexer::getImmediateMacroName(CastLoc, 3390b57cec5SDimitry Andric Pass.Ctx.getSourceManager(), 3400b57cec5SDimitry Andric Pass.Ctx.getLangOpts()); 3410b57cec5SDimitry Andric if (MacroName == "Block_copy") { 3420b57cec5SDimitry Andric rewriteBlockCopyMacro(E); 3430b57cec5SDimitry Andric return; 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric if (MacroName == "Block_release") { 3460b57cec5SDimitry Andric removeBlockReleaseMacro(E); 3470b57cec5SDimitry Andric return; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric if (isSelf(E->getSubExpr())) 3520b57cec5SDimitry Andric return rewriteToBridgedCast(E, OBC_Bridge); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric CallExpr *callE; 3550b57cec5SDimitry Andric if (isPassedToCFRetain(E, callE)) 3560b57cec5SDimitry Andric return rewriteCastForCFRetain(E, callE); 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); 3590b57cec5SDimitry Andric if (family == OMF_retain) 3600b57cec5SDimitry Andric return rewriteToBridgedCast(E, OBC_BridgeRetained); 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric if (family == OMF_autorelease || family == OMF_release) { 3630b57cec5SDimitry Andric std::string err = "it is not safe to cast to '"; 3640b57cec5SDimitry Andric err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 3650b57cec5SDimitry Andric err += "' the result of '"; 3660b57cec5SDimitry Andric err += family == OMF_autorelease ? "autorelease" : "release"; 3670b57cec5SDimitry Andric err += "' message; a __bridge cast may result in a pointer to a " 3680b57cec5SDimitry Andric "destroyed object and a __bridge_retained may leak the object"; 3690b57cec5SDimitry Andric Pass.TA.reportError(err, E->getBeginLoc(), 3700b57cec5SDimitry Andric E->getSubExpr()->getSourceRange()); 3710b57cec5SDimitry Andric Stmt *parent = E; 3720b57cec5SDimitry Andric do { 3730b57cec5SDimitry Andric parent = StmtMap->getParentIgnoreParenImpCasts(parent); 374*0fca6ea1SDimitry Andric } while (isa_and_nonnull<FullExpr>(parent)); 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { 3770b57cec5SDimitry Andric std::string note = "remove the cast and change return type of function " 3780b57cec5SDimitry Andric "to '"; 3790b57cec5SDimitry Andric note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 3800b57cec5SDimitry Andric note += "' to have the object automatically autoreleased"; 3810b57cec5SDimitry Andric Pass.TA.reportNote(note, retS->getBeginLoc()); 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric Expr *subExpr = E->getSubExpr(); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric // Look through pseudo-object expressions. 3880b57cec5SDimitry Andric if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) { 3890b57cec5SDimitry Andric subExpr = pseudo->getResultExpr(); 3900b57cec5SDimitry Andric assert(subExpr && "no result for pseudo-object of non-void type?"); 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) { 3940b57cec5SDimitry Andric if (implCE->getCastKind() == CK_ARCConsumeObject) 3950b57cec5SDimitry Andric return rewriteToBridgedCast(E, OBC_BridgeRetained); 3960b57cec5SDimitry Andric if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) 3970b57cec5SDimitry Andric return rewriteToBridgedCast(E, OBC_Bridge); 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric bool isConsumed = false; 4010b57cec5SDimitry Andric if (isPassedToCParamWithKnownOwnership(E, isConsumed)) 4020b57cec5SDimitry Andric return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained 4030b57cec5SDimitry Andric : OBC_Bridge); 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric static ObjCMethodFamily getFamilyOfMessage(Expr *E) { 4070b57cec5SDimitry Andric E = E->IgnoreParenCasts(); 4080b57cec5SDimitry Andric if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) 4090b57cec5SDimitry Andric return ME->getMethodFamily(); 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric return OMF_None; 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { 4150b57cec5SDimitry Andric if ((callE = dyn_cast_or_null<CallExpr>( 4160b57cec5SDimitry Andric StmtMap->getParentIgnoreParenImpCasts(E)))) 4170b57cec5SDimitry Andric if (FunctionDecl * 4180b57cec5SDimitry Andric FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) 4190b57cec5SDimitry Andric if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && 4200b57cec5SDimitry Andric FD->getParent()->isTranslationUnit() && 4210b57cec5SDimitry Andric FD->isExternallyVisible()) 4220b57cec5SDimitry Andric return true; 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric return false; 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { 4280b57cec5SDimitry Andric if (CallExpr *callE = dyn_cast_or_null<CallExpr>( 4290b57cec5SDimitry Andric StmtMap->getParentIgnoreParenImpCasts(E))) 4300b57cec5SDimitry Andric if (FunctionDecl * 4310b57cec5SDimitry Andric FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { 4320b57cec5SDimitry Andric unsigned i = 0; 4330b57cec5SDimitry Andric for (unsigned e = callE->getNumArgs(); i != e; ++i) { 4340b57cec5SDimitry Andric Expr *arg = callE->getArg(i); 4350b57cec5SDimitry Andric if (arg == E || arg->IgnoreParenImpCasts() == E) 4360b57cec5SDimitry Andric break; 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric if (i < callE->getNumArgs() && i < FD->getNumParams()) { 4390b57cec5SDimitry Andric ParmVarDecl *PD = FD->getParamDecl(i); 4400b57cec5SDimitry Andric if (PD->hasAttr<CFConsumedAttr>()) { 4410b57cec5SDimitry Andric isConsumed = true; 4420b57cec5SDimitry Andric return true; 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric return false; 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric bool isSelf(Expr *E) const { 4510b57cec5SDimitry Andric E = E->IgnoreParenLValueCasts(); 4520b57cec5SDimitry Andric if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 4530b57cec5SDimitry Andric if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) 4540b57cec5SDimitry Andric if (IPD->getIdentifier() == SelfII) 4550b57cec5SDimitry Andric return true; 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric return false; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric }; 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric } // end anonymous namespace 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric void trans::rewriteUnbridgedCasts(MigrationPass &pass) { 4640b57cec5SDimitry Andric BodyTransform<UnbridgedCastRewriter> trans(pass); 4650b57cec5SDimitry Andric trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 4660b57cec5SDimitry Andric } 467