blob: 42a92edd4ea0d0f824dedd9dc2d5cf6ad4c1cb1f [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,
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"
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"
41
42using namespace clang;
43using namespace arcmt;
44using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000045
46namespace {
47
48class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
49 MigrationPass &Pass;
50 IdentifierInfo *SelfII;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000051 llvm::OwningPtr<ParentMap> StmtMap;
52
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000053public:
54 UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
55 SelfII = &Pass.Ctx.Idents.get("self");
56 }
57
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000058 void transformBody(Stmt *body) {
59 StmtMap.reset(new ParentMap(body));
60 TraverseStmt(body);
61 }
62
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000063 bool VisitCastExpr(CastExpr *E) {
John McCall9320b872011-09-09 05:25:32 +000064 if (E->getCastKind() != CK_CPointerToObjCPointerCast
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000065 && E->getCastKind() != CK_BitCast)
66 return true;
67
68 QualType castType = E->getType();
69 Expr *castExpr = E->getSubExpr();
70 QualType castExprType = castExpr->getType();
71
72 if (castType->isObjCObjectPointerType() &&
73 castExprType->isObjCObjectPointerType())
74 return true;
75 if (!castType->isObjCObjectPointerType() &&
76 !castExprType->isObjCObjectPointerType())
77 return true;
78
79 bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
80 bool castRetainable = castType->isObjCIndirectLifetimeType();
81 if (exprRetainable == castRetainable) return true;
82
83 if (castExpr->isNullPointerConstant(Pass.Ctx,
84 Expr::NPC_ValueDependentIsNull))
85 return true;
86
87 SourceLocation loc = castExpr->getExprLoc();
88 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
89 return true;
90
91 if (castType->isObjCObjectPointerType())
92 transformNonObjCToObjCCast(E);
93 else
94 transformObjCToNonObjCCast(E);
95
96 return true;
97 }
98
99private:
100 void transformNonObjCToObjCCast(CastExpr *E) {
101 if (!E) return;
102
103 // Global vars are assumed that are cast as unretained.
104 if (isGlobalVar(E))
105 if (E->getSubExpr()->getType()->isPointerType()) {
106 castToObjCObject(E, /*retained=*/false);
107 return;
108 }
109
110 // If the cast is directly over the result of a Core Foundation function
111 // try to figure out whether it should be cast as retained or unretained.
112 Expr *inner = E->IgnoreParenCasts();
113 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
114 if (FunctionDecl *FD = callE->getDirectCallee()) {
115 if (FD->getAttr<CFReturnsRetainedAttr>()) {
116 castToObjCObject(E, /*retained=*/true);
117 return;
118 }
119 if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
120 castToObjCObject(E, /*retained=*/false);
121 return;
122 }
123 if (FD->isGlobal() &&
124 FD->getIdentifier() &&
125 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
126 FD->getIdentifier()->getName())) {
127 StringRef fname = FD->getIdentifier()->getName();
128 if (fname.endswith("Retain") ||
129 fname.find("Create") != StringRef::npos ||
130 fname.find("Copy") != StringRef::npos) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000131 // Do not migrate to couple of bridge transfer casts which
132 // cancel each other out. Leave it unchanged so error gets user
133 // attention instead.
134 if (FD->getName() == "CFRetain" &&
135 FD->getNumParams() == 1 &&
136 FD->getParent()->isTranslationUnit() &&
137 FD->getLinkage() == ExternalLinkage) {
138 Expr *Arg = callE->getArg(0);
Fariborz Jahaniana1c1b152012-01-31 22:09:44 +0000139 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
Fariborz Jahanianeb002842012-01-31 21:58:23 +0000140 const Expr *sub = ICE->getSubExpr();
141 QualType T = sub->getType();
142 if (T->isObjCObjectPointerType())
143 return;
144 }
145 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000146 castToObjCObject(E, /*retained=*/true);
147 return;
148 }
149
150 if (fname.find("Get") != StringRef::npos) {
151 castToObjCObject(E, /*retained=*/false);
152 return;
153 }
154 }
155 }
156 }
157 }
158
159 void castToObjCObject(CastExpr *E, bool retained) {
160 rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
161 }
162
163 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000164 Transaction Trans(Pass.TA);
165 rewriteToBridgedCast(E, Kind, Trans);
166 }
167
168 void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
169 Transaction &Trans) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000170 TransformActions &TA = Pass.TA;
171
172 // We will remove the compiler diagnostic.
173 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
174 diag::err_arc_cast_requires_bridge,
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000175 E->getLocStart())) {
176 Trans.abort();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000177 return;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000178 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000179
180 StringRef bridge;
181 switch(Kind) {
182 case OBC_Bridge:
183 bridge = "__bridge "; break;
184 case OBC_BridgeTransfer:
185 bridge = "__bridge_transfer "; break;
186 case OBC_BridgeRetained:
187 bridge = "__bridge_retained "; break;
188 }
189
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000190 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
191 diag::err_arc_cast_requires_bridge,
192 E->getLocStart());
193 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
194 TA.insertAfterToken(CCE->getLParenLoc(), bridge);
195 } else {
196 SourceLocation insertLoc = E->getSubExpr()->getLocStart();
197 llvm::SmallString<128> newCast;
198 newCast += '(';
199 newCast += bridge;
Douglas Gregorc0b07282011-09-27 22:38:19 +0000200 newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000201 newCast += ')';
202
203 if (isa<ParenExpr>(E->getSubExpr())) {
204 TA.insert(insertLoc, newCast.str());
205 } else {
206 newCast += '(';
207 TA.insert(insertLoc, newCast.str());
208 TA.insertAfterToken(E->getLocEnd(), ")");
209 }
210 }
211 }
212
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000213 void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
214 Transaction Trans(Pass.TA);
215 Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
216 rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
217 }
218
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000219 void transformObjCToNonObjCCast(CastExpr *E) {
220 if (isSelf(E->getSubExpr()))
221 return rewriteToBridgedCast(E, OBC_Bridge);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000222
223 CallExpr *callE;
224 if (isPassedToCFRetain(E, callE))
225 return rewriteCastForCFRetain(E, callE);
226
227 ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
228 if (family == OMF_retain)
229 return rewriteToBridgedCast(E, OBC_BridgeRetained);
230
231 if (family == OMF_autorelease || family == OMF_release) {
232 std::string err = "it is not safe to cast to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000233 err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000234 err += "' the result of '";
235 err += family == OMF_autorelease ? "autorelease" : "release";
236 err += "' message; a __bridge cast may result in a pointer to a "
237 "destroyed object and a __bridge_retained may leak the object";
238 Pass.TA.reportError(err, E->getLocStart(),
239 E->getSubExpr()->getSourceRange());
240 Stmt *parent = E;
241 do {
242 parent = StmtMap->getParentIgnoreParenImpCasts(parent);
243 } while (parent && isa<ExprWithCleanups>(parent));
244
245 if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
246 std::string note = "remove the cast and change return type of function "
247 "to '";
Douglas Gregorc0b07282011-09-27 22:38:19 +0000248 note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000249 note += "' to have the object automatically autoreleased";
250 Pass.TA.reportNote(note, retS->getLocStart());
251 }
252 }
253
John McCallfe96e0b2011-11-06 09:01:30 +0000254 Expr *subExpr = E->getSubExpr();
255
256 // Look through pseudo-object expressions.
257 if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
258 subExpr = pseudo->getResultExpr();
259 assert(subExpr && "no result for pseudo-object of non-void type?");
260 }
261
262 if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
John McCall2d637d22011-09-10 06:18:15 +0000263 if (implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000264 return rewriteToBridgedCast(E, OBC_BridgeRetained);
John McCall2d637d22011-09-10 06:18:15 +0000265 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000266 return rewriteToBridgedCast(E, OBC_Bridge);
267 }
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000268
269 bool isConsumed = false;
270 if (isPassedToCParamWithKnownOwnership(E, isConsumed))
271 return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
272 : OBC_Bridge);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000273 }
274
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000275 static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
276 E = E->IgnoreParenCasts();
277 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
278 return ME->getMethodFamily();
279
280 return OMF_None;
281 }
282
283 bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
284 if ((callE = dyn_cast_or_null<CallExpr>(
285 StmtMap->getParentIgnoreParenImpCasts(E))))
286 if (FunctionDecl *
287 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
288 if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
289 FD->getParent()->isTranslationUnit() &&
290 FD->getLinkage() == ExternalLinkage)
291 return true;
292
293 return false;
294 }
295
Argyrios Kyrtzidis41899f32011-09-14 18:17:09 +0000296 bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
297 if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
298 StmtMap->getParentIgnoreParenImpCasts(E)))
299 if (FunctionDecl *
300 FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
301 unsigned i = 0;
302 for (unsigned e = callE->getNumArgs(); i != e; ++i) {
303 Expr *arg = callE->getArg(i);
304 if (arg == E || arg->IgnoreParenImpCasts() == E)
305 break;
306 }
307 if (i < callE->getNumArgs()) {
308 ParmVarDecl *PD = FD->getParamDecl(i);
309 if (PD->getAttr<CFConsumedAttr>()) {
310 isConsumed = true;
311 return true;
312 }
313 }
314 }
315
316 return false;
317 }
318
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000319 bool isSelf(Expr *E) const {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000320 E = E->IgnoreParenLValueCasts();
321 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000322 if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
323 if (IPD->getIdentifier() == SelfII)
324 return true;
325
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000326 return false;
327 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000328};
329
330} // end anonymous namespace
331
332void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000333 BodyTransform<UnbridgedCastRewriter> trans(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000334 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
335}