TransUnbridgedCasts.cpp revision 2908ffbc5f54323f150405fa2b06f50788ae55c7
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 42using namespace clang; 43using namespace arcmt; 44using namespace trans; 45 46namespace { 47 48class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ 49 MigrationPass &Pass; 50 IdentifierInfo *SelfII; 51 llvm::OwningPtr<ParentMap> StmtMap; 52 53public: 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 99private: 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 // Do not migrate to couple of bridge transfer casts which 132 // cancel each other out. Leave it unchanged so error gets user 133 // attention instead. 134 if (FD->getName() == "CFRetain" && 135 FD->getNumParams() == 1 && 136 FD->getParent()->isTranslationUnit() && 137 FD->getLinkage() == ExternalLinkage) { 138 Expr *Arg = callE->getArg(0); 139 if (const CastExpr *ICE = dyn_cast<CastExpr>(Arg)) { 140 const Expr *sub = ICE->getSubExpr(); 141 QualType T = sub->getType(); 142 if (T->isObjCObjectPointerType()) 143 return; 144 } 145 } 146 castToObjCObject(E, /*retained=*/true); 147 return; 148 } 149 150 if (fname.find("Get") != StringRef::npos) { 151 castToObjCObject(E, /*retained=*/false); 152 return; 153 } 154 } 155 } 156 } 157 } 158 159 void castToObjCObject(CastExpr *E, bool retained) { 160 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge); 161 } 162 163 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { 164 Transaction Trans(Pass.TA); 165 rewriteToBridgedCast(E, Kind, Trans); 166 } 167 168 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, 169 Transaction &Trans) { 170 TransformActions &TA = Pass.TA; 171 172 // We will remove the compiler diagnostic. 173 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, 174 diag::err_arc_cast_requires_bridge, 175 E->getLocStart())) { 176 Trans.abort(); 177 return; 178 } 179 180 StringRef bridge; 181 switch(Kind) { 182 case OBC_Bridge: 183 bridge = "__bridge "; break; 184 case OBC_BridgeTransfer: 185 bridge = "__bridge_transfer "; break; 186 case OBC_BridgeRetained: 187 bridge = "__bridge_retained "; break; 188 } 189 190 TA.clearDiagnostic(diag::err_arc_mismatched_cast, 191 diag::err_arc_cast_requires_bridge, 192 E->getLocStart()); 193 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) { 194 TA.insertAfterToken(CCE->getLParenLoc(), bridge); 195 } else { 196 SourceLocation insertLoc = E->getSubExpr()->getLocStart(); 197 llvm::SmallString<128> newCast; 198 newCast += '('; 199 newCast += bridge; 200 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 201 newCast += ')'; 202 203 if (isa<ParenExpr>(E->getSubExpr())) { 204 TA.insert(insertLoc, newCast.str()); 205 } else { 206 newCast += '('; 207 TA.insert(insertLoc, newCast.str()); 208 TA.insertAfterToken(E->getLocEnd(), ")"); 209 } 210 } 211 } 212 213 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { 214 Transaction Trans(Pass.TA); 215 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); 216 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); 217 } 218 219 void transformObjCToNonObjCCast(CastExpr *E) { 220 if (isSelf(E->getSubExpr())) 221 return rewriteToBridgedCast(E, OBC_Bridge); 222 223 CallExpr *callE; 224 if (isPassedToCFRetain(E, callE)) 225 return rewriteCastForCFRetain(E, callE); 226 227 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); 228 if (family == OMF_retain) 229 return rewriteToBridgedCast(E, OBC_BridgeRetained); 230 231 if (family == OMF_autorelease || family == OMF_release) { 232 std::string err = "it is not safe to cast to '"; 233 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 234 err += "' the result of '"; 235 err += family == OMF_autorelease ? "autorelease" : "release"; 236 err += "' message; a __bridge cast may result in a pointer to a " 237 "destroyed object and a __bridge_retained may leak the object"; 238 Pass.TA.reportError(err, E->getLocStart(), 239 E->getSubExpr()->getSourceRange()); 240 Stmt *parent = E; 241 do { 242 parent = StmtMap->getParentIgnoreParenImpCasts(parent); 243 } while (parent && isa<ExprWithCleanups>(parent)); 244 245 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { 246 std::string note = "remove the cast and change return type of function " 247 "to '"; 248 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 249 note += "' to have the object automatically autoreleased"; 250 Pass.TA.reportNote(note, retS->getLocStart()); 251 } 252 } 253 254 Expr *subExpr = E->getSubExpr(); 255 256 // Look through pseudo-object expressions. 257 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) { 258 subExpr = pseudo->getResultExpr(); 259 assert(subExpr && "no result for pseudo-object of non-void type?"); 260 } 261 262 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) { 263 if (implCE->getCastKind() == CK_ARCConsumeObject) 264 return rewriteToBridgedCast(E, OBC_BridgeRetained); 265 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) 266 return rewriteToBridgedCast(E, OBC_Bridge); 267 } 268 269 bool isConsumed = false; 270 if (isPassedToCParamWithKnownOwnership(E, isConsumed)) 271 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained 272 : OBC_Bridge); 273 } 274 275 static ObjCMethodFamily getFamilyOfMessage(Expr *E) { 276 E = E->IgnoreParenCasts(); 277 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) 278 return ME->getMethodFamily(); 279 280 return OMF_None; 281 } 282 283 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { 284 if ((callE = dyn_cast_or_null<CallExpr>( 285 StmtMap->getParentIgnoreParenImpCasts(E)))) 286 if (FunctionDecl * 287 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) 288 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && 289 FD->getParent()->isTranslationUnit() && 290 FD->getLinkage() == ExternalLinkage) 291 return true; 292 293 return false; 294 } 295 296 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { 297 if (CallExpr *callE = dyn_cast_or_null<CallExpr>( 298 StmtMap->getParentIgnoreParenImpCasts(E))) 299 if (FunctionDecl * 300 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { 301 unsigned i = 0; 302 for (unsigned e = callE->getNumArgs(); i != e; ++i) { 303 Expr *arg = callE->getArg(i); 304 if (arg == E || arg->IgnoreParenImpCasts() == E) 305 break; 306 } 307 if (i < callE->getNumArgs()) { 308 ParmVarDecl *PD = FD->getParamDecl(i); 309 if (PD->getAttr<CFConsumedAttr>()) { 310 isConsumed = true; 311 return true; 312 } 313 } 314 } 315 316 return false; 317 } 318 319 bool isSelf(Expr *E) const { 320 E = E->IgnoreParenLValueCasts(); 321 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 322 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) 323 if (IPD->getIdentifier() == SelfII) 324 return true; 325 326 return false; 327 } 328}; 329 330} // end anonymous namespace 331 332void trans::rewriteUnbridgedCasts(MigrationPass &pass) { 333 BodyTransform<UnbridgedCastRewriter> trans(pass); 334 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 335} 336