• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Basic/SourceManager.h"
40 
41 using namespace clang;
42 using namespace arcmt;
43 using namespace trans;
44 using llvm::StringRef;
45 
46 namespace {
47 
48 class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
49   MigrationPass &Pass;
50   IdentifierInfo *SelfII;
51 public:
UnbridgedCastRewriter(MigrationPass & pass)52   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
53     SelfII = &Pass.Ctx.Idents.get("self");
54   }
55 
VisitCastExpr(CastExpr * E)56   bool VisitCastExpr(CastExpr *E) {
57     if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
58         && E->getCastKind() != CK_BitCast)
59       return true;
60 
61     QualType castType = E->getType();
62     Expr *castExpr = E->getSubExpr();
63     QualType castExprType = castExpr->getType();
64 
65     if (castType->isObjCObjectPointerType() &&
66         castExprType->isObjCObjectPointerType())
67       return true;
68     if (!castType->isObjCObjectPointerType() &&
69         !castExprType->isObjCObjectPointerType())
70       return true;
71 
72     bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
73     bool castRetainable = castType->isObjCIndirectLifetimeType();
74     if (exprRetainable == castRetainable) return true;
75 
76     if (castExpr->isNullPointerConstant(Pass.Ctx,
77                                         Expr::NPC_ValueDependentIsNull))
78       return true;
79 
80     SourceLocation loc = castExpr->getExprLoc();
81     if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
82       return true;
83 
84     if (castType->isObjCObjectPointerType())
85       transformNonObjCToObjCCast(E);
86     else
87       transformObjCToNonObjCCast(E);
88 
89     return true;
90   }
91 
92 private:
transformNonObjCToObjCCast(CastExpr * E)93   void transformNonObjCToObjCCast(CastExpr *E) {
94     if (!E) return;
95 
96     // Global vars are assumed that are cast as unretained.
97     if (isGlobalVar(E))
98       if (E->getSubExpr()->getType()->isPointerType()) {
99         castToObjCObject(E, /*retained=*/false);
100         return;
101       }
102 
103     // If the cast is directly over the result of a Core Foundation function
104     // try to figure out whether it should be cast as retained or unretained.
105     Expr *inner = E->IgnoreParenCasts();
106     if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
107       if (FunctionDecl *FD = callE->getDirectCallee()) {
108         if (FD->getAttr<CFReturnsRetainedAttr>()) {
109           castToObjCObject(E, /*retained=*/true);
110           return;
111         }
112         if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
113           castToObjCObject(E, /*retained=*/false);
114           return;
115         }
116         if (FD->isGlobal() &&
117             FD->getIdentifier() &&
118             ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
119                                    FD->getIdentifier()->getName())) {
120           StringRef fname = FD->getIdentifier()->getName();
121           if (fname.endswith("Retain") ||
122               fname.find("Create") != StringRef::npos ||
123               fname.find("Copy") != StringRef::npos) {
124             castToObjCObject(E, /*retained=*/true);
125             return;
126           }
127 
128           if (fname.find("Get") != StringRef::npos) {
129             castToObjCObject(E, /*retained=*/false);
130             return;
131           }
132         }
133       }
134     }
135   }
136 
castToObjCObject(CastExpr * E,bool retained)137   void castToObjCObject(CastExpr *E, bool retained) {
138     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
139   }
140 
rewriteToBridgedCast(CastExpr * E,ObjCBridgeCastKind Kind)141   void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
142     TransformActions &TA = Pass.TA;
143 
144     // We will remove the compiler diagnostic.
145     if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
146                           diag::err_arc_cast_requires_bridge,
147                           E->getLocStart()))
148       return;
149 
150     StringRef bridge;
151     switch(Kind) {
152     case OBC_Bridge:
153       bridge = "__bridge "; break;
154     case OBC_BridgeTransfer:
155       bridge = "__bridge_transfer "; break;
156     case OBC_BridgeRetained:
157       bridge = "__bridge_retained "; break;
158     }
159 
160     Transaction Trans(TA);
161     TA.clearDiagnostic(diag::err_arc_mismatched_cast,
162                        diag::err_arc_cast_requires_bridge,
163                        E->getLocStart());
164     if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
165       TA.insertAfterToken(CCE->getLParenLoc(), bridge);
166     } else {
167       SourceLocation insertLoc = E->getSubExpr()->getLocStart();
168       llvm::SmallString<128> newCast;
169       newCast += '(';
170       newCast += bridge;
171       newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
172       newCast += ')';
173 
174       if (isa<ParenExpr>(E->getSubExpr())) {
175         TA.insert(insertLoc, newCast.str());
176       } else {
177         newCast += '(';
178         TA.insert(insertLoc, newCast.str());
179         TA.insertAfterToken(E->getLocEnd(), ")");
180       }
181     }
182   }
183 
transformObjCToNonObjCCast(CastExpr * E)184   void transformObjCToNonObjCCast(CastExpr *E) {
185     if (isSelf(E->getSubExpr()))
186       return rewriteToBridgedCast(E, OBC_Bridge);
187   }
188 
isSelf(Expr * E)189   bool isSelf(Expr *E) {
190     E = E->IgnoreParenLValueCasts();
191     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
192       if (DRE->getDecl()->getIdentifier() == SelfII)
193         return true;
194     return false;
195   }
196 };
197 
198 } // end anonymous namespace
199 
rewriteUnbridgedCasts(MigrationPass & pass)200 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
201   UnbridgedCastRewriter trans(pass);
202   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
203 }
204