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