1f4a2713aSLionel Sambuc //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // rewriteUnbridgedCasts:
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
13f4a2713aSLionel Sambuc // is from a file-level variable, __bridge cast is used to convert it.
14f4a2713aSLionel Sambuc // For the result of a function call that we know is +1/+0,
15f4a2713aSLionel Sambuc // __bridge/CFBridgingRelease is used.
16f4a2713aSLionel Sambuc //
17f4a2713aSLionel Sambuc // NSString *str = (NSString *)kUTTypePlainText;
18f4a2713aSLionel Sambuc // str = b ? kUTTypeRTF : kUTTypePlainText;
19f4a2713aSLionel Sambuc // NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
20f4a2713aSLionel Sambuc // _uuid);
21f4a2713aSLionel Sambuc // ---->
22f4a2713aSLionel Sambuc // NSString *str = (__bridge NSString *)kUTTypePlainText;
23f4a2713aSLionel Sambuc // str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
24f4a2713aSLionel Sambuc // NSString *_uuidString = (NSString *)
25f4a2713aSLionel Sambuc // CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
26f4a2713aSLionel Sambuc //
27f4a2713aSLionel Sambuc // For a C pointer to ObjC, for casting 'self', __bridge is used.
28f4a2713aSLionel Sambuc //
29f4a2713aSLionel Sambuc // CFStringRef str = (CFStringRef)self;
30f4a2713aSLionel Sambuc // ---->
31f4a2713aSLionel Sambuc // CFStringRef str = (__bridge CFStringRef)self;
32f4a2713aSLionel Sambuc //
33f4a2713aSLionel Sambuc // Uses of Block_copy/Block_release macros are rewritten:
34f4a2713aSLionel Sambuc //
35f4a2713aSLionel Sambuc // c = Block_copy(b);
36f4a2713aSLionel Sambuc // Block_release(c);
37f4a2713aSLionel Sambuc // ---->
38f4a2713aSLionel Sambuc // c = [b copy];
39f4a2713aSLionel Sambuc // <removed>
40f4a2713aSLionel Sambuc //
41f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
42f4a2713aSLionel Sambuc
43f4a2713aSLionel Sambuc #include "Transforms.h"
44f4a2713aSLionel Sambuc #include "Internals.h"
45f4a2713aSLionel Sambuc #include "clang/AST/ASTContext.h"
46f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
47f4a2713aSLionel Sambuc #include "clang/AST/ParentMap.h"
48f4a2713aSLionel Sambuc #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
49f4a2713aSLionel Sambuc #include "clang/Basic/SourceManager.h"
50f4a2713aSLionel Sambuc #include "clang/Lex/Lexer.h"
51f4a2713aSLionel Sambuc #include "clang/Sema/SemaDiagnostic.h"
52f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
53f4a2713aSLionel Sambuc
54f4a2713aSLionel Sambuc using namespace clang;
55f4a2713aSLionel Sambuc using namespace arcmt;
56f4a2713aSLionel Sambuc using namespace trans;
57f4a2713aSLionel Sambuc
58f4a2713aSLionel Sambuc namespace {
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambuc class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
61f4a2713aSLionel Sambuc MigrationPass &Pass;
62f4a2713aSLionel Sambuc IdentifierInfo *SelfII;
63*0a6a1f1dSLionel Sambuc std::unique_ptr<ParentMap> StmtMap;
64f4a2713aSLionel Sambuc Decl *ParentD;
65f4a2713aSLionel Sambuc Stmt *Body;
66*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<ExprSet> Removables;
67f4a2713aSLionel Sambuc
68f4a2713aSLionel Sambuc public:
UnbridgedCastRewriter(MigrationPass & pass)69*0a6a1f1dSLionel Sambuc UnbridgedCastRewriter(MigrationPass &pass)
70*0a6a1f1dSLionel Sambuc : Pass(pass), ParentD(nullptr), Body(nullptr) {
71f4a2713aSLionel Sambuc SelfII = &Pass.Ctx.Idents.get("self");
72f4a2713aSLionel Sambuc }
73f4a2713aSLionel Sambuc
transformBody(Stmt * body,Decl * ParentD)74f4a2713aSLionel Sambuc void transformBody(Stmt *body, Decl *ParentD) {
75f4a2713aSLionel Sambuc this->ParentD = ParentD;
76f4a2713aSLionel Sambuc Body = body;
77f4a2713aSLionel Sambuc StmtMap.reset(new ParentMap(body));
78f4a2713aSLionel Sambuc TraverseStmt(body);
79f4a2713aSLionel Sambuc }
80f4a2713aSLionel Sambuc
TraverseBlockDecl(BlockDecl * D)81f4a2713aSLionel Sambuc bool TraverseBlockDecl(BlockDecl *D) {
82f4a2713aSLionel Sambuc // ParentMap does not enter into a BlockDecl to record its stmts, so use a
83f4a2713aSLionel Sambuc // new UnbridgedCastRewriter to handle the block.
84f4a2713aSLionel Sambuc UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D);
85f4a2713aSLionel Sambuc return true;
86f4a2713aSLionel Sambuc }
87f4a2713aSLionel Sambuc
VisitCastExpr(CastExpr * E)88f4a2713aSLionel Sambuc bool VisitCastExpr(CastExpr *E) {
89f4a2713aSLionel Sambuc if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
90f4a2713aSLionel Sambuc E->getCastKind() != CK_BitCast &&
91f4a2713aSLionel Sambuc E->getCastKind() != CK_AnyPointerToBlockPointerCast)
92f4a2713aSLionel Sambuc return true;
93f4a2713aSLionel Sambuc
94f4a2713aSLionel Sambuc QualType castType = E->getType();
95f4a2713aSLionel Sambuc Expr *castExpr = E->getSubExpr();
96f4a2713aSLionel Sambuc QualType castExprType = castExpr->getType();
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
99f4a2713aSLionel Sambuc return true;
100f4a2713aSLionel Sambuc
101f4a2713aSLionel Sambuc bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
102f4a2713aSLionel Sambuc bool castRetainable = castType->isObjCIndirectLifetimeType();
103f4a2713aSLionel Sambuc if (exprRetainable == castRetainable) return true;
104f4a2713aSLionel Sambuc
105f4a2713aSLionel Sambuc if (castExpr->isNullPointerConstant(Pass.Ctx,
106f4a2713aSLionel Sambuc Expr::NPC_ValueDependentIsNull))
107f4a2713aSLionel Sambuc return true;
108f4a2713aSLionel Sambuc
109f4a2713aSLionel Sambuc SourceLocation loc = castExpr->getExprLoc();
110f4a2713aSLionel Sambuc if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
111f4a2713aSLionel Sambuc return true;
112f4a2713aSLionel Sambuc
113f4a2713aSLionel Sambuc if (castType->isObjCRetainableType())
114f4a2713aSLionel Sambuc transformNonObjCToObjCCast(E);
115f4a2713aSLionel Sambuc else
116f4a2713aSLionel Sambuc transformObjCToNonObjCCast(E);
117f4a2713aSLionel Sambuc
118f4a2713aSLionel Sambuc return true;
119f4a2713aSLionel Sambuc }
120f4a2713aSLionel Sambuc
121f4a2713aSLionel Sambuc private:
transformNonObjCToObjCCast(CastExpr * E)122f4a2713aSLionel Sambuc void transformNonObjCToObjCCast(CastExpr *E) {
123f4a2713aSLionel Sambuc if (!E) return;
124f4a2713aSLionel Sambuc
125f4a2713aSLionel Sambuc // Global vars are assumed that are cast as unretained.
126f4a2713aSLionel Sambuc if (isGlobalVar(E))
127f4a2713aSLionel Sambuc if (E->getSubExpr()->getType()->isPointerType()) {
128f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/false);
129f4a2713aSLionel Sambuc return;
130f4a2713aSLionel Sambuc }
131f4a2713aSLionel Sambuc
132f4a2713aSLionel Sambuc // If the cast is directly over the result of a Core Foundation function
133f4a2713aSLionel Sambuc // try to figure out whether it should be cast as retained or unretained.
134f4a2713aSLionel Sambuc Expr *inner = E->IgnoreParenCasts();
135f4a2713aSLionel Sambuc if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
136f4a2713aSLionel Sambuc if (FunctionDecl *FD = callE->getDirectCallee()) {
137*0a6a1f1dSLionel Sambuc if (FD->hasAttr<CFReturnsRetainedAttr>()) {
138f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/true);
139f4a2713aSLionel Sambuc return;
140f4a2713aSLionel Sambuc }
141*0a6a1f1dSLionel Sambuc if (FD->hasAttr<CFReturnsNotRetainedAttr>()) {
142f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/false);
143f4a2713aSLionel Sambuc return;
144f4a2713aSLionel Sambuc }
145f4a2713aSLionel Sambuc if (FD->isGlobal() &&
146f4a2713aSLionel Sambuc FD->getIdentifier() &&
147f4a2713aSLionel Sambuc ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
148f4a2713aSLionel Sambuc FD->getIdentifier()->getName())) {
149f4a2713aSLionel Sambuc StringRef fname = FD->getIdentifier()->getName();
150f4a2713aSLionel Sambuc if (fname.endswith("Retain") ||
151f4a2713aSLionel Sambuc fname.find("Create") != StringRef::npos ||
152f4a2713aSLionel Sambuc fname.find("Copy") != StringRef::npos) {
153f4a2713aSLionel Sambuc // Do not migrate to couple of bridge transfer casts which
154f4a2713aSLionel Sambuc // cancel each other out. Leave it unchanged so error gets user
155f4a2713aSLionel Sambuc // attention instead.
156f4a2713aSLionel Sambuc if (FD->getName() == "CFRetain" &&
157f4a2713aSLionel Sambuc FD->getNumParams() == 1 &&
158f4a2713aSLionel Sambuc FD->getParent()->isTranslationUnit() &&
159f4a2713aSLionel Sambuc FD->isExternallyVisible()) {
160f4a2713aSLionel Sambuc Expr *Arg = callE->getArg(0);
161f4a2713aSLionel Sambuc if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
162f4a2713aSLionel Sambuc const Expr *sub = ICE->getSubExpr();
163f4a2713aSLionel Sambuc QualType T = sub->getType();
164f4a2713aSLionel Sambuc if (T->isObjCObjectPointerType())
165f4a2713aSLionel Sambuc return;
166f4a2713aSLionel Sambuc }
167f4a2713aSLionel Sambuc }
168f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/true);
169f4a2713aSLionel Sambuc return;
170f4a2713aSLionel Sambuc }
171f4a2713aSLionel Sambuc
172f4a2713aSLionel Sambuc if (fname.find("Get") != StringRef::npos) {
173f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/false);
174f4a2713aSLionel Sambuc return;
175f4a2713aSLionel Sambuc }
176f4a2713aSLionel Sambuc }
177f4a2713aSLionel Sambuc }
178f4a2713aSLionel Sambuc }
179f4a2713aSLionel Sambuc
180f4a2713aSLionel Sambuc // If returning an ivar or a member of an ivar from a +0 method, use
181f4a2713aSLionel Sambuc // a __bridge cast.
182f4a2713aSLionel Sambuc Expr *base = inner->IgnoreParenImpCasts();
183f4a2713aSLionel Sambuc while (isa<MemberExpr>(base))
184f4a2713aSLionel Sambuc base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts();
185f4a2713aSLionel Sambuc if (isa<ObjCIvarRefExpr>(base) &&
186f4a2713aSLionel Sambuc isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
187f4a2713aSLionel Sambuc if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
188f4a2713aSLionel Sambuc if (!method->hasAttr<NSReturnsRetainedAttr>()) {
189f4a2713aSLionel Sambuc castToObjCObject(E, /*retained=*/false);
190f4a2713aSLionel Sambuc return;
191f4a2713aSLionel Sambuc }
192f4a2713aSLionel Sambuc }
193f4a2713aSLionel Sambuc }
194f4a2713aSLionel Sambuc }
195f4a2713aSLionel Sambuc
castToObjCObject(CastExpr * E,bool retained)196f4a2713aSLionel Sambuc void castToObjCObject(CastExpr *E, bool retained) {
197f4a2713aSLionel Sambuc rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
198f4a2713aSLionel Sambuc }
199f4a2713aSLionel Sambuc
rewriteToBridgedCast(CastExpr * E,ObjCBridgeCastKind Kind)200f4a2713aSLionel Sambuc void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
201f4a2713aSLionel Sambuc Transaction Trans(Pass.TA);
202f4a2713aSLionel Sambuc rewriteToBridgedCast(E, Kind, Trans);
203f4a2713aSLionel Sambuc }
204f4a2713aSLionel Sambuc
rewriteToBridgedCast(CastExpr * E,ObjCBridgeCastKind Kind,Transaction & Trans)205f4a2713aSLionel Sambuc void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind,
206f4a2713aSLionel Sambuc Transaction &Trans) {
207f4a2713aSLionel Sambuc TransformActions &TA = Pass.TA;
208f4a2713aSLionel Sambuc
209f4a2713aSLionel Sambuc // We will remove the compiler diagnostic.
210f4a2713aSLionel Sambuc if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
211f4a2713aSLionel Sambuc diag::err_arc_cast_requires_bridge,
212f4a2713aSLionel Sambuc E->getLocStart())) {
213f4a2713aSLionel Sambuc Trans.abort();
214f4a2713aSLionel Sambuc return;
215f4a2713aSLionel Sambuc }
216f4a2713aSLionel Sambuc
217f4a2713aSLionel Sambuc StringRef bridge;
218f4a2713aSLionel Sambuc switch(Kind) {
219f4a2713aSLionel Sambuc case OBC_Bridge:
220f4a2713aSLionel Sambuc bridge = "__bridge "; break;
221f4a2713aSLionel Sambuc case OBC_BridgeTransfer:
222f4a2713aSLionel Sambuc bridge = "__bridge_transfer "; break;
223f4a2713aSLionel Sambuc case OBC_BridgeRetained:
224f4a2713aSLionel Sambuc bridge = "__bridge_retained "; break;
225f4a2713aSLionel Sambuc }
226f4a2713aSLionel Sambuc
227f4a2713aSLionel Sambuc TA.clearDiagnostic(diag::err_arc_mismatched_cast,
228f4a2713aSLionel Sambuc diag::err_arc_cast_requires_bridge,
229f4a2713aSLionel Sambuc E->getLocStart());
230f4a2713aSLionel Sambuc if (Kind == OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
231f4a2713aSLionel Sambuc if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
232f4a2713aSLionel Sambuc TA.insertAfterToken(CCE->getLParenLoc(), bridge);
233f4a2713aSLionel Sambuc } else {
234f4a2713aSLionel Sambuc SourceLocation insertLoc = E->getSubExpr()->getLocStart();
235f4a2713aSLionel Sambuc SmallString<128> newCast;
236f4a2713aSLionel Sambuc newCast += '(';
237f4a2713aSLionel Sambuc newCast += bridge;
238f4a2713aSLionel Sambuc newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
239f4a2713aSLionel Sambuc newCast += ')';
240f4a2713aSLionel Sambuc
241f4a2713aSLionel Sambuc if (isa<ParenExpr>(E->getSubExpr())) {
242f4a2713aSLionel Sambuc TA.insert(insertLoc, newCast.str());
243f4a2713aSLionel Sambuc } else {
244f4a2713aSLionel Sambuc newCast += '(';
245f4a2713aSLionel Sambuc TA.insert(insertLoc, newCast.str());
246f4a2713aSLionel Sambuc TA.insertAfterToken(E->getLocEnd(), ")");
247f4a2713aSLionel Sambuc }
248f4a2713aSLionel Sambuc }
249f4a2713aSLionel Sambuc } else {
250f4a2713aSLionel Sambuc assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained);
251f4a2713aSLionel Sambuc SmallString<32> BridgeCall;
252f4a2713aSLionel Sambuc
253f4a2713aSLionel Sambuc Expr *WrapE = E->getSubExpr();
254f4a2713aSLionel Sambuc SourceLocation InsertLoc = WrapE->getLocStart();
255f4a2713aSLionel Sambuc
256f4a2713aSLionel Sambuc SourceManager &SM = Pass.Ctx.getSourceManager();
257f4a2713aSLionel Sambuc char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1));
258f4a2713aSLionel Sambuc if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts()))
259f4a2713aSLionel Sambuc BridgeCall += ' ';
260f4a2713aSLionel Sambuc
261f4a2713aSLionel Sambuc if (Kind == OBC_BridgeTransfer)
262f4a2713aSLionel Sambuc BridgeCall += "CFBridgingRelease";
263f4a2713aSLionel Sambuc else
264f4a2713aSLionel Sambuc BridgeCall += "CFBridgingRetain";
265f4a2713aSLionel Sambuc
266f4a2713aSLionel Sambuc if (isa<ParenExpr>(WrapE)) {
267f4a2713aSLionel Sambuc TA.insert(InsertLoc, BridgeCall);
268f4a2713aSLionel Sambuc } else {
269f4a2713aSLionel Sambuc BridgeCall += '(';
270f4a2713aSLionel Sambuc TA.insert(InsertLoc, BridgeCall);
271f4a2713aSLionel Sambuc TA.insertAfterToken(WrapE->getLocEnd(), ")");
272f4a2713aSLionel Sambuc }
273f4a2713aSLionel Sambuc }
274f4a2713aSLionel Sambuc }
275f4a2713aSLionel Sambuc
rewriteCastForCFRetain(CastExpr * castE,CallExpr * callE)276f4a2713aSLionel Sambuc void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) {
277f4a2713aSLionel Sambuc Transaction Trans(Pass.TA);
278f4a2713aSLionel Sambuc Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange());
279f4a2713aSLionel Sambuc rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
280f4a2713aSLionel Sambuc }
281f4a2713aSLionel Sambuc
getBlockMacroRanges(CastExpr * E,SourceRange & Outer,SourceRange & Inner)282f4a2713aSLionel Sambuc void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
283f4a2713aSLionel Sambuc SourceManager &SM = Pass.Ctx.getSourceManager();
284f4a2713aSLionel Sambuc SourceLocation Loc = E->getExprLoc();
285f4a2713aSLionel Sambuc assert(Loc.isMacroID());
286f4a2713aSLionel Sambuc SourceLocation MacroBegin, MacroEnd;
287*0a6a1f1dSLionel Sambuc std::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
288f4a2713aSLionel Sambuc SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
289f4a2713aSLionel Sambuc SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
290f4a2713aSLionel Sambuc SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
291f4a2713aSLionel Sambuc
292f4a2713aSLionel Sambuc Outer = SourceRange(MacroBegin, MacroEnd);
293f4a2713aSLionel Sambuc Inner = SourceRange(InnerBegin, InnerEnd);
294f4a2713aSLionel Sambuc }
295f4a2713aSLionel Sambuc
rewriteBlockCopyMacro(CastExpr * E)296f4a2713aSLionel Sambuc void rewriteBlockCopyMacro(CastExpr *E) {
297f4a2713aSLionel Sambuc SourceRange OuterRange, InnerRange;
298f4a2713aSLionel Sambuc getBlockMacroRanges(E, OuterRange, InnerRange);
299f4a2713aSLionel Sambuc
300f4a2713aSLionel Sambuc Transaction Trans(Pass.TA);
301f4a2713aSLionel Sambuc Pass.TA.replace(OuterRange, InnerRange);
302f4a2713aSLionel Sambuc Pass.TA.insert(InnerRange.getBegin(), "[");
303f4a2713aSLionel Sambuc Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
304f4a2713aSLionel Sambuc Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
305f4a2713aSLionel Sambuc diag::err_arc_cast_requires_bridge,
306f4a2713aSLionel Sambuc OuterRange);
307f4a2713aSLionel Sambuc }
308f4a2713aSLionel Sambuc
removeBlockReleaseMacro(CastExpr * E)309f4a2713aSLionel Sambuc void removeBlockReleaseMacro(CastExpr *E) {
310f4a2713aSLionel Sambuc SourceRange OuterRange, InnerRange;
311f4a2713aSLionel Sambuc getBlockMacroRanges(E, OuterRange, InnerRange);
312f4a2713aSLionel Sambuc
313f4a2713aSLionel Sambuc Transaction Trans(Pass.TA);
314f4a2713aSLionel Sambuc Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
315f4a2713aSLionel Sambuc diag::err_arc_cast_requires_bridge,
316f4a2713aSLionel Sambuc OuterRange);
317f4a2713aSLionel Sambuc if (!hasSideEffects(E, Pass.Ctx)) {
318f4a2713aSLionel Sambuc if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
319f4a2713aSLionel Sambuc return;
320f4a2713aSLionel Sambuc }
321f4a2713aSLionel Sambuc Pass.TA.replace(OuterRange, InnerRange);
322f4a2713aSLionel Sambuc }
323f4a2713aSLionel Sambuc
tryRemoving(Expr * E) const324f4a2713aSLionel Sambuc bool tryRemoving(Expr *E) const {
325f4a2713aSLionel Sambuc if (!Removables) {
326f4a2713aSLionel Sambuc Removables.reset(new ExprSet);
327f4a2713aSLionel Sambuc collectRemovables(Body, *Removables);
328f4a2713aSLionel Sambuc }
329f4a2713aSLionel Sambuc
330f4a2713aSLionel Sambuc if (Removables->count(E)) {
331f4a2713aSLionel Sambuc Pass.TA.removeStmt(E);
332f4a2713aSLionel Sambuc return true;
333f4a2713aSLionel Sambuc }
334f4a2713aSLionel Sambuc
335f4a2713aSLionel Sambuc return false;
336f4a2713aSLionel Sambuc }
337f4a2713aSLionel Sambuc
transformObjCToNonObjCCast(CastExpr * E)338f4a2713aSLionel Sambuc void transformObjCToNonObjCCast(CastExpr *E) {
339f4a2713aSLionel Sambuc SourceLocation CastLoc = E->getExprLoc();
340f4a2713aSLionel Sambuc if (CastLoc.isMacroID()) {
341f4a2713aSLionel Sambuc StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
342f4a2713aSLionel Sambuc Pass.Ctx.getSourceManager(),
343f4a2713aSLionel Sambuc Pass.Ctx.getLangOpts());
344f4a2713aSLionel Sambuc if (MacroName == "Block_copy") {
345f4a2713aSLionel Sambuc rewriteBlockCopyMacro(E);
346f4a2713aSLionel Sambuc return;
347f4a2713aSLionel Sambuc }
348f4a2713aSLionel Sambuc if (MacroName == "Block_release") {
349f4a2713aSLionel Sambuc removeBlockReleaseMacro(E);
350f4a2713aSLionel Sambuc return;
351f4a2713aSLionel Sambuc }
352f4a2713aSLionel Sambuc }
353f4a2713aSLionel Sambuc
354f4a2713aSLionel Sambuc if (isSelf(E->getSubExpr()))
355f4a2713aSLionel Sambuc return rewriteToBridgedCast(E, OBC_Bridge);
356f4a2713aSLionel Sambuc
357f4a2713aSLionel Sambuc CallExpr *callE;
358f4a2713aSLionel Sambuc if (isPassedToCFRetain(E, callE))
359f4a2713aSLionel Sambuc return rewriteCastForCFRetain(E, callE);
360f4a2713aSLionel Sambuc
361f4a2713aSLionel Sambuc ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr());
362f4a2713aSLionel Sambuc if (family == OMF_retain)
363f4a2713aSLionel Sambuc return rewriteToBridgedCast(E, OBC_BridgeRetained);
364f4a2713aSLionel Sambuc
365f4a2713aSLionel Sambuc if (family == OMF_autorelease || family == OMF_release) {
366f4a2713aSLionel Sambuc std::string err = "it is not safe to cast to '";
367f4a2713aSLionel Sambuc err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy());
368f4a2713aSLionel Sambuc err += "' the result of '";
369f4a2713aSLionel Sambuc err += family == OMF_autorelease ? "autorelease" : "release";
370f4a2713aSLionel Sambuc err += "' message; a __bridge cast may result in a pointer to a "
371f4a2713aSLionel Sambuc "destroyed object and a __bridge_retained may leak the object";
372f4a2713aSLionel Sambuc Pass.TA.reportError(err, E->getLocStart(),
373f4a2713aSLionel Sambuc E->getSubExpr()->getSourceRange());
374f4a2713aSLionel Sambuc Stmt *parent = E;
375f4a2713aSLionel Sambuc do {
376f4a2713aSLionel Sambuc parent = StmtMap->getParentIgnoreParenImpCasts(parent);
377f4a2713aSLionel Sambuc } while (parent && isa<ExprWithCleanups>(parent));
378f4a2713aSLionel Sambuc
379f4a2713aSLionel Sambuc if (ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
380f4a2713aSLionel Sambuc std::string note = "remove the cast and change return type of function "
381f4a2713aSLionel Sambuc "to '";
382f4a2713aSLionel Sambuc note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy());
383f4a2713aSLionel Sambuc note += "' to have the object automatically autoreleased";
384f4a2713aSLionel Sambuc Pass.TA.reportNote(note, retS->getLocStart());
385f4a2713aSLionel Sambuc }
386f4a2713aSLionel Sambuc }
387f4a2713aSLionel Sambuc
388f4a2713aSLionel Sambuc Expr *subExpr = E->getSubExpr();
389f4a2713aSLionel Sambuc
390f4a2713aSLionel Sambuc // Look through pseudo-object expressions.
391f4a2713aSLionel Sambuc if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
392f4a2713aSLionel Sambuc subExpr = pseudo->getResultExpr();
393f4a2713aSLionel Sambuc assert(subExpr && "no result for pseudo-object of non-void type?");
394f4a2713aSLionel Sambuc }
395f4a2713aSLionel Sambuc
396f4a2713aSLionel Sambuc if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
397f4a2713aSLionel Sambuc if (implCE->getCastKind() == CK_ARCConsumeObject)
398f4a2713aSLionel Sambuc return rewriteToBridgedCast(E, OBC_BridgeRetained);
399f4a2713aSLionel Sambuc if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
400f4a2713aSLionel Sambuc return rewriteToBridgedCast(E, OBC_Bridge);
401f4a2713aSLionel Sambuc }
402f4a2713aSLionel Sambuc
403f4a2713aSLionel Sambuc bool isConsumed = false;
404f4a2713aSLionel Sambuc if (isPassedToCParamWithKnownOwnership(E, isConsumed))
405f4a2713aSLionel Sambuc return rewriteToBridgedCast(E, isConsumed ? OBC_BridgeRetained
406f4a2713aSLionel Sambuc : OBC_Bridge);
407f4a2713aSLionel Sambuc }
408f4a2713aSLionel Sambuc
getFamilyOfMessage(Expr * E)409f4a2713aSLionel Sambuc static ObjCMethodFamily getFamilyOfMessage(Expr *E) {
410f4a2713aSLionel Sambuc E = E->IgnoreParenCasts();
411f4a2713aSLionel Sambuc if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
412f4a2713aSLionel Sambuc return ME->getMethodFamily();
413f4a2713aSLionel Sambuc
414f4a2713aSLionel Sambuc return OMF_None;
415f4a2713aSLionel Sambuc }
416f4a2713aSLionel Sambuc
isPassedToCFRetain(Expr * E,CallExpr * & callE) const417f4a2713aSLionel Sambuc bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const {
418f4a2713aSLionel Sambuc if ((callE = dyn_cast_or_null<CallExpr>(
419f4a2713aSLionel Sambuc StmtMap->getParentIgnoreParenImpCasts(E))))
420f4a2713aSLionel Sambuc if (FunctionDecl *
421f4a2713aSLionel Sambuc FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
422f4a2713aSLionel Sambuc if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
423f4a2713aSLionel Sambuc FD->getParent()->isTranslationUnit() &&
424f4a2713aSLionel Sambuc FD->isExternallyVisible())
425f4a2713aSLionel Sambuc return true;
426f4a2713aSLionel Sambuc
427f4a2713aSLionel Sambuc return false;
428f4a2713aSLionel Sambuc }
429f4a2713aSLionel Sambuc
isPassedToCParamWithKnownOwnership(Expr * E,bool & isConsumed) const430f4a2713aSLionel Sambuc bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const {
431f4a2713aSLionel Sambuc if (CallExpr *callE = dyn_cast_or_null<CallExpr>(
432f4a2713aSLionel Sambuc StmtMap->getParentIgnoreParenImpCasts(E)))
433f4a2713aSLionel Sambuc if (FunctionDecl *
434f4a2713aSLionel Sambuc FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) {
435f4a2713aSLionel Sambuc unsigned i = 0;
436f4a2713aSLionel Sambuc for (unsigned e = callE->getNumArgs(); i != e; ++i) {
437f4a2713aSLionel Sambuc Expr *arg = callE->getArg(i);
438f4a2713aSLionel Sambuc if (arg == E || arg->IgnoreParenImpCasts() == E)
439f4a2713aSLionel Sambuc break;
440f4a2713aSLionel Sambuc }
441f4a2713aSLionel Sambuc if (i < callE->getNumArgs() && i < FD->getNumParams()) {
442f4a2713aSLionel Sambuc ParmVarDecl *PD = FD->getParamDecl(i);
443*0a6a1f1dSLionel Sambuc if (PD->hasAttr<CFConsumedAttr>()) {
444f4a2713aSLionel Sambuc isConsumed = true;
445f4a2713aSLionel Sambuc return true;
446f4a2713aSLionel Sambuc }
447f4a2713aSLionel Sambuc }
448f4a2713aSLionel Sambuc }
449f4a2713aSLionel Sambuc
450f4a2713aSLionel Sambuc return false;
451f4a2713aSLionel Sambuc }
452f4a2713aSLionel Sambuc
isSelf(Expr * E) const453f4a2713aSLionel Sambuc bool isSelf(Expr *E) const {
454f4a2713aSLionel Sambuc E = E->IgnoreParenLValueCasts();
455f4a2713aSLionel Sambuc if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
456f4a2713aSLionel Sambuc if (ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
457f4a2713aSLionel Sambuc if (IPD->getIdentifier() == SelfII)
458f4a2713aSLionel Sambuc return true;
459f4a2713aSLionel Sambuc
460f4a2713aSLionel Sambuc return false;
461f4a2713aSLionel Sambuc }
462f4a2713aSLionel Sambuc };
463f4a2713aSLionel Sambuc
464f4a2713aSLionel Sambuc } // end anonymous namespace
465f4a2713aSLionel Sambuc
rewriteUnbridgedCasts(MigrationPass & pass)466f4a2713aSLionel Sambuc void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
467f4a2713aSLionel Sambuc BodyTransform<UnbridgedCastRewriter> trans(pass);
468f4a2713aSLionel Sambuc trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
469f4a2713aSLionel Sambuc }
470