clang API Documentation

TransUnbridgedCasts.cpp
Go to the documentation of this file.
00001 //===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // rewriteUnbridgedCasts:
00011 //
00012 // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
00013 // is from a file-level variable, __bridge cast is used to convert it.
00014 // For the result of a function call that we know is +1/+0,
00015 // __bridge/__bridge_transfer is used.
00016 //
00017 //  NSString *str = (NSString *)kUTTypePlainText;
00018 //  str = b ? kUTTypeRTF : kUTTypePlainText;
00019 //  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
00020 //                                                         _uuid);
00021 // ---->
00022 //  NSString *str = (__bridge NSString *)kUTTypePlainText;
00023 //  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
00024 // NSString *_uuidString = (__bridge_transfer NSString *)
00025 //                               CFUUIDCreateString(kCFAllocatorDefault, _uuid);
00026 //
00027 // For a C pointer to ObjC, for casting 'self', __bridge is used.
00028 //
00029 //  CFStringRef str = (CFStringRef)self;
00030 // ---->
00031 //  CFStringRef str = (__bridge CFStringRef)self;
00032 //
00033 //===----------------------------------------------------------------------===//
00034 
00035 #include "Transforms.h"
00036 #include "Internals.h"
00037 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
00038 #include "clang/Sema/SemaDiagnostic.h"
00039 #include "clang/AST/ParentMap.h"
00040 #include "clang/Basic/SourceManager.h"
00041 #include "llvm/ADT/SmallString.h"
00042 
00043 using namespace clang;
00044 using namespace arcmt;
00045 using namespace trans;
00046 
00047 namespace {
00048 
00049 class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
00050   MigrationPass &Pass;
00051   IdentifierInfo *SelfII;
00052   OwningPtr<ParentMap> StmtMap;
00053 
00054 public:
00055   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
00056     SelfII = &Pass.Ctx.Idents.get("self");
00057   }
00058 
00059   void transformBody(Stmt *body) {
00060     StmtMap.reset(new ParentMap(body));
00061     TraverseStmt(body);
00062   }
00063 
00064   bool VisitCastExpr(CastExpr *E) {
00065     if (E->getCastKind() != CK_CPointerToObjCPointerCast
00066         && E->getCastKind() != CK_BitCast)
00067       return true;
00068 
00069     QualType castType = E->getType();
00070     Expr *castExpr = E->getSubExpr();
00071     QualType castExprType = castExpr->getType();
00072 
00073     if (castType->isObjCObjectPointerType() &&
00074         castExprType->isObjCObjectPointerType())
00075       return true;
00076     if (!castType->isObjCObjectPointerType() &&
00077         !castExprType->isObjCObjectPointerType())
00078       return true;
00079     
00080     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
00081     bool castRetainable = castType->isObjCIndirectLifetimeType();
00082     if (exprRetainable == castRetainable) return true;
00083 
00084     if (castExpr->isNullPointerConstant(Pass.Ctx,
00085                                         Expr::NPC_ValueDependentIsNull))
00086       return true;
00087 
00088     SourceLocation loc = castExpr->getExprLoc();
00089     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
00090       return true;
00091 
00092     if (castType->isObjCObjectPointerType())
00093       transformNonObjCToObjCCast(E);
00094     else
00095       transformObjCToNonObjCCast(E);
00096 
00097     return true;
00098   }
00099 
00100 private:
00101   void transformNonObjCToObjCCast(CastExpr *E) {
00102     if (!E) return;
00103 
00104     // Global vars are assumed that are cast as unretained.
00105     if (isGlobalVar(E))
00106       if (E->getSubExpr()->getType()->isPointerType()) {
00107         castToObjCObject(E, /*retained=*/false);
00108         return;
00109       }
00110 
00111     // If the cast is directly over the result of a Core Foundation function
00112     // try to figure out whether it should be cast as retained or unretained.
00113     Expr *inner = E->IgnoreParenCasts();
00114     if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
00115       if (FunctionDecl *FD = callE->getDirectCallee()) {
00116         if (FD->getAttr<CFReturnsRetainedAttr>()) {
00117           castToObjCObject(E, /*retained=*/true);
00118           return;
00119         }
00120         if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
00121           castToObjCObject(E, /*retained=*/false);
00122           return;
00123         }
00124         if (FD->isGlobal() &&
00125             FD->getIdentifier() &&
00126             ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
00127                                    FD->getIdentifier()->getName())) {
00128           StringRef fname = FD->getIdentifier()->getName();
00129           if (fname.endswith("Retain") ||
00130               fname.find("Create") != StringRef::npos ||
00131               fname.find("Copy") != StringRef::npos) {
00132             // Do not migrate to couple of bridge transfer casts which
00133             // cancel each other out. Leave it unchanged so error gets user
00134             // attention instead.
00135             if (FD->getName() == "CFRetain" && 
00136                 FD->getNumParams() == 1 &&
00137                 FD->getParent()->isTranslationUnit() &&
00138                 FD->getLinkage() == ExternalLinkage) {
00139               Expr *Arg = callE->getArg(0);
00140               if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
00141                 const Expr *sub = ICE->getSubExpr();
00142                 QualType T = sub->getType();
00143                 if (T->isObjCObjectPointerType())
00144                   return;
00145               }
00146             }
00147             castToObjCObject(E, /*retained=*/true);
00148             return;
00149           }
00150 
00151           if (fname.find("Get") != StringRef::npos) {
00152             castToObjCObject(E, /*retained=*/false);
00153             return;
00154           }
00155         }
00156       }
00157     }
00158   }
00159 
00160   void castToObjCObject(CastExpr *E, bool retained) {
00161     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
00162   }
00163 
00164   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
00165     Transaction Trans(Pass.TA);
00166     rewriteToBridgedCast(E, Kind, Trans);
00167   }
00168 
00169   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
00170                             Transaction &Trans) {
00171     TransformActions &TA = Pass.TA;
00172 
00173     // We will remove the compiler diagnostic.
00174     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
00175                           diag::err_arc_cast_requires_bridge,
00176                           E->getLocStart())) {
00177       Trans.abort();
00178       return;
00179     }
00180 
00181     StringRef bridge;
00182     switch(Kind) {
00183     case OBC_Bridge:
00184       bridge = "__bridge "; break;
00185     case OBC_BridgeTransfer:
00186       bridge = "__bridge_transfer "; break;
00187     case OBC_BridgeRetained:
00188       bridge = "__bridge_retained "; break;
00189     }
00190 
00191     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
00192                        diag::err_arc_cast_requires_bridge,
00193                        E->getLocStart());
00194     if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
00195       TA.insertAfterToken(CCE->getLParenLoc(), bridge);
00196     } else {
00197       SourceLocation insertLoc = E->getSubExpr()->getLocStart();
00198       SmallString<128> newCast;
00199       newCast += '(';
00200       newCast += bridge;
00201       newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
00202       newCast += ')';
00203 
00204       if (isa<ParenExpr>(E->getSubExpr())) {
00205         TA.insert(insertLoc, newCast.str());
00206       } else {
00207         newCast += '(';
00208         TA.insert(insertLoc, newCast.str());
00209         TA.insertAfterToken(E->getLocEnd(), ")");
00210       }
00211     }
00212   }
00213 
00214   void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
00215     Transaction Trans(Pass.TA);
00216     Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
00217     rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
00218   }
00219 
00220   void transformObjCToNonObjCCast(CastExpr *E) {
00221     if (isSelf(E->getSubExpr()))
00222       return rewriteToBridgedCast(E, OBC_Bridge);
00223 
00224     CallExpr *callE;
00225     if (isPassedToCFRetain(E, callE))
00226       return rewriteCastForCFRetain(E, callE);
00227 
00228     ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
00229     if (family == OMF_retain)
00230       return rewriteToBridgedCast(E, OBC_BridgeRetained);
00231 
00232     if (family == OMF_autorelease || family == OMF_release) {
00233       std::string err = "it is not safe to cast to '";
00234       err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
00235       err += "' the result of '";
00236       err += family == OMF_autorelease ? "autorelease" : "release";
00237       err += "' message; a __bridge cast may result in a pointer to a "
00238           "destroyed object and a __bridge_retained may leak the object";
00239       Pass.TA.reportError(err, E->getLocStart(),
00240                           E->getSubExpr()->getSourceRange());
00241       Stmt *parent = E;
00242       do {
00243         parent = StmtMap->getParentIgnoreParenImpCasts(parent);
00244       } while (parent && isa<ExprWithCleanups>(parent));
00245 
00246       if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
00247         std::string note = "remove the cast and change return type of function "
00248             "to '";
00249         note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
00250         note += "' to have the object automatically autoreleased";
00251         Pass.TA.reportNote(note, retS->getLocStart());
00252       }
00253     }
00254 
00255     Expr *subExpr = E->getSubExpr();
00256 
00257     // Look through pseudo-object expressions.
00258     if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
00259       subExpr = pseudo->getResultExpr();
00260       assert(subExpr && "no result for pseudo-object of non-void type?");
00261     }
00262 
00263     if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
00264       if (implCE->getCastKind() == CK_ARCConsumeObject)
00265         return rewriteToBridgedCast(E, OBC_BridgeRetained);
00266       if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
00267         return rewriteToBridgedCast(E, OBC_Bridge);
00268     }
00269 
00270     bool isConsumed = false;
00271     if (isPassedToCParamWithKnownOwnership(E, isConsumed))
00272       return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
00273                                                 : OBC_Bridge);
00274   }
00275 
00276   static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
00277     E = E->IgnoreParenCasts();
00278     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
00279       return ME->getMethodFamily();
00280 
00281     return OMF_None;
00282   }
00283 
00284   bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
00285     if ((callE = dyn_cast_or_null<CallExpr>(
00286                                      StmtMap->getParentIgnoreParenImpCasts(E))))
00287       if (FunctionDecl *
00288             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
00289         if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
00290             FD->getParent()->isTranslationUnit() &&
00291             FD->getLinkage() == ExternalLinkage)
00292           return true;
00293 
00294     return false;
00295   }
00296 
00297   bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
00298     if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
00299                                      StmtMap->getParentIgnoreParenImpCasts(E)))
00300       if (FunctionDecl *
00301             FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
00302         unsigned i = 0;
00303         for (unsigned e = callE->getNumArgs(); i != e; ++i) {
00304           Expr *arg = callE->getArg(i);
00305           if (arg == E || arg->IgnoreParenImpCasts() == E)
00306             break;
00307         }
00308         if (i < callE->getNumArgs()) {
00309           ParmVarDecl *PD = FD->getParamDecl(i);
00310           if (PD->getAttr<CFConsumedAttr>()) {
00311             isConsumed = true;
00312             return true;
00313           }
00314         }
00315       }
00316 
00317     return false;
00318   }
00319 
00320   bool isSelf(Expr *E) const {
00321     E = E->IgnoreParenLValueCasts();
00322     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
00323       if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
00324         if (IPD->getIdentifier() == SelfII)
00325           return true;
00326 
00327     return false;
00328   }
00329 };
00330 
00331 } // end anonymous namespace
00332 
00333 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
00334   BodyTransform<UnbridgedCastRewriter> trans(pass);
00335   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
00336 }