blob: 72c0d8e7de38b041dd01989f5f6ae639f6863966 [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"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000040#include "clang/Basic/SourceManager.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000041#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000042
43using namespace clang;
44using namespace arcmt;
45using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000046
47namespace {
48
49class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
50 MigrationPass &Pass;
51 IdentifierInfo *SelfII;
Dylan Noblesmithe2778992012-02-05 02:12:40 +000052 OwningPtr<ParentMap> StmtMap;
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000053 Decl *ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000054
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000055public:
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000056 UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000057 SelfII = &Pass.Ctx.Idents.get("self");
58 }
59
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +000060 void transformBody(Stmt *body, Decl *ParentD) {
61 this->ParentD = ParentD;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000062 StmtMap.reset(new ParentMap(body));
63 TraverseStmt(body);
64 }
65
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000066 bool VisitCastExpr(CastExpr *E) {
John McCall9320b872011-09-09 05:25:32 +000067 if (E->getCastKind() != CK_CPointerToObjCPointerCast
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000068 && E->getCastKind() != CK_BitCast)
69 return true;
70
71 QualType castType = E->getType();
72 Expr *castExpr = E->getSubExpr();
73 QualType castExprType = castExpr->getType();
74
75 if (castType->isObjCObjectPointerType() &&
76 castExprType->isObjCObjectPointerType())
77 return true;
78 if (!castType->isObjCObjectPointerType() &&
79 !castExprType->isObjCObjectPointerType())
80 return true;
81
82 bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
83 bool castRetainable = castType->isObjCIndirectLifetimeType();
84 if (exprRetainable == castRetainable) return true;
85
86 if (castExpr->isNullPointerConstant(Pass.Ctx,
87 Expr::NPC_ValueDependentIsNull))
88 return true;
89
90 SourceLocation loc = castExpr->getExprLoc();
91 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
92 return true;
93
94 if (castType->isObjCObjectPointerType())
95 transformNonObjCToObjCCast(E);
96 else
97 transformObjCToNonObjCCast(E);
98
99 return true;
100 }
101
102private:
103 void transformNonObjCToObjCCast(CastExpr *E) {
104 if (!E) return;
105
106 // Global vars are assumed that are cast as unretained.
107 if (isGlobalVar(E))
108 if (E->getSubExpr()->getType()->isPointerType()) {
109 castToObjCObject(E, /*retained=*/false);
110 return;
111 }
112
113 // If the cast is directly over the result of a Core Foundation function
114 // try to figure out whether it should be cast as retained or unretained.
115 Expr *inner = E->IgnoreParenCasts();
116 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
117 if (FunctionDecl *FD = callE->getDirectCallee()) {
118 if (FD->getAttr<CFReturnsRetainedAttr>()) {
119 castToObjCObject(E, /*retained=*/true);
120 return;
121 }
122 if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
123 castToObjCObject(E, /*retained=*/false);
124 return;
125 }
126 if (FD->isGlobal() &&
127 FD->getIdentifier() &&
128 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
129 FD->getIdentifier()->getName())) {
130 StringRef fname = FD->getIdentifier()->getName();
131 if (fname.endswith("Retain") ||
132 fname.find("Create") != StringRef::npos ||
133 fname.find("Copy") != StringRef::npos) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000134 // Do not migrate to couple of bridge transfer casts which
135 // cancel each other out. Leave it unchanged so error gets user
136 // attention instead.
137 if (FD->getName() == "CFRetain" &&
138 FD->getNumParams() == 1 &&
139 FD->getParent()->isTranslationUnit() &&
140 FD->getLinkage() == ExternalLinkage) {
141 Expr *Arg = callE->getArg(0);
Fariborz Jahaniana1c1b152012-01-31 22:09:44 +0000142 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000143 const Expr *sub = ICE->getSubExpr();
144 QualType T = sub->getType();
145 if (T->isObjCObjectPointerType())
146 return;
147 }
148 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000149 castToObjCObject(E, /*retained=*/true);
150 return;
151 }
152
153 if (fname.find("Get") != StringRef::npos) {
154 castToObjCObject(E, /*retained=*/false);
155 return;
156 }
157 }
158 }
159 }
Argyrios Kyrtzidisb03cc792012-06-07 00:44:06 +0000160
161 // If returning an ivar or a member of an ivar from a +0 method, use
162 // a __bridge cast.
163 Expr *base = inner->IgnoreParenImpCasts();
164 while (isa<MemberExpr>(base))
165 base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
166 if (isa<ObjCIvarRefExpr>(base) &&
167 isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
168 if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
169 if (!method->hasAttr<NSReturnsRetainedAttr>()) {
170 castToObjCObject(E, /*retained=*/false);
171 return;
172 }
173 }
174 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000175 }
176
177 void castToObjCObject(CastExpr *E, bool retained) {
178 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
179 }
180
181 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000182 Transaction Trans(Pass.TA);
183 rewriteToBridgedCast(E, Kind, Trans);
184 }
185
186 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
187 Transaction &Trans) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000188 TransformActions &TA = Pass.TA;
189
190 // We will remove the compiler diagnostic.
191 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
192 diag::err_arc_cast_requires_bridge,
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000193 E->getLocStart())) {
194 Trans.abort();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000195 return;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000196 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000197
198 StringRef bridge;
199 switch(Kind) {
200 case OBC_Bridge:
201 bridge = "__bridge "; break;
202 case OBC_BridgeTransfer:
203 bridge = "__bridge_transfer "; break;
204 case OBC_BridgeRetained:
205 bridge = "__bridge_retained "; break;
206 }
207
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000208 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
209 diag::err_arc_cast_requires_bridge,
210 E->getLocStart());
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000211 if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
212 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
213 TA.insertAfterToken(CCE->getLParenLoc(), bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000214 } else {
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000215 SourceLocation insertLoc = E->getSubExpr()->getLocStart();
216 SmallString<128> newCast;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000217 newCast += '(';
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +0000218 newCast += bridge;
219 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
220 newCast += ')';
221
222 if (isa<ParenExpr>(E->getSubExpr())) {
223 TA.insert(insertLoc, newCast.str());
224 } else {
225 newCast += '(';
226 TA.insert(insertLoc, newCast.str());
227 TA.insertAfterToken(E->getLocEnd(), ")");
228 }
229 }
230 } else {
231 assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
232 StringRef cfBridging;
233 if (Kind == OBC_BridgeTransfer)
234 cfBridging = "CFBridgingRelease";
235 else
236 cfBridging = "CFBridgingRetain";
237
238 Expr *WrapE = E->getSubExpr();
239 SourceLocation insertLoc = WrapE->getLocStart();
240 if (isa<ParenExpr>(WrapE)) {
241 TA.insert(insertLoc, cfBridging);
242 } else {
243 std::string withParens = cfBridging;
244 withParens += '(';
245 TA.insert(insertLoc, withParens);
246 TA.insertAfterToken(WrapE->getLocEnd(), ")");
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000247 }
248 }
249 }
250
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000251 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
252 Transaction Trans(Pass.TA);
253 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
254 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
255 }
256
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000257 void transformObjCToNonObjCCast(CastExpr *E) {
258 if (isSelf(E->getSubExpr()))
259 return rewriteToBridgedCast(E, OBC_Bridge);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000260
261 CallExpr *callE;
262 if (isPassedToCFRetain(E, callE))
263 return rewriteCastForCFRetain(E, callE);
264
265 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
266 if (family == OMF_retain)
267 return rewriteToBridgedCast(E, OBC_BridgeRetained);
268
269 if (family == OMF_autorelease || family == OMF_release) {
270 std::string err = "it is not safe to cast to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000271 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000272 err += "' the result of '";
273 err += family == OMF_autorelease ? "autorelease" : "release";
274 err += "' message; a __bridge cast may result in a pointer to a "
275 "destroyed object and a __bridge_retained may leak the object";
276 Pass.TA.reportError(err, E->getLocStart(),
277 E->getSubExpr()->getSourceRange());
278 Stmt *parent = E;
279 do {
280 parent = StmtMap->getParentIgnoreParenImpCasts(parent);
281 } while (parent && isa<ExprWithCleanups>(parent));
282
283 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
284 std::string note = "remove the cast and change return type of function "
285 "to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000286 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000287 note += "' to have the object automatically autoreleased";
288 Pass.TA.reportNote(note, retS->getLocStart());
289 }
290 }
291
John McCallfe96e0b2011-11-06 09:01:30 +0000292 Expr *subExpr = E->getSubExpr();
293
294 // Look through pseudo-object expressions.
295 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
296 subExpr = pseudo->getResultExpr();
297 assert(subExpr && "no result for pseudo-object of non-void type?");
298 }
299
300 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
John McCall2d637d22011-09-10 06:18:15 +0000301 if (implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000302 return rewriteToBridgedCast(E, OBC_BridgeRetained);
John McCall2d637d22011-09-10 06:18:15 +0000303 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000304 return rewriteToBridgedCast(E, OBC_Bridge);
305 }
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000306
307 bool isConsumed = false;
308 if (isPassedToCParamWithKnownOwnership(E, isConsumed))
309 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
310 : OBC_Bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000311 }
312
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000313 static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
314 E = E->IgnoreParenCasts();
315 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
316 return ME->getMethodFamily();
317
318 return OMF_None;
319 }
320
321 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
322 if ((callE = dyn_cast_or_null<CallExpr>(
323 StmtMap->getParentIgnoreParenImpCasts(E))))
324 if (FunctionDecl *
325 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
326 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
327 FD->getParent()->isTranslationUnit() &&
328 FD->getLinkage() == ExternalLinkage)
329 return true;
330
331 return false;
332 }
333
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000334 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
335 if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
336 StmtMap->getParentIgnoreParenImpCasts(E)))
337 if (FunctionDecl *
338 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
339 unsigned i = 0;
340 for (unsigned e = callE->getNumArgs(); i != e; ++i) {
341 Expr *arg = callE->getArg(i);
342 if (arg == E || arg->IgnoreParenImpCasts() == E)
343 break;
344 }
345 if (i < callE->getNumArgs()) {
346 ParmVarDecl *PD = FD->getParamDecl(i);
347 if (PD->getAttr<CFConsumedAttr>()) {
348 isConsumed = true;
349 return true;
350 }
351 }
352 }
353
354 return false;
355 }
356
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000357 bool isSelf(Expr *E) const {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000358 E = E->IgnoreParenLValueCasts();
359 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000360 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
361 if (IPD->getIdentifier() == SelfII)
362 return true;
363
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000364 return false;
365 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000366};
367
368} // end anonymous namespace
369
370void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000371 BodyTransform<UnbridgedCastRewriter> trans(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000372 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
373}