xref: /minix3/external/bsd/llvm/dist/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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