Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- TransUnbridgedCasts.cpp - Tranformations 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/__bridge_transfer 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 = (__bridge_transfer NSString *)
     25 //                               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 //===----------------------------------------------------------------------===//
     34 
     35 #include "Transforms.h"
     36 #include "Internals.h"
     37 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
     38 #include "clang/Sema/SemaDiagnostic.h"
     39 #include "clang/AST/ParentMap.h"
     40 #include "clang/Basic/SourceManager.h"
     41 
     42 using namespace clang;
     43 using namespace arcmt;
     44 using namespace trans;
     45 
     46 namespace {
     47 
     48 class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
     49   MigrationPass &Pass;
     50   IdentifierInfo *SelfII;
     51   llvm::OwningPtr<ParentMap> StmtMap;
     52 
     53 public:
     54   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
     55     SelfII = &Pass.Ctx.Idents.get("self");
     56   }
     57 
     58   void transformBody(Stmt *body) {
     59     StmtMap.reset(new ParentMap(body));
     60     TraverseStmt(body);
     61   }
     62 
     63   bool VisitCastExpr(CastExpr *E) {
     64     if (E->getCastKind() != CK_CPointerToObjCPointerCast
     65         && E->getCastKind() != CK_BitCast)
     66       return true;
     67 
     68     QualType castType = E->getType();
     69     Expr *castExpr = E->getSubExpr();
     70     QualType castExprType = castExpr->getType();
     71 
     72     if (castType->isObjCObjectPointerType() &&
     73         castExprType->isObjCObjectPointerType())
     74       return true;
     75     if (!castType->isObjCObjectPointerType() &&
     76         !castExprType->isObjCObjectPointerType())
     77       return true;
     78 
     79     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
     80     bool castRetainable = castType->isObjCIndirectLifetimeType();
     81     if (exprRetainable == castRetainable) return true;
     82 
     83     if (castExpr->isNullPointerConstant(Pass.Ctx,
     84                                         Expr::NPC_ValueDependentIsNull))
     85       return true;
     86 
     87     SourceLocation loc = castExpr->getExprLoc();
     88     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
     89       return true;
     90 
     91     if (castType->isObjCObjectPointerType())
     92       transformNonObjCToObjCCast(E);
     93     else
     94       transformObjCToNonObjCCast(E);
     95 
     96     return true;
     97   }
     98 
     99 private:
    100   void transformNonObjCToObjCCast(CastExpr *E) {
    101     if (!E) return;
    102 
    103     // Global vars are assumed that are cast as unretained.
    104     if (isGlobalVar(E))
    105       if (E->getSubExpr()->getType()->isPointerType()) {
    106         castToObjCObject(E, /*retained=*/false);
    107         return;
    108       }
    109 
    110     // If the cast is directly over the result of a Core Foundation function
    111     // try to figure out whether it should be cast as retained or unretained.
    112     Expr *inner = E->IgnoreParenCasts();
    113     if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
    114       if (FunctionDecl *FD = callE->getDirectCallee()) {
    115         if (FD->getAttr<CFReturnsRetainedAttr>()) {
    116           castToObjCObject(E, /*retained=*/true);
    117           return;
    118         }
    119         if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
    120           castToObjCObject(E, /*retained=*/false);
    121           return;
    122         }
    123         if (FD->isGlobal() &&
    124             FD->getIdentifier() &&
    125             ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
    126                                    FD->getIdentifier()->getName())) {
    127           StringRef fname = FD->getIdentifier()->getName();
    128           if (fname.endswith("Retain") ||
    129               fname.find("Create") != StringRef::npos ||
    130               fname.find("Copy") != StringRef::npos) {
    131             castToObjCObject(E, /*retained=*/true);
    132             return;
    133           }
    134 
    135           if (fname.find("Get") != StringRef::npos) {
    136             castToObjCObject(E, /*retained=*/false);
    137             return;
    138           }
    139         }
    140       }
    141     }
    142   }
    143 
    144   void castToObjCObject(CastExpr *E, bool retained) {
    145     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
    146   }
    147 
    148   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
    149     Transaction Trans(Pass.TA);
    150     rewriteToBridgedCast(E, Kind, Trans);
    151   }
    152 
    153   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
    154                             Transaction &Trans) {
    155     TransformActions &TA = Pass.TA;
    156 
    157     // We will remove the compiler diagnostic.
    158     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
    159                           diag::err_arc_cast_requires_bridge,
    160                           E->getLocStart())) {
    161       Trans.abort();
    162       return;
    163     }
    164 
    165     StringRef bridge;
    166     switch(Kind) {
    167     case OBC_Bridge:
    168       bridge = "__bridge "; break;
    169     case OBC_BridgeTransfer:
    170       bridge = "__bridge_transfer "; break;
    171     case OBC_BridgeRetained:
    172       bridge = "__bridge_retained "; break;
    173     }
    174 
    175     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
    176                        diag::err_arc_cast_requires_bridge,
    177                        E->getLocStart());
    178     if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
    179       TA.insertAfterToken(CCE->getLParenLoc(), bridge);
    180     } else {
    181       SourceLocation insertLoc = E->getSubExpr()->getLocStart();
    182       llvm::SmallString<128> newCast;
    183       newCast += '(';
    184       newCast += bridge;
    185       newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
    186       newCast += ')';
    187 
    188       if (isa<ParenExpr>(E->getSubExpr())) {
    189         TA.insert(insertLoc, newCast.str());
    190       } else {
    191         newCast += '(';
    192         TA.insert(insertLoc, newCast.str());
    193         TA.insertAfterToken(E->getLocEnd(), ")");
    194       }
    195     }
    196   }
    197 
    198   void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
    199     Transaction Trans(Pass.TA);
    200     Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
    201     rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
    202   }
    203 
    204   void transformObjCToNonObjCCast(CastExpr *E) {
    205     if (isSelf(E->getSubExpr()))
    206       return rewriteToBridgedCast(E, OBC_Bridge);
    207 
    208     CallExpr *callE;
    209     if (isPassedToCFRetain(E, callE))
    210       return rewriteCastForCFRetain(E, callE);
    211 
    212     ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
    213     if (family == OMF_retain)
    214       return rewriteToBridgedCast(E, OBC_BridgeRetained);
    215 
    216     if (family == OMF_autorelease || family == OMF_release) {
    217       std::string err = "it is not safe to cast to '";
    218       err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
    219       err += "' the result of '";
    220       err += family == OMF_autorelease ? "autorelease" : "release";
    221       err += "' message; a __bridge cast may result in a pointer to a "
    222           "destroyed object and a __bridge_retained may leak the object";
    223       Pass.TA.reportError(err, E->getLocStart(),
    224                           E->getSubExpr()->getSourceRange());
    225       Stmt *parent = E;
    226       do {
    227         parent = StmtMap->getParentIgnoreParenImpCasts(parent);
    228       } while (parent && isa<ExprWithCleanups>(parent));
    229 
    230       if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
    231         std::string note = "remove the cast and change return type of function "
    232             "to '";
    233         note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
    234         note += "' to have the object automatically autoreleased";
    235         Pass.TA.reportNote(note, retS->getLocStart());
    236       }
    237     }
    238 
    239     if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
    240       if (implCE->getCastKind() == CK_ARCConsumeObject)
    241         return rewriteToBridgedCast(E, OBC_BridgeRetained);
    242       if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
    243         return rewriteToBridgedCast(E, OBC_Bridge);
    244     }
    245 
    246     bool isConsumed = false;
    247     if (isPassedToCParamWithKnownOwnership(E, isConsumed))
    248       return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
    249                                                 : OBC_Bridge);
    250   }
    251 
    252   static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
    253     E = E->IgnoreParenCasts();
    254     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
    255       return ME->getMethodFamily();
    256 
    257     return OMF_None;
    258   }
    259 
    260   bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
    261     if ((callE = dyn_cast_or_null<CallExpr>(
    262                                      StmtMap->getParentIgnoreParenImpCasts(E))))
    263       if (FunctionDecl *
    264             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
    265         if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
    266             FD->getParent()->isTranslationUnit() &&
    267             FD->getLinkage() == ExternalLinkage)
    268           return true;
    269 
    270     return false;
    271   }
    272 
    273   bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
    274     if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
    275                                      StmtMap->getParentIgnoreParenImpCasts(E)))
    276       if (FunctionDecl *
    277             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
    278         unsigned i = 0;
    279         for (unsigned e = callE->getNumArgs(); i != e; ++i) {
    280           Expr *arg = callE->getArg(i);
    281           if (arg == E || arg->IgnoreParenImpCasts() == E)
    282             break;
    283         }
    284         if (i < callE->getNumArgs()) {
    285           ParmVarDecl *PD = FD->getParamDecl(i);
    286           if (PD->getAttr<CFConsumedAttr>()) {
    287             isConsumed = true;
    288             return true;
    289           }
    290         }
    291       }
    292 
    293     return false;
    294   }
    295 
    296   bool isSelf(Expr *E) const {
    297     E = E->IgnoreParenLValueCasts();
    298     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    299       if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
    300         if (IPD->getIdentifier() == SelfII)
    301           return true;
    302 
    303     return false;
    304   }
    305 };
    306 
    307 } // end anonymous namespace
    308 
    309 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
    310   BodyTransform<UnbridgedCastRewriter> trans(pass);
    311   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    312 }
    313