TransUnbridgedCasts.cpp revision 239462
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/CFBridgingRelease 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 = (NSString *) 25// CFBridgingRelease(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/AST/ASTContext.h" 39#include "clang/AST/ParentMap.h" 40#include "clang/Basic/SourceManager.h" 41#include "clang/Lex/Lexer.h" 42#include "clang/Sema/SemaDiagnostic.h" 43#include "llvm/ADT/SmallString.h" 44 45using namespace clang; 46using namespace arcmt; 47using namespace trans; 48 49namespace { 50 51class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ 52 MigrationPass &Pass; 53 IdentifierInfo *SelfII; 54 OwningPtr<ParentMap> StmtMap; 55 Decl *ParentD; 56 57public: 58 UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) { 59 SelfII = &Pass.Ctx.Idents.get("self"); 60 } 61 62 void transformBody(Stmt *body, Decl *ParentD) { 63 this->ParentD = ParentD; 64 StmtMap.reset(new ParentMap(body)); 65 TraverseStmt(body); 66 } 67 68 bool VisitCastExpr(CastExpr *E) { 69 if (E->getCastKind() != CK_CPointerToObjCPointerCast 70 && E->getCastKind() != CK_BitCast) 71 return true; 72 73 QualType castType = E->getType(); 74 Expr *castExpr = E->getSubExpr(); 75 QualType castExprType = castExpr->getType(); 76 77 if (castType->isObjCObjectPointerType() && 78 castExprType->isObjCObjectPointerType()) 79 return true; 80 if (!castType->isObjCObjectPointerType() && 81 !castExprType->isObjCObjectPointerType()) 82 return true; 83 84 bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); 85 bool castRetainable = castType->isObjCIndirectLifetimeType(); 86 if (exprRetainable == castRetainable) return true; 87 88 if (castExpr->isNullPointerConstant(Pass.Ctx, 89 Expr::NPC_ValueDependentIsNull)) 90 return true; 91 92 SourceLocation loc = castExpr->getExprLoc(); 93 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) 94 return true; 95 96 if (castType->isObjCObjectPointerType()) 97 transformNonObjCToObjCCast(E); 98 else 99 transformObjCToNonObjCCast(E); 100 101 return true; 102 } 103 104private: 105 void transformNonObjCToObjCCast(CastExpr *E) { 106 if (!E) return; 107 108 // Global vars are assumed that are cast as unretained. 109 if (isGlobalVar(E)) 110 if (E->getSubExpr()->getType()->isPointerType()) { 111 castToObjCObject(E, /*retained=*/false); 112 return; 113 } 114 115 // If the cast is directly over the result of a Core Foundation function 116 // try to figure out whether it should be cast as retained or unretained. 117 Expr *inner = E->IgnoreParenCasts(); 118 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) { 119 if (FunctionDecl *FD = callE->getDirectCallee()) { 120 if (FD->getAttr<CFReturnsRetainedAttr>()) { 121 castToObjCObject(E, /*retained=*/true); 122 return; 123 } 124 if (FD->getAttr<CFReturnsNotRetainedAttr>()) { 125 castToObjCObject(E, /*retained=*/false); 126 return; 127 } 128 if (FD->isGlobal() && 129 FD->getIdentifier() && 130 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", 131 FD->getIdentifier()->getName())) { 132 StringRef fname = FD->getIdentifier()->getName(); 133 if (fname.endswith("Retain") || 134 fname.find("Create") != StringRef::npos || 135 fname.find("Copy") != StringRef::npos) { 136 // Do not migrate to couple of bridge transfer casts which 137 // cancel each other out. Leave it unchanged so error gets user 138 // attention instead. 139 if (FD->getName() == "CFRetain" && 140 FD->getNumParams() == 1 && 141 FD->getParent()->isTranslationUnit() && 142 FD->getLinkage() == ExternalLinkage) { 143 Expr *Arg = callE->getArg(0); 144 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { 145 const Expr *sub = ICE->getSubExpr(); 146 QualType T = sub->getType(); 147 if (T->isObjCObjectPointerType()) 148 return; 149 } 150 } 151 castToObjCObject(E, /*retained=*/true); 152 return; 153 } 154 155 if (fname.find("Get") != StringRef::npos) { 156 castToObjCObject(E, /*retained=*/false); 157 return; 158 } 159 } 160 } 161 } 162 163 // If returning an ivar or a member of an ivar from a +0 method, use 164 // a __bridge cast. 165 Expr *base = inner->IgnoreParenImpCasts(); 166 while (isa<MemberExpr>(base)) 167 base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts(); 168 if (isa<ObjCIvarRefExpr>(base) && 169 isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) { 170 if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) { 171 if (!method->hasAttr<NSReturnsRetainedAttr>()) { 172 castToObjCObject(E, /*retained=*/false); 173 return; 174 } 175 } 176 } 177 } 178 179 void castToObjCObject(CastExpr *E, bool retained) { 180 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge); 181 } 182 183 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { 184 Transaction Trans(Pass.TA); 185 rewriteToBridgedCast(E, Kind, Trans); 186 } 187 188 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, 189 Transaction &Trans) { 190 TransformActions &TA = Pass.TA; 191 192 // We will remove the compiler diagnostic. 193 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, 194 diag::err_arc_cast_requires_bridge, 195 E->getLocStart())) { 196 Trans.abort(); 197 return; 198 } 199 200 StringRef bridge; 201 switch(Kind) { 202 case OBC_Bridge: 203 bridge = "__bridge "; break; 204 case OBC_BridgeTransfer: 205 bridge = "__bridge_transfer "; break; 206 case OBC_BridgeRetained: 207 bridge = "__bridge_retained "; break; 208 } 209 210 TA.clearDiagnostic(diag::err_arc_mismatched_cast, 211 diag::err_arc_cast_requires_bridge, 212 E->getLocStart()); 213 if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) { 214 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) { 215 TA.insertAfterToken(CCE->getLParenLoc(), bridge); 216 } else { 217 SourceLocation insertLoc = E->getSubExpr()->getLocStart(); 218 SmallString<128> newCast; 219 newCast += '('; 220 newCast += bridge; 221 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 222 newCast += ')'; 223 224 if (isa<ParenExpr>(E->getSubExpr())) { 225 TA.insert(insertLoc, newCast.str()); 226 } else { 227 newCast += '('; 228 TA.insert(insertLoc, newCast.str()); 229 TA.insertAfterToken(E->getLocEnd(), ")"); 230 } 231 } 232 } else { 233 assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained); 234 SmallString<32> BridgeCall; 235 236 Expr *WrapE = E->getSubExpr(); 237 SourceLocation InsertLoc = WrapE->getLocStart(); 238 239 SourceManager &SM = Pass.Ctx.getSourceManager(); 240 char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1)); 241 if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts())) 242 BridgeCall += ' '; 243 244 if (Kind == OBC_BridgeTransfer) 245 BridgeCall += "CFBridgingRelease"; 246 else 247 BridgeCall += "CFBridgingRetain"; 248 249 if (isa<ParenExpr>(WrapE)) { 250 TA.insert(InsertLoc, BridgeCall); 251 } else { 252 BridgeCall += '('; 253 TA.insert(InsertLoc, BridgeCall); 254 TA.insertAfterToken(WrapE->getLocEnd(), ")"); 255 } 256 } 257 } 258 259 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { 260 Transaction Trans(Pass.TA); 261 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); 262 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); 263 } 264 265 void transformObjCToNonObjCCast(CastExpr *E) { 266 if (isSelf(E->getSubExpr())) 267 return rewriteToBridgedCast(E, OBC_Bridge); 268 269 CallExpr *callE; 270 if (isPassedToCFRetain(E, callE)) 271 return rewriteCastForCFRetain(E, callE); 272 273 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); 274 if (family == OMF_retain) 275 return rewriteToBridgedCast(E, OBC_BridgeRetained); 276 277 if (family == OMF_autorelease || family == OMF_release) { 278 std::string err = "it is not safe to cast to '"; 279 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 280 err += "' the result of '"; 281 err += family == OMF_autorelease ? "autorelease" : "release"; 282 err += "' message; a __bridge cast may result in a pointer to a " 283 "destroyed object and a __bridge_retained may leak the object"; 284 Pass.TA.reportError(err, E->getLocStart(), 285 E->getSubExpr()->getSourceRange()); 286 Stmt *parent = E; 287 do { 288 parent = StmtMap->getParentIgnoreParenImpCasts(parent); 289 } while (parent && isa<ExprWithCleanups>(parent)); 290 291 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) { 292 std::string note = "remove the cast and change return type of function " 293 "to '"; 294 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); 295 note += "' to have the object automatically autoreleased"; 296 Pass.TA.reportNote(note, retS->getLocStart()); 297 } 298 } 299 300 Expr *subExpr = E->getSubExpr(); 301 302 // Look through pseudo-object expressions. 303 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) { 304 subExpr = pseudo->getResultExpr(); 305 assert(subExpr && "no result for pseudo-object of non-void type?"); 306 } 307 308 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) { 309 if (implCE->getCastKind() == CK_ARCConsumeObject) 310 return rewriteToBridgedCast(E, OBC_BridgeRetained); 311 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject) 312 return rewriteToBridgedCast(E, OBC_Bridge); 313 } 314 315 bool isConsumed = false; 316 if (isPassedToCParamWithKnownOwnership(E, isConsumed)) 317 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained 318 : OBC_Bridge); 319 } 320 321 static ObjCMethodFamily getFamilyOfMessage(Expr *E) { 322 E = E->IgnoreParenCasts(); 323 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) 324 return ME->getMethodFamily(); 325 326 return OMF_None; 327 } 328 329 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { 330 if ((callE = dyn_cast_or_null<CallExpr>( 331 StmtMap->getParentIgnoreParenImpCasts(E)))) 332 if (FunctionDecl * 333 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) 334 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && 335 FD->getParent()->isTranslationUnit() && 336 FD->getLinkage() == ExternalLinkage) 337 return true; 338 339 return false; 340 } 341 342 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { 343 if (CallExpr *callE = dyn_cast_or_null<CallExpr>( 344 StmtMap->getParentIgnoreParenImpCasts(E))) 345 if (FunctionDecl * 346 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { 347 unsigned i = 0; 348 for (unsigned e = callE->getNumArgs(); i != e; ++i) { 349 Expr *arg = callE->getArg(i); 350 if (arg == E || arg->IgnoreParenImpCasts() == E) 351 break; 352 } 353 if (i < callE->getNumArgs()) { 354 ParmVarDecl *PD = FD->getParamDecl(i); 355 if (PD->getAttr<CFConsumedAttr>()) { 356 isConsumed = true; 357 return true; 358 } 359 } 360 } 361 362 return false; 363 } 364 365 bool isSelf(Expr *E) const { 366 E = E->IgnoreParenLValueCasts(); 367 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 368 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) 369 if (IPD->getIdentifier() == SelfII) 370 return true; 371 372 return false; 373 } 374}; 375 376} // end anonymous namespace 377 378void trans::rewriteUnbridgedCasts(MigrationPass &pass) { 379 BodyTransform<UnbridgedCastRewriter> trans(pass); 380 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 381} 382