]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / ARCMigrate / TransUnbridgedCasts.cpp
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:
52   UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
53     SelfII = &Pass.Ctx.Idents.get("self");
54   }
55
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:
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
137   void castToObjCObject(CastExpr *E, bool retained) {
138     rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
139   }
140
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
184   void transformObjCToNonObjCCast(CastExpr *E) {
185     if (isSelf(E->getSubExpr()))
186       return rewriteToBridgedCast(E, OBC_Bridge);
187   }
188
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
200 void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
201   UnbridgedCastRewriter trans(pass);
202   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
203 }