1 //===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // removeRetainReleaseDealloc:
12 // Removes retain/release/autorelease/dealloc messages.
14 // return [[foo retain] autorelease];
18 //===----------------------------------------------------------------------===//
20 #include "Transforms.h"
21 #include "Internals.h"
22 #include "clang/AST/ASTContext.h"
23 #include "clang/AST/ParentMap.h"
24 #include "clang/Basic/SourceManager.h"
25 #include "clang/Lex/Lexer.h"
26 #include "clang/Sema/SemaDiagnostic.h"
27 #include "llvm/ADT/StringSwitch.h"
29 using namespace clang;
30 using namespace arcmt;
31 using namespace trans;
35 class RetainReleaseDeallocRemover :
36 public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
41 std::unique_ptr<ParentMap> StmtMap;
43 Selector DelegateSel, FinalizeSel;
46 RetainReleaseDeallocRemover(MigrationPass &pass)
47 : Body(nullptr), Pass(pass) {
49 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
51 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
54 void transformBody(Stmt *body, Decl *ParentD) {
56 collectRemovables(body, Removables);
57 StmtMap.reset(new ParentMap(body));
61 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
62 switch (E->getMethodFamily()) {
64 if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
69 if (!isCommonUnusedAutorelease(E)) {
70 // An unused autorelease is badness. If we remove it the receiver
71 // will likely die immediately while previously it was kept alive
72 // by the autorelease pool. This is bad practice in general, leave it
73 // and emit an error to force the user to restructure their code.
74 Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
75 "message; its receiver may be destroyed immediately",
76 E->getLocStart(), 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->getLocStart());
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->getLocStart());
105 if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
106 Pass.TA.reportError("it is not safe to remove 'retain' "
107 "message on the result of a 'delegate' message; "
108 "the object that was passed to 'setDelegate:' may not be "
109 "properly retained", rec->getLocStart());
117 switch (E->getReceiverKind()) {
120 case ObjCMessageExpr::SuperInstance: {
121 Transaction Trans(Pass.TA);
122 clearDiagnostics(E->getSelectorLoc(0));
125 Pass.TA.replace(E->getSourceRange(), "self");
128 case ObjCMessageExpr::Instance:
132 Expr *rec = E->getInstanceReceiver();
133 if (!rec) return true;
135 Transaction Trans(Pass.TA);
136 clearDiagnostics(E->getSelectorLoc(0));
138 ObjCMessageExpr *Msg = E;
139 Expr *RecContainer = Msg;
140 SourceRange RecRange = rec->getSourceRange();
141 checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
143 if (Msg->getMethodFamily() == OMF_release &&
144 isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
145 // Change the -release to "receiver = nil" in a finally to avoid a leak
146 // when an exception is thrown.
147 Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
148 std::string str = " = ";
149 str += getNilString(Pass);
150 Pass.TA.insertAfterToken(RecRange.getEnd(), str);
154 if (hasSideEffects(rec, Pass.Ctx) || !tryRemoving(RecContainer))
155 Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
161 /// \brief Checks for idioms where an unused -autorelease is common.
163 /// Returns true for this idiom which is common in property
166 /// [backingValue autorelease];
167 /// backingValue = [newValue retain]; // in general a +1 assign
169 /// For these as well:
171 /// [[var retain] autorelease];
174 bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
175 return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
176 isReturnedAfterAutorelease(E);
179 bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
180 Expr *Rec = E->getInstanceReceiver();
184 Decl *RefD = getReferencedDecl(Rec);
188 Stmt *nextStmt = getNextStmt(E);
192 // Check for "return <variable>;".
194 if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
195 return RefD == getReferencedDecl(RetS->getRetValue());
200 bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
201 Expr *Rec = E->getInstanceReceiver();
205 Decl *RefD = getReferencedDecl(Rec);
209 Stmt *prevStmt, *nextStmt;
210 std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
212 return isPlusOneAssignToVar(prevStmt, RefD) ||
213 isPlusOneAssignToVar(nextStmt, RefD);
216 bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
220 // Check for "RefD = [+1 retained object];".
222 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
223 return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop);
226 if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
227 if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
228 if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
229 return isPlusOne(VD->getInit());
237 Stmt *getNextStmt(Expr *E) {
238 return getPreviousAndNextStmt(E).second;
241 std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
242 Stmt *prevStmt = nullptr, *nextStmt = nullptr;
244 return std::make_pair(prevStmt, nextStmt);
246 Stmt *OuterS = E, *InnerS;
249 OuterS = StmtMap->getParent(InnerS);
251 while (OuterS && (isa<ParenExpr>(OuterS) ||
252 isa<CastExpr>(OuterS) ||
253 isa<ExprWithCleanups>(OuterS)));
256 return std::make_pair(prevStmt, nextStmt);
258 Stmt::child_iterator currChildS = OuterS->child_begin();
259 Stmt::child_iterator childE = OuterS->child_end();
260 Stmt::child_iterator prevChildS = childE;
261 for (; currChildS != childE; ++currChildS) {
262 if (*currChildS == InnerS)
264 prevChildS = currChildS;
267 if (prevChildS != childE) {
268 prevStmt = *prevChildS;
270 prevStmt = prevStmt->IgnoreImplicit();
273 if (currChildS == childE)
274 return std::make_pair(prevStmt, nextStmt);
276 if (currChildS == childE)
277 return std::make_pair(prevStmt, nextStmt);
279 nextStmt = *currChildS;
281 nextStmt = nextStmt->IgnoreImplicit();
283 return std::make_pair(prevStmt, nextStmt);
286 Decl *getReferencedDecl(Expr *E) {
290 E = E->IgnoreParenCasts();
291 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
292 switch (ME->getMethodFamily()) {
294 case OMF_autorelease:
297 return getReferencedDecl(ME->getInstanceReceiver());
302 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
303 return DRE->getDecl();
304 if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
305 return ME->getMemberDecl();
306 if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
307 return IRE->getDecl();
312 /// \brief Check if the retain/release is due to a GCD/XPC macro that are
315 /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
316 /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
317 /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
318 /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
320 /// and return the top container which is the StmtExpr and the macro argument
322 void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
323 Expr *&Rec, SourceRange &RecRange) {
324 SourceLocation Loc = Msg->getExprLoc();
325 if (!Loc.isMacroID())
327 SourceManager &SM = Pass.Ctx.getSourceManager();
328 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
329 Pass.Ctx.getLangOpts());
330 bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
331 .Case("dispatch_retain", true)
332 .Case("dispatch_release", true)
333 .Case("xpc_retain", true)
334 .Case("xpc_release", true)
339 StmtExpr *StmtE = nullptr;
342 if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
346 S = StmtMap->getParent(S);
352 Stmt::child_range StmtExprChild = StmtE->children();
353 if (StmtExprChild.begin() == StmtExprChild.end())
355 auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
359 Stmt::child_range CompStmtChild = CompS->children();
360 if (CompStmtChild.begin() == CompStmtChild.end())
362 auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
365 if (!DeclS->isSingleDecl())
367 VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
370 Expr *Init = VD->getInit();
374 RecContainer = StmtE;
375 Rec = Init->IgnoreParenImpCasts();
376 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
377 Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
378 RecRange = Rec->getSourceRange();
379 if (SM.isMacroArgExpansion(RecRange.getBegin()))
380 RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
381 if (SM.isMacroArgExpansion(RecRange.getEnd()))
382 RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
385 void clearDiagnostics(SourceLocation loc) const {
386 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
387 diag::err_unavailable,
388 diag::err_unavailable_message,
392 bool isDelegateMessage(Expr *E) const {
393 if (!E) return false;
395 E = E->IgnoreParenCasts();
397 // Also look through property-getter sugar.
398 if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
399 E = pseudoOp->getResultExpr()->IgnoreImplicit();
401 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
402 return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
407 bool isInAtFinally(Expr *E) const {
411 if (isa<ObjCAtFinallyStmt>(S))
413 S = StmtMap->getParent(S);
419 bool isRemovable(Expr *E) const {
420 return Removables.count(E);
423 bool tryRemoving(Expr *E) const {
424 if (isRemovable(E)) {
425 Pass.TA.removeStmt(E);
429 Stmt *parent = StmtMap->getParent(E);
431 if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
432 return tryRemoving(castE);
434 if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
435 return tryRemoving(parenE);
438 bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
439 if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
441 Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
451 } // anonymous namespace
453 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
454 BodyTransform<RetainReleaseDeallocRemover> trans(pass);
455 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());