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/AST/ParentMap.h"
40#include "clang/Basic/SourceManager.h"
41
42using namespace clang;
43using namespace arcmt;
44using namespace trans;
45
46namespace {
47
48class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
49  MigrationPass &Pass;
50  IdentifierInfo *SelfII;
51  llvm::OwningPtr<ParentMap> StmtMap;
52
53public:
54  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
55    SelfII = &Pass.Ctx.Idents.get("self");
56  }
57
58  void transformBody(Stmt *body) {
59    StmtMap.reset(new ParentMap(body));
60    TraverseStmt(body);
61  }
62
63  bool VisitCastExpr(CastExpr *E) {
64    if (E->getCastKind() != CK_CPointerToObjCPointerCast
65        && 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) {
131            castToObjCObject(E, /*retained=*/true);
132            return;
133          }
134
135          if (fname.find("Get") != StringRef::npos) {
136            castToObjCObject(E, /*retained=*/false);
137            return;
138          }
139        }
140      }
141    }
142  }
143
144  void castToObjCObject(CastExpr *E, bool retained) {
145    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
146  }
147
148  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
149    Transaction Trans(Pass.TA);
150    rewriteToBridgedCast(E, Kind, Trans);
151  }
152
153  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
154                            Transaction &Trans) {
155    TransformActions &TA = Pass.TA;
156
157    // We will remove the compiler diagnostic.
158    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
159                          diag::err_arc_cast_requires_bridge,
160                          E->getLocStart())) {
161      Trans.abort();
162      return;
163    }
164
165    StringRef bridge;
166    switch(Kind) {
167    case OBC_Bridge:
168      bridge = "__bridge "; break;
169    case OBC_BridgeTransfer:
170      bridge = "__bridge_transfer "; break;
171    case OBC_BridgeRetained:
172      bridge = "__bridge_retained "; break;
173    }
174
175    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
176                       diag::err_arc_cast_requires_bridge,
177                       E->getLocStart());
178    if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
179      TA.insertAfterToken(CCE->getLParenLoc(), bridge);
180    } else {
181      SourceLocation insertLoc = E->getSubExpr()->getLocStart();
182      llvm::SmallString<128> newCast;
183      newCast += '(';
184      newCast += bridge;
185      newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
186      newCast += ')';
187
188      if (isa<ParenExpr>(E->getSubExpr())) {
189        TA.insert(insertLoc, newCast.str());
190      } else {
191        newCast += '(';
192        TA.insert(insertLoc, newCast.str());
193        TA.insertAfterToken(E->getLocEnd(), ")");
194      }
195    }
196  }
197
198  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
199    Transaction Trans(Pass.TA);
200    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
201    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
202  }
203
204  void transformObjCToNonObjCCast(CastExpr *E) {
205    if (isSelf(E->getSubExpr()))
206      return rewriteToBridgedCast(E, OBC_Bridge);
207
208    CallExpr *callE;
209    if (isPassedToCFRetain(E, callE))
210      return rewriteCastForCFRetain(E, callE);
211
212    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
213    if (family == OMF_retain)
214      return rewriteToBridgedCast(E, OBC_BridgeRetained);
215
216    if (family == OMF_autorelease || family == OMF_release) {
217      std::string err = "it is not safe to cast to '";
218      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
219      err += "' the result of '";
220      err += family == OMF_autorelease ? "autorelease" : "release";
221      err += "' message; a __bridge cast may result in a pointer to a "
222          "destroyed object and a __bridge_retained may leak the object";
223      Pass.TA.reportError(err, E->getLocStart(),
224                          E->getSubExpr()->getSourceRange());
225      Stmt *parent = E;
226      do {
227        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
228      } while (parent && isa<ExprWithCleanups>(parent));
229
230      if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
231        std::string note = "remove the cast and change return type of function "
232            "to '";
233        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
234        note += "' to have the object automatically autoreleased";
235        Pass.TA.reportNote(note, retS->getLocStart());
236      }
237    }
238
239    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
240      if (implCE->getCastKind() == CK_ARCConsumeObject)
241        return rewriteToBridgedCast(E, OBC_BridgeRetained);
242      if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
243        return rewriteToBridgedCast(E, OBC_Bridge);
244    }
245
246    bool isConsumed = false;
247    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
248      return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
249                                                : OBC_Bridge);
250  }
251
252  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
253    E = E->IgnoreParenCasts();
254    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
255      return ME->getMethodFamily();
256
257    return OMF_None;
258  }
259
260  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
261    if ((callE = dyn_cast_or_null<CallExpr>(
262                                     StmtMap->getParentIgnoreParenImpCasts(E))))
263      if (FunctionDecl *
264            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
265        if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
266            FD->getParent()->isTranslationUnit() &&
267            FD->getLinkage() == ExternalLinkage)
268          return true;
269
270    return false;
271  }
272
273  bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
274    if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
275                                     StmtMap->getParentIgnoreParenImpCasts(E)))
276      if (FunctionDecl *
277            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
278        unsigned i = 0;
279        for (unsigned e = callE->getNumArgs(); i != e; ++i) {
280          Expr *arg = callE->getArg(i);
281          if (arg == E || arg->IgnoreParenImpCasts() == E)
282            break;
283        }
284        if (i < callE->getNumArgs()) {
285          ParmVarDecl *PD = FD->getParamDecl(i);
286          if (PD->getAttr<CFConsumedAttr>()) {
287            isConsumed = true;
288            return true;
289          }
290        }
291      }
292
293    return false;
294  }
295
296  bool isSelf(Expr *E) const {
297    E = E->IgnoreParenLValueCasts();
298    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
299      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
300        if (IPD->getIdentifier() == SelfII)
301          return true;
302
303    return false;
304  }
305};
306
307} // end anonymous namespace
308
309void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
310  BodyTransform<UnbridgedCastRewriter> trans(pass);
311  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
312}
313