blob: f8bc5cf932c0e2af81dc6739cd3f85205f80c9a6 [file] [log] [blame]
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +00001//===--- 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,
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"
37#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
38#include "clang/Sema/SemaDiagnostic.h"
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000039#include "clang/AST/ParentMap.h"
Jordan Rose288c4212012-06-07 01:10:31 +000040#include "clang/Lex/Lexer.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000041#include "clang/Basic/SourceManager.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000042#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000043
44using namespace clang;
45using namespace arcmt;
46using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000047
48namespace {
49
50class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
51 MigrationPass &Pass;
52 IdentifierInfo *SelfII;
Dylan Noblesmithe2778992012-02-05 02:12:40 +000053 OwningPtr<ParentMap> StmtMap;
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000054 Decl *ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000055
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000056public:
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000057 UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000058 SelfII = &Pass.Ctx.Idents.get("self");
59 }
60
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000061 void transformBody(Stmt *body, Decl *ParentD) {
62 this->ParentD = ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000063 StmtMap.reset(new ParentMap(body));
64 TraverseStmt(body);
65 }
66
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000067 bool VisitCastExpr(CastExpr *E) {
John McCall9320b872011-09-09 05:25:32 +000068 if (E->getCastKind() != CK_CPointerToObjCPointerCast
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000069 && E->getCastKind() != CK_BitCast)
70 return true;
71
72 QualType castType = E->getType();
73 Expr *castExpr = E->getSubExpr();
74 QualType castExprType = castExpr->getType();
75
76 if (castType->isObjCObjectPointerType() &&
77 castExprType->isObjCObjectPointerType())
78 return true;
79 if (!castType->isObjCObjectPointerType() &&
80 !castExprType->isObjCObjectPointerType())
81 return true;
82
83 bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
84 bool castRetainable = castType->isObjCIndirectLifetimeType();
85 if (exprRetainable == castRetainable) return true;
86
87 if (castExpr->isNullPointerConstant(Pass.Ctx,
88 Expr::NPC_ValueDependentIsNull))
89 return true;
90
91 SourceLocation loc = castExpr->getExprLoc();
92 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
93 return true;
94
95 if (castType->isObjCObjectPointerType())
96 transformNonObjCToObjCCast(E);
97 else
98 transformObjCToNonObjCCast(E);
99
100 return true;
101 }
102
103private:
104 void transformNonObjCToObjCCast(CastExpr *E) {
105 if (!E) return;
106
107 // Global vars are assumed that are cast as unretained.
108 if (isGlobalVar(E))
109 if (E->getSubExpr()->getType()->isPointerType()) {
110 castToObjCObject(E, /*retained=*/false);
111 return;
112 }
113
114 // If the cast is directly over the result of a Core Foundation function
115 // try to figure out whether it should be cast as retained or unretained.
116 Expr *inner = E->IgnoreParenCasts();
117 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
118 if (FunctionDecl *FD = callE->getDirectCallee()) {
119 if (FD->getAttr<CFReturnsRetainedAttr>()) {
120 castToObjCObject(E, /*retained=*/true);
121 return;
122 }
123 if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
124 castToObjCObject(E, /*retained=*/false);
125 return;
126 }
127 if (FD->isGlobal() &&
128 FD->getIdentifier() &&
129 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
130 FD->getIdentifier()->getName())) {
131 StringRef fname = FD->getIdentifier()->getName();
132 if (fname.endswith("Retain") ||
133 fname.find("Create") != StringRef::npos ||
134 fname.find("Copy") != StringRef::npos) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000135 // Do not migrate to couple of bridge transfer casts which
136 // cancel each other out. Leave it unchanged so error gets user
137 // attention instead.
138 if (FD->getName() == "CFRetain" &&
139 FD->getNumParams() == 1 &&
140 FD->getParent()->isTranslationUnit() &&
141 FD->getLinkage() == ExternalLinkage) {
142 Expr *Arg = callE->getArg(0);
Fariborz Jahaniana1c1b152012-01-31 22:09:44 +0000143 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000144 const Expr *sub = ICE->getSubExpr();
145 QualType T = sub->getType();
146 if (T->isObjCObjectPointerType())
147 return;
148 }
149 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000150 castToObjCObject(E, /*retained=*/true);
151 return;
152 }
153
154 if (fname.find("Get") != StringRef::npos) {
155 castToObjCObject(E, /*retained=*/false);
156 return;
157 }
158 }
159 }
160 }
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +0000161
162 // If returning an ivar or a member of an ivar from a +0 method, use
163 // a __bridge cast.
164 Expr *base = inner->IgnoreParenImpCasts();
165 while (isa<MemberExpr>(base))
166 base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
167 if (isa<ObjCIvarRefExpr>(base) &&
168 isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
169 if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
170 if (!method->hasAttr<NSReturnsRetainedAttr>()) {
171 castToObjCObject(E, /*retained=*/false);
172 return;
173 }
174 }
175 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000176 }
177
178 void castToObjCObject(CastExpr *E, bool retained) {
179 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
180 }
181
182 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000183 Transaction Trans(Pass.TA);
184 rewriteToBridgedCast(E, Kind, Trans);
185 }
186
187 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
188 Transaction &Trans) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000189 TransformActions &TA = Pass.TA;
190
191 // We will remove the compiler diagnostic.
192 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
193 diag::err_arc_cast_requires_bridge,
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000194 E->getLocStart())) {
195 Trans.abort();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000196 return;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000197 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000198
199 StringRef bridge;
200 switch(Kind) {
201 case OBC_Bridge:
202 bridge = "__bridge "; break;
203 case OBC_BridgeTransfer:
204 bridge = "__bridge_transfer "; break;
205 case OBC_BridgeRetained:
206 bridge = "__bridge_retained "; break;
207 }
208
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000209 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
210 diag::err_arc_cast_requires_bridge,
211 E->getLocStart());
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000212 if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
213 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
214 TA.insertAfterToken(CCE->getLParenLoc(), bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000215 } else {
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000216 SourceLocation insertLoc = E->getSubExpr()->getLocStart();
217 SmallString<128> newCast;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000218 newCast += '(';
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000219 newCast += bridge;
220 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
221 newCast += ')';
222
223 if (isa<ParenExpr>(E->getSubExpr())) {
224 TA.insert(insertLoc, newCast.str());
225 } else {
226 newCast += '(';
227 TA.insert(insertLoc, newCast.str());
228 TA.insertAfterToken(E->getLocEnd(), ")");
229 }
230 }
231 } else {
232 assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
Jordan Rose288c4212012-06-07 01:10:31 +0000233 SmallString<32> BridgeCall;
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000234
235 Expr *WrapE = E->getSubExpr();
Jordan Rose288c4212012-06-07 01:10:31 +0000236 SourceLocation InsertLoc = WrapE->getLocStart();
237
238 SourceManager &SM = Pass.Ctx.getSourceManager();
239 char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
240 if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
241 BridgeCall += ' ';
242
243 if (Kind == OBC_BridgeTransfer)
244 BridgeCall += "CFBridgingRelease";
245 else
246 BridgeCall += "CFBridgingRetain";
247
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000248 if (isa<ParenExpr>(WrapE)) {
Jordan Rose288c4212012-06-07 01:10:31 +0000249 TA.insert(InsertLoc, BridgeCall);
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000250 } else {
Jordan Rose288c4212012-06-07 01:10:31 +0000251 BridgeCall += '(';
252 TA.insert(InsertLoc, BridgeCall);
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000253 TA.insertAfterToken(WrapE->getLocEnd(), ")");
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000254 }
255 }
256 }
257
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000258 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
259 Transaction Trans(Pass.TA);
260 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
261 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
262 }
263
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000264 void transformObjCToNonObjCCast(CastExpr *E) {
265 if (isSelf(E->getSubExpr()))
266 return rewriteToBridgedCast(E, OBC_Bridge);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000267
268 CallExpr *callE;
269 if (isPassedToCFRetain(E, callE))
270 return rewriteCastForCFRetain(E, callE);
271
272 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
273 if (family == OMF_retain)
274 return rewriteToBridgedCast(E, OBC_BridgeRetained);
275
276 if (family == OMF_autorelease || family == OMF_release) {
277 std::string err = "it is not safe to cast to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000278 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000279 err += "' the result of '";
280 err += family == OMF_autorelease ? "autorelease" : "release";
281 err += "' message; a __bridge cast may result in a pointer to a "
282 "destroyed object and a __bridge_retained may leak the object";
283 Pass.TA.reportError(err, E->getLocStart(),
284 E->getSubExpr()->getSourceRange());
285 Stmt *parent = E;
286 do {
287 parent = StmtMap->getParentIgnoreParenImpCasts(parent);
288 } while (parent && isa<ExprWithCleanups>(parent));
289
290 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
291 std::string note = "remove the cast and change return type of function "
292 "to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000293 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000294 note += "' to have the object automatically autoreleased";
295 Pass.TA.reportNote(note, retS->getLocStart());
296 }
297 }
298
John McCallfe96e0b2011-11-06 09:01:30 +0000299 Expr *subExpr = E->getSubExpr();
300
301 // Look through pseudo-object expressions.
302 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
303 subExpr = pseudo->getResultExpr();
304 assert(subExpr && "no result for pseudo-object of non-void type?");
305 }
306
307 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
John McCall2d637d22011-09-10 06:18:15 +0000308 if (implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000309 return rewriteToBridgedCast(E, OBC_BridgeRetained);
John McCall2d637d22011-09-10 06:18:15 +0000310 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000311 return rewriteToBridgedCast(E, OBC_Bridge);
312 }
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000313
314 bool isConsumed = false;
315 if (isPassedToCParamWithKnownOwnership(E, isConsumed))
316 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
317 : OBC_Bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000318 }
319
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000320 static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
321 E = E->IgnoreParenCasts();
322 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
323 return ME->getMethodFamily();
324
325 return OMF_None;
326 }
327
328 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
329 if ((callE = dyn_cast_or_null<CallExpr>(
330 StmtMap->getParentIgnoreParenImpCasts(E))))
331 if (FunctionDecl *
332 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
333 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
334 FD->getParent()->isTranslationUnit() &&
335 FD->getLinkage() == ExternalLinkage)
336 return true;
337
338 return false;
339 }
340
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000341 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
342 if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
343 StmtMap->getParentIgnoreParenImpCasts(E)))
344 if (FunctionDecl *
345 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
346 unsigned i = 0;
347 for (unsigned e = callE->getNumArgs(); i != e; ++i) {
348 Expr *arg = callE->getArg(i);
349 if (arg == E || arg->IgnoreParenImpCasts() == E)
350 break;
351 }
352 if (i < callE->getNumArgs()) {
353 ParmVarDecl *PD = FD->getParamDecl(i);
354 if (PD->getAttr<CFConsumedAttr>()) {
355 isConsumed = true;
356 return true;
357 }
358 }
359 }
360
361 return false;
362 }
363
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000364 bool isSelf(Expr *E) const {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000365 E = E->IgnoreParenLValueCasts();
366 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000367 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
368 if (IPD->getIdentifier() == SelfII)
369 return true;
370
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000371 return false;
372 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000373};
374
375} // end anonymous namespace
376
377void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000378 BodyTransform<UnbridgedCastRewriter> trans(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000379 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
380}