1 //===--- TransRetainReleaseDealloc.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 // removeRetainReleaseDealloc:
11 // Removes retain/release/autorelease/dealloc messages.
13 // return [[foo retain] autorelease];
17 //===----------------------------------------------------------------------===//
19 #include "Transforms.h"
20 #include "Internals.h"
21 #include "clang/AST/ASTContext.h"
22 #include "clang/AST/ParentMap.h"
23 #include "clang/Basic/SourceManager.h"
24 #include "clang/Lex/Lexer.h"
25 #include "clang/Sema/SemaDiagnostic.h"
26 #include "llvm/ADT/StringSwitch.h"
28 using namespace clang
;
29 using namespace arcmt
;
30 using namespace trans
;
34 class RetainReleaseDeallocRemover
:
35 public RecursiveASTVisitor
<RetainReleaseDeallocRemover
> {
40 std::unique_ptr
<ParentMap
> StmtMap
;
42 Selector DelegateSel
, FinalizeSel
;
45 RetainReleaseDeallocRemover(MigrationPass
&pass
)
46 : Body(nullptr), Pass(pass
) {
48 Pass
.Ctx
.Selectors
.getNullarySelector(&Pass
.Ctx
.Idents
.get("delegate"));
50 Pass
.Ctx
.Selectors
.getNullarySelector(&Pass
.Ctx
.Idents
.get("finalize"));
53 void transformBody(Stmt
*body
, Decl
*ParentD
) {
55 collectRemovables(body
, Removables
);
56 StmtMap
.reset(new ParentMap(body
));
60 bool VisitObjCMessageExpr(ObjCMessageExpr
*E
) {
61 switch (E
->getMethodFamily()) {
63 if (E
->isInstanceMessage() && E
->getSelector() == FinalizeSel
)
68 if (!isCommonUnusedAutorelease(E
)) {
69 // An unused autorelease is badness. If we remove it the receiver
70 // will likely die immediately while previously it was kept alive
71 // by the autorelease pool. This is bad practice in general, leave it
72 // and emit an error to force the user to restructure their code.
74 "it is not safe to remove an unused 'autorelease' "
75 "message; its receiver may be destroyed immediately",
76 E
->getBeginLoc(), E
->getSourceRange());
84 if (E
->getReceiverKind() == ObjCMessageExpr::Instance
)
85 if (Expr
*rec
= E
->getInstanceReceiver()) {
86 rec
= rec
->IgnoreParenImpCasts();
87 if (rec
->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone
&&
88 (E
->getMethodFamily() != OMF_retain
|| isRemovable(E
))) {
89 std::string err
= "it is not safe to remove '";
90 err
+= E
->getSelector().getAsString() + "' message on "
91 "an __unsafe_unretained type";
92 Pass
.TA
.reportError(err
, rec
->getBeginLoc());
96 if (isGlobalVar(rec
) &&
97 (E
->getMethodFamily() != OMF_retain
|| isRemovable(E
))) {
98 std::string err
= "it is not safe to remove '";
99 err
+= E
->getSelector().getAsString() + "' message on "
101 Pass
.TA
.reportError(err
, rec
->getBeginLoc());
105 if (E
->getMethodFamily() == OMF_release
&& isDelegateMessage(rec
)) {
107 "it is not safe to remove 'retain' "
108 "message on the result of a 'delegate' message; "
109 "the object that was passed to 'setDelegate:' may not be "
120 switch (E
->getReceiverKind()) {
123 case ObjCMessageExpr::SuperInstance
: {
124 Transaction
Trans(Pass
.TA
);
125 clearDiagnostics(E
->getSelectorLoc(0));
128 Pass
.TA
.replace(E
->getSourceRange(), "self");
131 case ObjCMessageExpr::Instance
:
135 Expr
*rec
= E
->getInstanceReceiver();
136 if (!rec
) return true;
138 Transaction
Trans(Pass
.TA
);
139 clearDiagnostics(E
->getSelectorLoc(0));
141 ObjCMessageExpr
*Msg
= E
;
142 Expr
*RecContainer
= Msg
;
143 SourceRange RecRange
= rec
->getSourceRange();
144 checkForGCDOrXPC(Msg
, RecContainer
, rec
, RecRange
);
146 if (Msg
->getMethodFamily() == OMF_release
&&
147 isRemovable(RecContainer
) && isInAtFinally(RecContainer
)) {
148 // Change the -release to "receiver = nil" in a finally to avoid a leak
149 // when an exception is thrown.
150 Pass
.TA
.replace(RecContainer
->getSourceRange(), RecRange
);
151 std::string str
= " = ";
152 str
+= getNilString(Pass
);
153 Pass
.TA
.insertAfterToken(RecRange
.getEnd(), str
);
157 if (hasSideEffects(rec
, Pass
.Ctx
) || !tryRemoving(RecContainer
))
158 Pass
.TA
.replace(RecContainer
->getSourceRange(), RecRange
);
164 /// Checks for idioms where an unused -autorelease is common.
166 /// Returns true for this idiom which is common in property
169 /// [backingValue autorelease];
170 /// backingValue = [newValue retain]; // in general a +1 assign
172 /// For these as well:
174 /// [[var retain] autorelease];
177 bool isCommonUnusedAutorelease(ObjCMessageExpr
*E
) {
178 return isPlusOneAssignBeforeOrAfterAutorelease(E
) ||
179 isReturnedAfterAutorelease(E
);
182 bool isReturnedAfterAutorelease(ObjCMessageExpr
*E
) {
183 Expr
*Rec
= E
->getInstanceReceiver();
187 Decl
*RefD
= getReferencedDecl(Rec
);
191 Stmt
*nextStmt
= getNextStmt(E
);
195 // Check for "return <variable>;".
197 if (ReturnStmt
*RetS
= dyn_cast
<ReturnStmt
>(nextStmt
))
198 return RefD
== getReferencedDecl(RetS
->getRetValue());
203 bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr
*E
) {
204 Expr
*Rec
= E
->getInstanceReceiver();
208 Decl
*RefD
= getReferencedDecl(Rec
);
212 Stmt
*prevStmt
, *nextStmt
;
213 std::tie(prevStmt
, nextStmt
) = getPreviousAndNextStmt(E
);
215 return isPlusOneAssignToVar(prevStmt
, RefD
) ||
216 isPlusOneAssignToVar(nextStmt
, RefD
);
219 bool isPlusOneAssignToVar(Stmt
*S
, Decl
*RefD
) {
223 // Check for "RefD = [+1 retained object];".
225 if (BinaryOperator
*Bop
= dyn_cast
<BinaryOperator
>(S
)) {
226 return (RefD
== getReferencedDecl(Bop
->getLHS())) && isPlusOneAssign(Bop
);
229 if (DeclStmt
*DS
= dyn_cast
<DeclStmt
>(S
)) {
230 if (DS
->isSingleDecl() && DS
->getSingleDecl() == RefD
) {
231 if (VarDecl
*VD
= dyn_cast
<VarDecl
>(RefD
))
232 return isPlusOne(VD
->getInit());
240 Stmt
*getNextStmt(Expr
*E
) {
241 return getPreviousAndNextStmt(E
).second
;
244 std::pair
<Stmt
*, Stmt
*> getPreviousAndNextStmt(Expr
*E
) {
245 Stmt
*prevStmt
= nullptr, *nextStmt
= nullptr;
247 return std::make_pair(prevStmt
, nextStmt
);
249 Stmt
*OuterS
= E
, *InnerS
;
252 OuterS
= StmtMap
->getParent(InnerS
);
254 while (OuterS
&& (isa
<ParenExpr
>(OuterS
) ||
255 isa
<CastExpr
>(OuterS
) ||
256 isa
<FullExpr
>(OuterS
)));
259 return std::make_pair(prevStmt
, nextStmt
);
261 Stmt::child_iterator currChildS
= OuterS
->child_begin();
262 Stmt::child_iterator childE
= OuterS
->child_end();
263 Stmt::child_iterator prevChildS
= childE
;
264 for (; currChildS
!= childE
; ++currChildS
) {
265 if (*currChildS
== InnerS
)
267 prevChildS
= currChildS
;
270 if (prevChildS
!= childE
) {
271 prevStmt
= *prevChildS
;
272 if (auto *E
= dyn_cast_or_null
<Expr
>(prevStmt
))
273 prevStmt
= E
->IgnoreImplicit();
276 if (currChildS
== childE
)
277 return std::make_pair(prevStmt
, nextStmt
);
279 if (currChildS
== childE
)
280 return std::make_pair(prevStmt
, nextStmt
);
282 nextStmt
= *currChildS
;
283 if (auto *E
= dyn_cast_or_null
<Expr
>(nextStmt
))
284 nextStmt
= E
->IgnoreImplicit();
286 return std::make_pair(prevStmt
, nextStmt
);
289 Decl
*getReferencedDecl(Expr
*E
) {
293 E
= E
->IgnoreParenCasts();
294 if (ObjCMessageExpr
*ME
= dyn_cast
<ObjCMessageExpr
>(E
)) {
295 switch (ME
->getMethodFamily()) {
297 case OMF_autorelease
:
300 return getReferencedDecl(ME
->getInstanceReceiver());
305 if (DeclRefExpr
*DRE
= dyn_cast
<DeclRefExpr
>(E
))
306 return DRE
->getDecl();
307 if (MemberExpr
*ME
= dyn_cast
<MemberExpr
>(E
))
308 return ME
->getMemberDecl();
309 if (ObjCIvarRefExpr
*IRE
= dyn_cast
<ObjCIvarRefExpr
>(E
))
310 return IRE
->getDecl();
315 /// Check if the retain/release is due to a GCD/XPC macro that are
318 /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
319 /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
320 /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
321 /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
323 /// and return the top container which is the StmtExpr and the macro argument
325 void checkForGCDOrXPC(ObjCMessageExpr
*Msg
, Expr
*&RecContainer
,
326 Expr
*&Rec
, SourceRange
&RecRange
) {
327 SourceLocation Loc
= Msg
->getExprLoc();
328 if (!Loc
.isMacroID())
330 SourceManager
&SM
= Pass
.Ctx
.getSourceManager();
331 StringRef MacroName
= Lexer::getImmediateMacroName(Loc
, SM
,
332 Pass
.Ctx
.getLangOpts());
333 bool isGCDOrXPC
= llvm::StringSwitch
<bool>(MacroName
)
334 .Case("dispatch_retain", true)
335 .Case("dispatch_release", true)
336 .Case("xpc_retain", true)
337 .Case("xpc_release", true)
342 StmtExpr
*StmtE
= nullptr;
345 if (StmtExpr
*SE
= dyn_cast
<StmtExpr
>(S
)) {
349 S
= StmtMap
->getParent(S
);
355 Stmt::child_range StmtExprChild
= StmtE
->children();
356 if (StmtExprChild
.begin() == StmtExprChild
.end())
358 auto *CompS
= dyn_cast_or_null
<CompoundStmt
>(*StmtExprChild
.begin());
362 Stmt::child_range CompStmtChild
= CompS
->children();
363 if (CompStmtChild
.begin() == CompStmtChild
.end())
365 auto *DeclS
= dyn_cast_or_null
<DeclStmt
>(*CompStmtChild
.begin());
368 if (!DeclS
->isSingleDecl())
370 VarDecl
*VD
= dyn_cast_or_null
<VarDecl
>(DeclS
->getSingleDecl());
373 Expr
*Init
= VD
->getInit();
377 RecContainer
= StmtE
;
378 Rec
= Init
->IgnoreParenImpCasts();
379 if (FullExpr
*FE
= dyn_cast
<FullExpr
>(Rec
))
380 Rec
= FE
->getSubExpr()->IgnoreParenImpCasts();
381 RecRange
= Rec
->getSourceRange();
382 if (SM
.isMacroArgExpansion(RecRange
.getBegin()))
383 RecRange
.setBegin(SM
.getImmediateSpellingLoc(RecRange
.getBegin()));
384 if (SM
.isMacroArgExpansion(RecRange
.getEnd()))
385 RecRange
.setEnd(SM
.getImmediateSpellingLoc(RecRange
.getEnd()));
388 void clearDiagnostics(SourceLocation loc
) const {
389 Pass
.TA
.clearDiagnostic(diag::err_arc_illegal_explicit_message
,
390 diag::err_unavailable
,
391 diag::err_unavailable_message
,
395 bool isDelegateMessage(Expr
*E
) const {
396 if (!E
) return false;
398 E
= E
->IgnoreParenCasts();
400 // Also look through property-getter sugar.
401 if (PseudoObjectExpr
*pseudoOp
= dyn_cast
<PseudoObjectExpr
>(E
))
402 E
= pseudoOp
->getResultExpr()->IgnoreImplicit();
404 if (ObjCMessageExpr
*ME
= dyn_cast
<ObjCMessageExpr
>(E
))
405 return (ME
->isInstanceMessage() && ME
->getSelector() == DelegateSel
);
410 bool isInAtFinally(Expr
*E
) const {
414 if (isa
<ObjCAtFinallyStmt
>(S
))
416 S
= StmtMap
->getParent(S
);
422 bool isRemovable(Expr
*E
) const {
423 return Removables
.count(E
);
426 bool tryRemoving(Expr
*E
) const {
427 if (isRemovable(E
)) {
428 Pass
.TA
.removeStmt(E
);
432 Stmt
*parent
= StmtMap
->getParent(E
);
434 if (ImplicitCastExpr
*castE
= dyn_cast_or_null
<ImplicitCastExpr
>(parent
))
435 return tryRemoving(castE
);
437 if (ParenExpr
*parenE
= dyn_cast_or_null
<ParenExpr
>(parent
))
438 return tryRemoving(parenE
);
441 bopE
= dyn_cast_or_null
<BinaryOperator
>(parent
)) {
442 if (bopE
->getOpcode() == BO_Comma
&& bopE
->getLHS() == E
&&
444 Pass
.TA
.replace(bopE
->getSourceRange(), bopE
->getRHS()->getSourceRange());
454 } // anonymous namespace
456 void trans::removeRetainReleaseDeallocFinalize(MigrationPass
&pass
) {
457 BodyTransform
<RetainReleaseDeallocRemover
> trans(pass
);
458 trans
.TraverseDecl(pass
.Ctx
.getTranslationUnitDecl());