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