TransUnbridgedCasts.cpp revision 2908ffbc5f54323f150405fa2b06f50788ae55c7
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            // 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);
139              if (const CastExpr *ICE = dyn_cast<CastExpr>(Arg)) {
140                const Expr *sub = ICE->getSubExpr();
141                QualType T = sub->getType();
142                if (T->isObjCObjectPointerType())
143                  return;
144              }
145            }
146            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) {
164    Transaction Trans(Pass.TA);
165    rewriteToBridgedCast(E, Kind, Trans);
166  }
167
168  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
169                            Transaction &Trans) {
170    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,
175                          E->getLocStart())) {
176      Trans.abort();
177      return;
178    }
179
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
190    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;
200      newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
201      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
213  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
219  void transformObjCToNonObjCCast(CastExpr *E) {
220    if (isSelf(E->getSubExpr()))
221      return rewriteToBridgedCast(E, OBC_Bridge);
222
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 '";
233      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
234      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 '";
248        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
249        note += "' to have the object automatically autoreleased";
250        Pass.TA.reportNote(note, retS->getLocStart());
251      }
252    }
253
254    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)) {
263      if (implCE->getCastKind() == CK_ARCConsumeObject)
264        return rewriteToBridgedCast(E, OBC_BridgeRetained);
265      if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
266        return rewriteToBridgedCast(E, OBC_Bridge);
267    }
268
269    bool isConsumed = false;
270    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
271      return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
272                                                : OBC_Bridge);
273  }
274
275  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
296  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
319  bool isSelf(Expr *E) const {
320    E = E->IgnoreParenLValueCasts();
321    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
322      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
323        if (IPD->getIdentifier() == SelfII)
324          return true;
325
326    return false;
327  }
328};
329
330} // end anonymous namespace
331
332void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
333  BodyTransform<UnbridgedCastRewriter> trans(pass);
334  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
335}
336