blob: 55518d12666b5784c28acb49ec6049788a499f0f [file] [log] [blame]
Benjamin Kramerd81108f2012-11-14 15:08:31 +00001//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +00002//
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,
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +000015// __bridge/CFBridgingRelease is used.
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000016//
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);
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +000024// NSString *_uuidString = (NSString *)
25// CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000026//
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"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000037#include "clang/AST/ASTContext.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000038#include "clang/AST/Attr.h"
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000039#include "clang/AST/ParentMap.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000040#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000041#include "clang/Basic/SourceManager.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000042#include "clang/Lex/Lexer.h"
43#include "clang/Sema/SemaDiagnostic.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000044#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000045
46using namespace clang;
47using namespace arcmt;
48using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000049
50namespace {
51
52class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
53 MigrationPass &Pass;
54 IdentifierInfo *SelfII;
Dylan Noblesmithe2778992012-02-05 02:12:40 +000055 OwningPtr<ParentMap> StmtMap;
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000056 Decl *ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000057
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000058public:
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000059 UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000060 SelfII = &Pass.Ctx.Idents.get("self");
61 }
62
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000063 void transformBody(Stmt *body, Decl *ParentD) {
64 this->ParentD = ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000065 StmtMap.reset(new ParentMap(body));
66 TraverseStmt(body);
67 }
68
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000069 bool VisitCastExpr(CastExpr *E) {
John McCall9320b872011-09-09 05:25:32 +000070 if (E->getCastKind() != CK_CPointerToObjCPointerCast
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000071 && E->getCastKind() != CK_BitCast)
72 return true;
73
74 QualType castType = E->getType();
75 Expr *castExpr = E->getSubExpr();
76 QualType castExprType = castExpr->getType();
77
78 if (castType->isObjCObjectPointerType() &&
79 castExprType->isObjCObjectPointerType())
80 return true;
81 if (!castType->isObjCObjectPointerType() &&
82 !castExprType->isObjCObjectPointerType())
83 return true;
84
85 bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
86 bool castRetainable = castType->isObjCIndirectLifetimeType();
87 if (exprRetainable == castRetainable) return true;
88
89 if (castExpr->isNullPointerConstant(Pass.Ctx,
90 Expr::NPC_ValueDependentIsNull))
91 return true;
92
93 SourceLocation loc = castExpr->getExprLoc();
94 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
95 return true;
96
97 if (castType->isObjCObjectPointerType())
98 transformNonObjCToObjCCast(E);
99 else
100 transformObjCToNonObjCCast(E);
101
102 return true;
103 }
104
105private:
106 void transformNonObjCToObjCCast(CastExpr *E) {
107 if (!E) return;
108
109 // Global vars are assumed that are cast as unretained.
110 if (isGlobalVar(E))
111 if (E->getSubExpr()->getType()->isPointerType()) {
112 castToObjCObject(E, /*retained=*/false);
113 return;
114 }
115
116 // If the cast is directly over the result of a Core Foundation function
117 // try to figure out whether it should be cast as retained or unretained.
118 Expr *inner = E->IgnoreParenCasts();
119 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
120 if (FunctionDecl *FD = callE->getDirectCallee()) {
121 if (FD->getAttr<CFReturnsRetainedAttr>()) {
122 castToObjCObject(E, /*retained=*/true);
123 return;
124 }
125 if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
126 castToObjCObject(E, /*retained=*/false);
127 return;
128 }
129 if (FD->isGlobal() &&
130 FD->getIdentifier() &&
131 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
132 FD->getIdentifier()->getName())) {
133 StringRef fname = FD->getIdentifier()->getName();
134 if (fname.endswith("Retain") ||
135 fname.find("Create") != StringRef::npos ||
136 fname.find("Copy") != StringRef::npos) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000137 // Do not migrate to couple of bridge transfer casts which
138 // cancel each other out. Leave it unchanged so error gets user
139 // attention instead.
140 if (FD->getName() == "CFRetain" &&
141 FD->getNumParams() == 1 &&
142 FD->getParent()->isTranslationUnit() &&
143 FD->getLinkage() == ExternalLinkage) {
144 Expr *Arg = callE->getArg(0);
Fariborz Jahaniana1c1b152012-01-31 22:09:44 +0000145 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000146 const Expr *sub = ICE->getSubExpr();
147 QualType T = sub->getType();
148 if (T->isObjCObjectPointerType())
149 return;
150 }
151 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000152 castToObjCObject(E, /*retained=*/true);
153 return;
154 }
155
156 if (fname.find("Get") != StringRef::npos) {
157 castToObjCObject(E, /*retained=*/false);
158 return;
159 }
160 }
161 }
162 }
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +0000163
164 // If returning an ivar or a member of an ivar from a +0 method, use
165 // a __bridge cast.
166 Expr *base = inner->IgnoreParenImpCasts();
167 while (isa<MemberExpr>(base))
168 base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
169 if (isa<ObjCIvarRefExpr>(base) &&
170 isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
171 if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
172 if (!method->hasAttr<NSReturnsRetainedAttr>()) {
173 castToObjCObject(E, /*retained=*/false);
174 return;
175 }
176 }
177 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000178 }
179
180 void castToObjCObject(CastExpr *E, bool retained) {
181 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
182 }
183
184 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000185 Transaction Trans(Pass.TA);
186 rewriteToBridgedCast(E, Kind, Trans);
187 }
188
189 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
190 Transaction &Trans) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000191 TransformActions &TA = Pass.TA;
192
193 // We will remove the compiler diagnostic.
194 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
195 diag::err_arc_cast_requires_bridge,
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000196 E->getLocStart())) {
197 Trans.abort();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000198 return;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000199 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000200
201 StringRef bridge;
202 switch(Kind) {
203 case OBC_Bridge:
204 bridge = "__bridge "; break;
205 case OBC_BridgeTransfer:
206 bridge = "__bridge_transfer "; break;
207 case OBC_BridgeRetained:
208 bridge = "__bridge_retained "; break;
209 }
210
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000211 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
212 diag::err_arc_cast_requires_bridge,
213 E->getLocStart());
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000214 if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
215 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
216 TA.insertAfterToken(CCE->getLParenLoc(), bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000217 } else {
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000218 SourceLocation insertLoc = E->getSubExpr()->getLocStart();
219 SmallString<128> newCast;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000220 newCast += '(';
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000221 newCast += bridge;
222 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
223 newCast += ')';
224
225 if (isa<ParenExpr>(E->getSubExpr())) {
226 TA.insert(insertLoc, newCast.str());
227 } else {
228 newCast += '(';
229 TA.insert(insertLoc, newCast.str());
230 TA.insertAfterToken(E->getLocEnd(), ")");
231 }
232 }
233 } else {
234 assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
Jordan Rose288c4212012-06-07 01:10:31 +0000235 SmallString<32> BridgeCall;
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000236
237 Expr *WrapE = E->getSubExpr();
Jordan Rose288c4212012-06-07 01:10:31 +0000238 SourceLocation InsertLoc = WrapE->getLocStart();
239
240 SourceManager &SM = Pass.Ctx.getSourceManager();
241 char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
242 if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
243 BridgeCall += ' ';
244
245 if (Kind == OBC_BridgeTransfer)
246 BridgeCall += "CFBridgingRelease";
247 else
248 BridgeCall += "CFBridgingRetain";
249
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000250 if (isa<ParenExpr>(WrapE)) {
Jordan Rose288c4212012-06-07 01:10:31 +0000251 TA.insert(InsertLoc, BridgeCall);
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000252 } else {
Jordan Rose288c4212012-06-07 01:10:31 +0000253 BridgeCall += '(';
254 TA.insert(InsertLoc, BridgeCall);
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000255 TA.insertAfterToken(WrapE->getLocEnd(), ")");
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000256 }
257 }
258 }
259
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000260 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
261 Transaction Trans(Pass.TA);
262 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
263 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
264 }
265
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000266 void transformObjCToNonObjCCast(CastExpr *E) {
267 if (isSelf(E->getSubExpr()))
268 return rewriteToBridgedCast(E, OBC_Bridge);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000269
270 CallExpr *callE;
271 if (isPassedToCFRetain(E, callE))
272 return rewriteCastForCFRetain(E, callE);
273
274 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
275 if (family == OMF_retain)
276 return rewriteToBridgedCast(E, OBC_BridgeRetained);
277
278 if (family == OMF_autorelease || family == OMF_release) {
279 std::string err = "it is not safe to cast to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000280 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000281 err += "' the result of '";
282 err += family == OMF_autorelease ? "autorelease" : "release";
283 err += "' message; a __bridge cast may result in a pointer to a "
284 "destroyed object and a __bridge_retained may leak the object";
285 Pass.TA.reportError(err, E->getLocStart(),
286 E->getSubExpr()->getSourceRange());
287 Stmt *parent = E;
288 do {
289 parent = StmtMap->getParentIgnoreParenImpCasts(parent);
290 } while (parent && isa<ExprWithCleanups>(parent));
291
292 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
293 std::string note = "remove the cast and change return type of function "
294 "to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000295 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000296 note += "' to have the object automatically autoreleased";
297 Pass.TA.reportNote(note, retS->getLocStart());
298 }
299 }
300
John McCallfe96e0b2011-11-06 09:01:30 +0000301 Expr *subExpr = E->getSubExpr();
302
303 // Look through pseudo-object expressions.
304 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
305 subExpr = pseudo->getResultExpr();
306 assert(subExpr && "no result for pseudo-object of non-void type?");
307 }
308
309 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
John McCall2d637d22011-09-10 06:18:15 +0000310 if (implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000311 return rewriteToBridgedCast(E, OBC_BridgeRetained);
John McCall2d637d22011-09-10 06:18:15 +0000312 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000313 return rewriteToBridgedCast(E, OBC_Bridge);
314 }
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000315
316 bool isConsumed = false;
317 if (isPassedToCParamWithKnownOwnership(E, isConsumed))
318 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
319 : OBC_Bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000320 }
321
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000322 static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
323 E = E->IgnoreParenCasts();
324 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
325 return ME->getMethodFamily();
326
327 return OMF_None;
328 }
329
330 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
331 if ((callE = dyn_cast_or_null<CallExpr>(
332 StmtMap->getParentIgnoreParenImpCasts(E))))
333 if (FunctionDecl *
334 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
335 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
336 FD->getParent()->isTranslationUnit() &&
337 FD->getLinkage() == ExternalLinkage)
338 return true;
339
340 return false;
341 }
342
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000343 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
344 if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
345 StmtMap->getParentIgnoreParenImpCasts(E)))
346 if (FunctionDecl *
347 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
348 unsigned i = 0;
349 for (unsigned e = callE->getNumArgs(); i != e; ++i) {
350 Expr *arg = callE->getArg(i);
351 if (arg == E || arg->IgnoreParenImpCasts() == E)
352 break;
353 }
354 if (i < callE->getNumArgs()) {
355 ParmVarDecl *PD = FD->getParamDecl(i);
356 if (PD->getAttr<CFConsumedAttr>()) {
357 isConsumed = true;
358 return true;
359 }
360 }
361 }
362
363 return false;
364 }
365
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000366 bool isSelf(Expr *E) const {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000367 E = E->IgnoreParenLValueCasts();
368 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000369 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
370 if (IPD->getIdentifier() == SelfII)
371 return true;
372
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000373 return false;
374 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000375};
376
377} // end anonymous namespace
378
379void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000380 BodyTransform<UnbridgedCastRewriter> trans(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000381 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
382}