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/Basic/SourceManager.h"
     40 
     41 using namespace clang;
     42 using namespace arcmt;
     43 using namespace trans;
     44 using llvm::StringRef;
     45 
     46 namespace {
     47 
     48 class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
     49   MigrationPass &Pass;
     50   IdentifierInfo *SelfII;
     51 public:
     52   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
     53     SelfII = &Pass.Ctx.Idents.get("self");
     54   }
     55 
     56   bool VisitCastExpr(CastExpr *E) {
     57     if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
     58         && E->getCastKind() != CK_BitCast)
     59       return true;
     60 
     61     QualType castType = E->getType();
     62     Expr *castExpr = E->getSubExpr();
     63     QualType castExprType = castExpr->getType();
     64 
     65     if (castType->isObjCObjectPointerType() &&
     66         castExprType->isObjCObjectPointerType())
     67       return true;
     68     if (!castType->isObjCObjectPointerType() &&
     69         !castExprType->isObjCObjectPointerType())
     70       return true;
     71 
     72     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
     73     bool castRetainable = castType->isObjCIndirectLifetimeType();
     74     if (exprRetainable == castRetainable) return true;
     75 
     76     if (castExpr->isNullPointerConstant(Pass.Ctx,
     77                                         Expr::NPC_ValueDependentIsNull))
     78       return true;
     79 
     80     SourceLocation loc = castExpr->getExprLoc();
     81     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
     82       return true;
     83 
     84     if (castType->isObjCObjectPointerType())
     85       transformNonObjCToObjCCast(E);
     86     else
     87       transformObjCToNonObjCCast(E);
     88 
     89     return true;
     90   }
     91 
     92 private:
     93   void transformNonObjCToObjCCast(CastExpr *E) {
     94     if (!E) return;
     95 
     96     // Global vars are assumed that are cast as unretained.
     97     if (isGlobalVar(E))
     98       if (E->getSubExpr()->getType()->isPointerType()) {
     99         castToObjCObject(E, /*retained=*/false);
    100         return;
    101       }
    102 
    103     // If the cast is directly over the result of a Core Foundation function
    104     // try to figure out whether it should be cast as retained or unretained.
    105     Expr *inner = E->IgnoreParenCasts();
    106     if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
    107       if (FunctionDecl *FD = callE->getDirectCallee()) {
    108         if (FD->getAttr<CFReturnsRetainedAttr>()) {
    109           castToObjCObject(E, /*retained=*/true);
    110           return;
    111         }
    112         if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
    113           castToObjCObject(E, /*retained=*/false);
    114           return;
    115         }
    116         if (FD->isGlobal() &&
    117             FD->getIdentifier() &&
    118             ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
    119                                    FD->getIdentifier()->getName())) {
    120           StringRef fname = FD->getIdentifier()->getName();
    121           if (fname.endswith("Retain") ||
    122               fname.find("Create") != StringRef::npos ||
    123               fname.find("Copy") != StringRef::npos) {
    124             castToObjCObject(E, /*retained=*/true);
    125             return;
    126           }
    127 
    128           if (fname.find("Get") != StringRef::npos) {
    129             castToObjCObject(E, /*retained=*/false);
    130             return;
    131           }
    132         }
    133       }
    134     }
    135   }
    136 
    137   void castToObjCObject(CastExpr *E, bool retained) {
    138     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
    139   }
    140 
    141   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
    142     TransformActions &TA = Pass.TA;
    143 
    144     // We will remove the compiler diagnostic.
    145     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
    146                           diag::err_arc_cast_requires_bridge,
    147                           E->getLocStart()))
    148       return;
    149 
    150     StringRef bridge;
    151     switch(Kind) {
    152     case OBC_Bridge:
    153       bridge = "__bridge "; break;
    154     case OBC_BridgeTransfer:
    155       bridge = "__bridge_transfer "; break;
    156     case OBC_BridgeRetained:
    157       bridge = "__bridge_retained "; break;
    158     }
    159 
    160     Transaction Trans(TA);
    161     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
    162                        diag::err_arc_cast_requires_bridge,
    163                        E->getLocStart());
    164     if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
    165       TA.insertAfterToken(CCE->getLParenLoc(), bridge);
    166     } else {
    167       SourceLocation insertLoc = E->getSubExpr()->getLocStart();
    168       llvm::SmallString<128> newCast;
    169       newCast += '(';
    170       newCast += bridge;
    171       newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
    172       newCast += ')';
    173 
    174       if (isa<ParenExpr>(E->getSubExpr())) {
    175         TA.insert(insertLoc, newCast.str());
    176       } else {
    177         newCast += '(';
    178         TA.insert(insertLoc, newCast.str());
    179         TA.insertAfterToken(E->getLocEnd(), ")");
    180       }
    181     }
    182   }
    183 
    184   void transformObjCToNonObjCCast(CastExpr *E) {
    185     if (isSelf(E->getSubExpr()))
    186       return rewriteToBridgedCast(E, OBC_Bridge);
    187   }
    188 
    189   bool isSelf(Expr *E) {
    190     E = E->IgnoreParenLValueCasts();
    191     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
    192       if (DRE->getDecl()->getIdentifier() == SelfII)
    193         return true;
    194     return false;
    195   }
    196 };
    197 
    198 } // end anonymous namespace
    199 
    200 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
    201   UnbridgedCastRewriter trans(pass);
    202   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    203 }
    204