clang API Documentation
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 }