TransUnbridgedCasts.cpp revision 239462
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/CFBridgingRelease 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 = (NSString *)
25//            CFBridgingRelease(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/AST/ASTContext.h"
39#include "clang/AST/ParentMap.h"
40#include "clang/Basic/SourceManager.h"
41#include "clang/Lex/Lexer.h"
42#include "clang/Sema/SemaDiagnostic.h"
43#include "llvm/ADT/SmallString.h"
44
45using namespace clang;
46using namespace arcmt;
47using namespace trans;
48
49namespace {
50
51class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
52  MigrationPass &Pass;
53  IdentifierInfo *SelfII;
54  OwningPtr<ParentMap> StmtMap;
55  Decl *ParentD;
56
57public:
58  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
59    SelfII = &Pass.Ctx.Idents.get("self");
60  }
61
62  void transformBody(Stmt *body, Decl *ParentD) {
63    this->ParentD = ParentD;
64    StmtMap.reset(new ParentMap(body));
65    TraverseStmt(body);
66  }
67
68  bool VisitCastExpr(CastExpr *E) {
69    if (E->getCastKind() != CK_CPointerToObjCPointerCast
70        && E->getCastKind() != CK_BitCast)
71      return true;
72
73    QualType castType = E->getType();
74    Expr *castExpr = E->getSubExpr();
75    QualType castExprType = castExpr->getType();
76
77    if (castType->isObjCObjectPointerType() &&
78        castExprType->isObjCObjectPointerType())
79      return true;
80    if (!castType->isObjCObjectPointerType() &&
81        !castExprType->isObjCObjectPointerType())
82      return true;
83
84    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
85    bool castRetainable = castType->isObjCIndirectLifetimeType();
86    if (exprRetainable == castRetainable) return true;
87
88    if (castExpr->isNullPointerConstant(Pass.Ctx,
89                                        Expr::NPC_ValueDependentIsNull))
90      return true;
91
92    SourceLocation loc = castExpr->getExprLoc();
93    if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
94      return true;
95
96    if (castType->isObjCObjectPointerType())
97      transformNonObjCToObjCCast(E);
98    else
99      transformObjCToNonObjCCast(E);
100
101    return true;
102  }
103
104private:
105  void transformNonObjCToObjCCast(CastExpr *E) {
106    if (!E) return;
107
108    // Global vars are assumed that are cast as unretained.
109    if (isGlobalVar(E))
110      if (E->getSubExpr()->getType()->isPointerType()) {
111        castToObjCObject(E, /*retained=*/false);
112        return;
113      }
114
115    // If the cast is directly over the result of a Core Foundation function
116    // try to figure out whether it should be cast as retained or unretained.
117    Expr *inner = E->IgnoreParenCasts();
118    if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
119      if (FunctionDecl *FD = callE->getDirectCallee()) {
120        if (FD->getAttr<CFReturnsRetainedAttr>()) {
121          castToObjCObject(E, /*retained=*/true);
122          return;
123        }
124        if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
125          castToObjCObject(E, /*retained=*/false);
126          return;
127        }
128        if (FD->isGlobal() &&
129            FD->getIdentifier() &&
130            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
131                                   FD->getIdentifier()->getName())) {
132          StringRef fname = FD->getIdentifier()->getName();
133          if (fname.endswith("Retain") ||
134              fname.find("Create") != StringRef::npos ||
135              fname.find("Copy") != StringRef::npos) {
136            // Do not migrate to couple of bridge transfer casts which
137            // cancel each other out. Leave it unchanged so error gets user
138            // attention instead.
139            if (FD->getName() == "CFRetain" &&
140                FD->getNumParams() == 1 &&
141                FD->getParent()->isTranslationUnit() &&
142                FD->getLinkage() == ExternalLinkage) {
143              Expr *Arg = callE->getArg(0);
144              if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
145                const Expr *sub = ICE->getSubExpr();
146                QualType T = sub->getType();
147                if (T->isObjCObjectPointerType())
148                  return;
149              }
150            }
151            castToObjCObject(E, /*retained=*/true);
152            return;
153          }
154
155          if (fname.find("Get") != StringRef::npos) {
156            castToObjCObject(E, /*retained=*/false);
157            return;
158          }
159        }
160      }
161    }
162
163    // If returning an ivar or a member of an ivar from a +0 method, use
164    // a __bridge cast.
165    Expr *base = inner->IgnoreParenImpCasts();
166    while (isa<MemberExpr>(base))
167      base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
168    if (isa<ObjCIvarRefExpr>(base) &&
169        isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
170      if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
171        if (!method->hasAttr<NSReturnsRetainedAttr>()) {
172          castToObjCObject(E, /*retained=*/false);
173          return;
174        }
175      }
176    }
177  }
178
179  void castToObjCObject(CastExpr *E, bool retained) {
180    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
181  }
182
183  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
184    Transaction Trans(Pass.TA);
185    rewriteToBridgedCast(E, Kind, Trans);
186  }
187
188  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
189                            Transaction &Trans) {
190    TransformActions &TA = Pass.TA;
191
192    // We will remove the compiler diagnostic.
193    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
194                          diag::err_arc_cast_requires_bridge,
195                          E->getLocStart())) {
196      Trans.abort();
197      return;
198    }
199
200    StringRef bridge;
201    switch(Kind) {
202    case OBC_Bridge:
203      bridge = "__bridge "; break;
204    case OBC_BridgeTransfer:
205      bridge = "__bridge_transfer "; break;
206    case OBC_BridgeRetained:
207      bridge = "__bridge_retained "; break;
208    }
209
210    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
211                       diag::err_arc_cast_requires_bridge,
212                       E->getLocStart());
213    if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
214      if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
215        TA.insertAfterToken(CCE->getLParenLoc(), bridge);
216      } else {
217        SourceLocation insertLoc = E->getSubExpr()->getLocStart();
218        SmallString<128> newCast;
219        newCast += '(';
220        newCast += bridge;
221        newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
222        newCast += ')';
223
224        if (isa<ParenExpr>(E->getSubExpr())) {
225          TA.insert(insertLoc, newCast.str());
226        } else {
227          newCast += '(';
228          TA.insert(insertLoc, newCast.str());
229          TA.insertAfterToken(E->getLocEnd(), ")");
230        }
231      }
232    } else {
233      assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
234      SmallString<32> BridgeCall;
235
236      Expr *WrapE = E->getSubExpr();
237      SourceLocation InsertLoc = WrapE->getLocStart();
238
239      SourceManager &SM = Pass.Ctx.getSourceManager();
240      char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
241      if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
242        BridgeCall += ' ';
243
244      if (Kind == OBC_BridgeTransfer)
245        BridgeCall += "CFBridgingRelease";
246      else
247        BridgeCall += "CFBridgingRetain";
248
249      if (isa<ParenExpr>(WrapE)) {
250        TA.insert(InsertLoc, BridgeCall);
251      } else {
252        BridgeCall += '(';
253        TA.insert(InsertLoc, BridgeCall);
254        TA.insertAfterToken(WrapE->getLocEnd(), ")");
255      }
256    }
257  }
258
259  void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
260    Transaction Trans(Pass.TA);
261    Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
262    rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
263  }
264
265  void transformObjCToNonObjCCast(CastExpr *E) {
266    if (isSelf(E->getSubExpr()))
267      return rewriteToBridgedCast(E, OBC_Bridge);
268
269    CallExpr *callE;
270    if (isPassedToCFRetain(E, callE))
271      return rewriteCastForCFRetain(E, callE);
272
273    ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
274    if (family == OMF_retain)
275      return rewriteToBridgedCast(E, OBC_BridgeRetained);
276
277    if (family == OMF_autorelease || family == OMF_release) {
278      std::string err = "it is not safe to cast to '";
279      err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
280      err += "' the result of '";
281      err += family == OMF_autorelease ? "autorelease" : "release";
282      err += "' message; a __bridge cast may result in a pointer to a "
283          "destroyed object and a __bridge_retained may leak the object";
284      Pass.TA.reportError(err, E->getLocStart(),
285                          E->getSubExpr()->getSourceRange());
286      Stmt *parent = E;
287      do {
288        parent = StmtMap->getParentIgnoreParenImpCasts(parent);
289      } while (parent && isa<ExprWithCleanups>(parent));
290
291      if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
292        std::string note = "remove the cast and change return type of function "
293            "to '";
294        note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
295        note += "' to have the object automatically autoreleased";
296        Pass.TA.reportNote(note, retS->getLocStart());
297      }
298    }
299
300    Expr *subExpr = E->getSubExpr();
301
302    // Look through pseudo-object expressions.
303    if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
304      subExpr = pseudo->getResultExpr();
305      assert(subExpr && "no result for pseudo-object of non-void type?");
306    }
307
308    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
309      if (implCE->getCastKind() == CK_ARCConsumeObject)
310        return rewriteToBridgedCast(E, OBC_BridgeRetained);
311      if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
312        return rewriteToBridgedCast(E, OBC_Bridge);
313    }
314
315    bool isConsumed = false;
316    if (isPassedToCParamWithKnownOwnership(E, isConsumed))
317      return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
318                                                : OBC_Bridge);
319  }
320
321  static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
322    E = E->IgnoreParenCasts();
323    if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
324      return ME->getMethodFamily();
325
326    return OMF_None;
327  }
328
329  bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
330    if ((callE = dyn_cast_or_null<CallExpr>(
331                                     StmtMap->getParentIgnoreParenImpCasts(E))))
332      if (FunctionDecl *
333            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
334        if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
335            FD->getParent()->isTranslationUnit() &&
336            FD->getLinkage() == ExternalLinkage)
337          return true;
338
339    return false;
340  }
341
342  bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
343    if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
344                                     StmtMap->getParentIgnoreParenImpCasts(E)))
345      if (FunctionDecl *
346            FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
347        unsigned i = 0;
348        for (unsigned e = callE->getNumArgs(); i != e; ++i) {
349          Expr *arg = callE->getArg(i);
350          if (arg == E || arg->IgnoreParenImpCasts() == E)
351            break;
352        }
353        if (i < callE->getNumArgs()) {
354          ParmVarDecl *PD = FD->getParamDecl(i);
355          if (PD->getAttr<CFConsumedAttr>()) {
356            isConsumed = true;
357            return true;
358          }
359        }
360      }
361
362    return false;
363  }
364
365  bool isSelf(Expr *E) const {
366    E = E->IgnoreParenLValueCasts();
367    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
368      if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
369        if (IPD->getIdentifier() == SelfII)
370          return true;
371
372    return false;
373  }
374};
375
376} // end anonymous namespace
377
378void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
379  BodyTransform<UnbridgedCastRewriter> trans(pass);
380  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
381}
382