xref: /freebsd-src/contrib/llvm-project/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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