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