1 //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // rewriteUnbridgedCasts:
11 // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
12 // is from a file-level variable, __bridge cast is used to convert it.
13 // For the result of a function call that we know is +1/+0,
14 // __bridge/CFBridgingRelease is used.
16 // NSString *str = (NSString *)kUTTypePlainText;
17 // str = b ? kUTTypeRTF : kUTTypePlainText;
18 // NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
21 // NSString *str = (__bridge NSString *)kUTTypePlainText;
22 // str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
23 // NSString *_uuidString = (NSString *)
24 // CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid));
26 // For a C pointer to ObjC, for casting 'self', __bridge is used.
28 // CFStringRef str = (CFStringRef)self;
30 // CFStringRef str = (__bridge CFStringRef)self;
32 // Uses of Block_copy/Block_release macros are rewritten:
40 //===----------------------------------------------------------------------===//
42 #include "Transforms.h"
43 #include "Internals.h"
44 #include "clang/AST/ASTContext.h"
45 #include "clang/AST/Attr.h"
46 #include "clang/AST/ParentMap.h"
47 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
48 #include "clang/Basic/SourceManager.h"
49 #include "clang/Lex/Lexer.h"
50 #include "clang/Sema/SemaDiagnostic.h"
51 #include "llvm/ADT/SmallString.h"
53 using namespace clang
;
54 using namespace arcmt
;
55 using namespace trans
;
59 class UnbridgedCastRewriter
: public RecursiveASTVisitor
<UnbridgedCastRewriter
>{
61 IdentifierInfo
*SelfII
;
62 std::unique_ptr
<ParentMap
> StmtMap
;
65 mutable std::unique_ptr
<ExprSet
> Removables
;
68 UnbridgedCastRewriter(MigrationPass
&pass
)
69 : Pass(pass
), ParentD(nullptr), Body(nullptr) {
70 SelfII
= &Pass
.Ctx
.Idents
.get("self");
73 void transformBody(Stmt
*body
, Decl
*ParentD
) {
74 this->ParentD
= ParentD
;
76 StmtMap
.reset(new ParentMap(body
));
80 bool TraverseBlockDecl(BlockDecl
*D
) {
81 // ParentMap does not enter into a BlockDecl to record its stmts, so use a
82 // new UnbridgedCastRewriter to handle the block.
83 UnbridgedCastRewriter(Pass
).transformBody(D
->getBody(), D
);
87 bool VisitCastExpr(CastExpr
*E
) {
88 if (E
->getCastKind() != CK_CPointerToObjCPointerCast
&&
89 E
->getCastKind() != CK_BitCast
&&
90 E
->getCastKind() != CK_AnyPointerToBlockPointerCast
)
93 QualType castType
= E
->getType();
94 Expr
*castExpr
= E
->getSubExpr();
95 QualType castExprType
= castExpr
->getType();
97 if (castType
->isObjCRetainableType() == castExprType
->isObjCRetainableType())
100 bool exprRetainable
= castExprType
->isObjCIndirectLifetimeType();
101 bool castRetainable
= castType
->isObjCIndirectLifetimeType();
102 if (exprRetainable
== castRetainable
) return true;
104 if (castExpr
->isNullPointerConstant(Pass
.Ctx
,
105 Expr::NPC_ValueDependentIsNull
))
108 SourceLocation loc
= castExpr
->getExprLoc();
109 if (loc
.isValid() && Pass
.Ctx
.getSourceManager().isInSystemHeader(loc
))
112 if (castType
->isObjCRetainableType())
113 transformNonObjCToObjCCast(E
);
115 transformObjCToNonObjCCast(E
);
121 void transformNonObjCToObjCCast(CastExpr
*E
) {
124 // Global vars are assumed that are cast as unretained.
126 if (E
->getSubExpr()->getType()->isPointerType()) {
127 castToObjCObject(E
, /*retained=*/false);
131 // If the cast is directly over the result of a Core Foundation function
132 // try to figure out whether it should be cast as retained or unretained.
133 Expr
*inner
= E
->IgnoreParenCasts();
134 if (CallExpr
*callE
= dyn_cast
<CallExpr
>(inner
)) {
135 if (FunctionDecl
*FD
= callE
->getDirectCallee()) {
136 if (FD
->hasAttr
<CFReturnsRetainedAttr
>()) {
137 castToObjCObject(E
, /*retained=*/true);
140 if (FD
->hasAttr
<CFReturnsNotRetainedAttr
>()) {
141 castToObjCObject(E
, /*retained=*/false);
144 if (FD
->isGlobal() &&
145 FD
->getIdentifier() &&
146 ento::cocoa::isRefType(E
->getSubExpr()->getType(), "CF",
147 FD
->getIdentifier()->getName())) {
148 StringRef fname
= FD
->getIdentifier()->getName();
149 if (fname
.endswith("Retain") || fname
.contains("Create") ||
150 fname
.contains("Copy")) {
151 // Do not migrate to couple of bridge transfer casts which
152 // cancel each other out. Leave it unchanged so error gets user
153 // attention instead.
154 if (FD
->getName() == "CFRetain" &&
155 FD
->getNumParams() == 1 &&
156 FD
->getParent()->isTranslationUnit() &&
157 FD
->isExternallyVisible()) {
158 Expr
*Arg
= callE
->getArg(0);
159 if (const ImplicitCastExpr
*ICE
= dyn_cast
<ImplicitCastExpr
>(Arg
)) {
160 const Expr
*sub
= ICE
->getSubExpr();
161 QualType T
= sub
->getType();
162 if (T
->isObjCObjectPointerType())
166 castToObjCObject(E
, /*retained=*/true);
170 if (fname
.contains("Get")) {
171 castToObjCObject(E
, /*retained=*/false);
178 // If returning an ivar or a member of an ivar from a +0 method, use
180 Expr
*base
= inner
->IgnoreParenImpCasts();
181 while (isa
<MemberExpr
>(base
))
182 base
= cast
<MemberExpr
>(base
)->getBase()->IgnoreParenImpCasts();
183 if (isa
<ObjCIvarRefExpr
>(base
) &&
184 isa
<ReturnStmt
>(StmtMap
->getParentIgnoreParenCasts(E
))) {
185 if (ObjCMethodDecl
*method
= dyn_cast_or_null
<ObjCMethodDecl
>(ParentD
)) {
186 if (!method
->hasAttr
<NSReturnsRetainedAttr
>()) {
187 castToObjCObject(E
, /*retained=*/false);
194 void castToObjCObject(CastExpr
*E
, bool retained
) {
195 rewriteToBridgedCast(E
, retained
? OBC_BridgeTransfer
: OBC_Bridge
);
198 void rewriteToBridgedCast(CastExpr
*E
, ObjCBridgeCastKind Kind
) {
199 Transaction
Trans(Pass
.TA
);
200 rewriteToBridgedCast(E
, Kind
, Trans
);
203 void rewriteToBridgedCast(CastExpr
*E
, ObjCBridgeCastKind Kind
,
204 Transaction
&Trans
) {
205 TransformActions
&TA
= Pass
.TA
;
207 // We will remove the compiler diagnostic.
208 if (!TA
.hasDiagnostic(diag::err_arc_mismatched_cast
,
209 diag::err_arc_cast_requires_bridge
,
218 bridge
= "__bridge "; break;
219 case OBC_BridgeTransfer
:
220 bridge
= "__bridge_transfer "; break;
221 case OBC_BridgeRetained
:
222 bridge
= "__bridge_retained "; break;
225 TA
.clearDiagnostic(diag::err_arc_mismatched_cast
,
226 diag::err_arc_cast_requires_bridge
, E
->getBeginLoc());
227 if (Kind
== OBC_Bridge
|| !Pass
.CFBridgingFunctionsDefined()) {
228 if (CStyleCastExpr
*CCE
= dyn_cast
<CStyleCastExpr
>(E
)) {
229 TA
.insertAfterToken(CCE
->getLParenLoc(), bridge
);
231 SourceLocation insertLoc
= E
->getSubExpr()->getBeginLoc();
232 SmallString
<128> newCast
;
235 newCast
+= E
->getType().getAsString(Pass
.Ctx
.getPrintingPolicy());
238 if (isa
<ParenExpr
>(E
->getSubExpr())) {
239 TA
.insert(insertLoc
, newCast
.str());
242 TA
.insert(insertLoc
, newCast
.str());
243 TA
.insertAfterToken(E
->getEndLoc(), ")");
247 assert(Kind
== OBC_BridgeTransfer
|| Kind
== OBC_BridgeRetained
);
248 SmallString
<32> BridgeCall
;
250 Expr
*WrapE
= E
->getSubExpr();
251 SourceLocation InsertLoc
= WrapE
->getBeginLoc();
253 SourceManager
&SM
= Pass
.Ctx
.getSourceManager();
254 char PrevChar
= *SM
.getCharacterData(InsertLoc
.getLocWithOffset(-1));
255 if (Lexer::isAsciiIdentifierContinueChar(PrevChar
,
256 Pass
.Ctx
.getLangOpts()))
259 if (Kind
== OBC_BridgeTransfer
)
260 BridgeCall
+= "CFBridgingRelease";
262 BridgeCall
+= "CFBridgingRetain";
264 if (isa
<ParenExpr
>(WrapE
)) {
265 TA
.insert(InsertLoc
, BridgeCall
);
268 TA
.insert(InsertLoc
, BridgeCall
);
269 TA
.insertAfterToken(WrapE
->getEndLoc(), ")");
274 void rewriteCastForCFRetain(CastExpr
*castE
, CallExpr
*callE
) {
275 Transaction
Trans(Pass
.TA
);
276 Pass
.TA
.replace(callE
->getSourceRange(), callE
->getArg(0)->getSourceRange());
277 rewriteToBridgedCast(castE
, OBC_BridgeRetained
, Trans
);
280 void getBlockMacroRanges(CastExpr
*E
, SourceRange
&Outer
, SourceRange
&Inner
) {
281 SourceManager
&SM
= Pass
.Ctx
.getSourceManager();
282 SourceLocation Loc
= E
->getExprLoc();
283 assert(Loc
.isMacroID());
284 CharSourceRange MacroRange
= SM
.getImmediateExpansionRange(Loc
);
285 SourceRange SubRange
= E
->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
286 SourceLocation InnerBegin
= SM
.getImmediateMacroCallerLoc(SubRange
.getBegin());
287 SourceLocation InnerEnd
= SM
.getImmediateMacroCallerLoc(SubRange
.getEnd());
289 Outer
= MacroRange
.getAsRange();
290 Inner
= SourceRange(InnerBegin
, InnerEnd
);
293 void rewriteBlockCopyMacro(CastExpr
*E
) {
294 SourceRange OuterRange
, InnerRange
;
295 getBlockMacroRanges(E
, OuterRange
, InnerRange
);
297 Transaction
Trans(Pass
.TA
);
298 Pass
.TA
.replace(OuterRange
, InnerRange
);
299 Pass
.TA
.insert(InnerRange
.getBegin(), "[");
300 Pass
.TA
.insertAfterToken(InnerRange
.getEnd(), " copy]");
301 Pass
.TA
.clearDiagnostic(diag::err_arc_mismatched_cast
,
302 diag::err_arc_cast_requires_bridge
,
306 void removeBlockReleaseMacro(CastExpr
*E
) {
307 SourceRange OuterRange
, InnerRange
;
308 getBlockMacroRanges(E
, OuterRange
, InnerRange
);
310 Transaction
Trans(Pass
.TA
);
311 Pass
.TA
.clearDiagnostic(diag::err_arc_mismatched_cast
,
312 diag::err_arc_cast_requires_bridge
,
314 if (!hasSideEffects(E
, Pass
.Ctx
)) {
315 if (tryRemoving(cast
<Expr
>(StmtMap
->getParentIgnoreParenCasts(E
))))
318 Pass
.TA
.replace(OuterRange
, InnerRange
);
321 bool tryRemoving(Expr
*E
) const {
323 Removables
.reset(new ExprSet
);
324 collectRemovables(Body
, *Removables
);
327 if (Removables
->count(E
)) {
328 Pass
.TA
.removeStmt(E
);
335 void transformObjCToNonObjCCast(CastExpr
*E
) {
336 SourceLocation CastLoc
= E
->getExprLoc();
337 if (CastLoc
.isMacroID()) {
338 StringRef MacroName
= Lexer::getImmediateMacroName(CastLoc
,
339 Pass
.Ctx
.getSourceManager(),
340 Pass
.Ctx
.getLangOpts());
341 if (MacroName
== "Block_copy") {
342 rewriteBlockCopyMacro(E
);
345 if (MacroName
== "Block_release") {
346 removeBlockReleaseMacro(E
);
351 if (isSelf(E
->getSubExpr()))
352 return rewriteToBridgedCast(E
, OBC_Bridge
);
355 if (isPassedToCFRetain(E
, callE
))
356 return rewriteCastForCFRetain(E
, callE
);
358 ObjCMethodFamily family
= getFamilyOfMessage(E
->getSubExpr());
359 if (family
== OMF_retain
)
360 return rewriteToBridgedCast(E
, OBC_BridgeRetained
);
362 if (family
== OMF_autorelease
|| family
== OMF_release
) {
363 std::string err
= "it is not safe to cast to '";
364 err
+= E
->getType().getAsString(Pass
.Ctx
.getPrintingPolicy());
365 err
+= "' the result of '";
366 err
+= family
== OMF_autorelease
? "autorelease" : "release";
367 err
+= "' message; a __bridge cast may result in a pointer to a "
368 "destroyed object and a __bridge_retained may leak the object";
369 Pass
.TA
.reportError(err
, E
->getBeginLoc(),
370 E
->getSubExpr()->getSourceRange());
373 parent
= StmtMap
->getParentIgnoreParenImpCasts(parent
);
374 } while (parent
&& isa
<FullExpr
>(parent
));
376 if (ReturnStmt
*retS
= dyn_cast_or_null
<ReturnStmt
>(parent
)) {
377 std::string note
= "remove the cast and change return type of function "
379 note
+= E
->getSubExpr()->getType().getAsString(Pass
.Ctx
.getPrintingPolicy());
380 note
+= "' to have the object automatically autoreleased";
381 Pass
.TA
.reportNote(note
, retS
->getBeginLoc());
385 Expr
*subExpr
= E
->getSubExpr();
387 // Look through pseudo-object expressions.
388 if (PseudoObjectExpr
*pseudo
= dyn_cast
<PseudoObjectExpr
>(subExpr
)) {
389 subExpr
= pseudo
->getResultExpr();
390 assert(subExpr
&& "no result for pseudo-object of non-void type?");
393 if (ImplicitCastExpr
*implCE
= dyn_cast
<ImplicitCastExpr
>(subExpr
)) {
394 if (implCE
->getCastKind() == CK_ARCConsumeObject
)
395 return rewriteToBridgedCast(E
, OBC_BridgeRetained
);
396 if (implCE
->getCastKind() == CK_ARCReclaimReturnedObject
)
397 return rewriteToBridgedCast(E
, OBC_Bridge
);
400 bool isConsumed
= false;
401 if (isPassedToCParamWithKnownOwnership(E
, isConsumed
))
402 return rewriteToBridgedCast(E
, isConsumed
? OBC_BridgeRetained
406 static ObjCMethodFamily
getFamilyOfMessage(Expr
*E
) {
407 E
= E
->IgnoreParenCasts();
408 if (ObjCMessageExpr
*ME
= dyn_cast
<ObjCMessageExpr
>(E
))
409 return ME
->getMethodFamily();
414 bool isPassedToCFRetain(Expr
*E
, CallExpr
*&callE
) const {
415 if ((callE
= dyn_cast_or_null
<CallExpr
>(
416 StmtMap
->getParentIgnoreParenImpCasts(E
))))
418 FD
= dyn_cast_or_null
<FunctionDecl
>(callE
->getCalleeDecl()))
419 if (FD
->getName() == "CFRetain" && FD
->getNumParams() == 1 &&
420 FD
->getParent()->isTranslationUnit() &&
421 FD
->isExternallyVisible())
427 bool isPassedToCParamWithKnownOwnership(Expr
*E
, bool &isConsumed
) const {
428 if (CallExpr
*callE
= dyn_cast_or_null
<CallExpr
>(
429 StmtMap
->getParentIgnoreParenImpCasts(E
)))
431 FD
= dyn_cast_or_null
<FunctionDecl
>(callE
->getCalleeDecl())) {
433 for (unsigned e
= callE
->getNumArgs(); i
!= e
; ++i
) {
434 Expr
*arg
= callE
->getArg(i
);
435 if (arg
== E
|| arg
->IgnoreParenImpCasts() == E
)
438 if (i
< callE
->getNumArgs() && i
< FD
->getNumParams()) {
439 ParmVarDecl
*PD
= FD
->getParamDecl(i
);
440 if (PD
->hasAttr
<CFConsumedAttr
>()) {
450 bool isSelf(Expr
*E
) const {
451 E
= E
->IgnoreParenLValueCasts();
452 if (DeclRefExpr
*DRE
= dyn_cast
<DeclRefExpr
>(E
))
453 if (ImplicitParamDecl
*IPD
= dyn_cast
<ImplicitParamDecl
>(DRE
->getDecl()))
454 if (IPD
->getIdentifier() == SelfII
)
461 } // end anonymous namespace
463 void trans::rewriteUnbridgedCasts(MigrationPass
&pass
) {
464 BodyTransform
<UnbridgedCastRewriter
> trans(pass
);
465 trans
.TraverseDecl(pass
.Ctx
.getTranslationUnitDecl());