1 //===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // removeRetainReleaseDealloc:
11 //
12 // Removes retain/release/autorelease/dealloc messages.
13 //
14 //  return [[foo retain] autorelease];
15 // ---->
16 //  return foo;
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "Transforms.h"
21 #include "Internals.h"
22 #include "clang/Sema/SemaDiagnostic.h"
23 #include "clang/AST/ParentMap.h"
24 #include "clang/Lex/Lexer.h"
25 #include "clang/Basic/SourceManager.h"
26 
27 using namespace clang;
28 using namespace arcmt;
29 using namespace trans;
30 
31 namespace {
32 
33 class RetainReleaseDeallocRemover :
34                        public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
35   Stmt *Body;
36   MigrationPass &Pass;
37 
38   ExprSet Removables;
39   OwningPtr<ParentMap> StmtMap;
40 
41   Selector DelegateSel, FinalizeSel;
42 
43 public:
44   RetainReleaseDeallocRemover(MigrationPass &pass)
45     : Body(0), Pass(pass) {
46     DelegateSel =
47         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
48     FinalizeSel =
49         Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
50   }
51 
52   void transformBody(Stmt *body) {
53     Body = body;
54     collectRemovables(body, Removables);
55     StmtMap.reset(new ParentMap(body));
56     TraverseStmt(body);
57   }
58 
59   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
60     switch (E->getMethodFamily()) {
61     default:
62       if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
63         break;
64       return true;
65     case OMF_autorelease:
66       if (isRemovable(E)) {
67         if (!isCommonUnusedAutorelease(E)) {
68           // An unused autorelease is badness. If we remove it the receiver
69           // will likely die immediately while previously it was kept alive
70           // by the autorelease pool. This is bad practice in general, leave it
71           // and emit an error to force the user to restructure his code.
72           Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
73               "message; its receiver may be destroyed immediately",
74               E->getLocStart(), E->getSourceRange());
75           return true;
76         }
77       }
78       // Pass through.
79     case OMF_retain:
80     case OMF_release:
81       if (E->getReceiverKind() == ObjCMessageExpr::Instance)
82         if (Expr *rec = E->getInstanceReceiver()) {
83           rec = rec->IgnoreParenImpCasts();
84           if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
85               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
86             std::string err = "it is not safe to remove '";
87             err += E->getSelector().getAsString() + "' message on "
88                 "an __unsafe_unretained type";
89             Pass.TA.reportError(err, rec->getLocStart());
90             return true;
91           }
92 
93           if (isGlobalVar(rec) &&
94               (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
95             std::string err = "it is not safe to remove '";
96             err += E->getSelector().getAsString() + "' message on "
97                 "a global variable";
98             Pass.TA.reportError(err, rec->getLocStart());
99             return true;
100           }
101 
102           if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
103             Pass.TA.reportError("it is not safe to remove 'retain' "
104                 "message on the result of a 'delegate' message; "
105                 "the object that was passed to 'setDelegate:' may not be "
106                 "properly retained", rec->getLocStart());
107             return true;
108           }
109         }
110     case OMF_dealloc:
111       break;
112     }
113 
114     switch (E->getReceiverKind()) {
115     default:
116       return true;
117     case ObjCMessageExpr::SuperInstance: {
118       Transaction Trans(Pass.TA);
119       clearDiagnostics(E->getSuperLoc());
120       if (tryRemoving(E))
121         return true;
122       Pass.TA.replace(E->getSourceRange(), "self");
123       return true;
124     }
125     case ObjCMessageExpr::Instance:
126       break;
127     }
128 
129     Expr *rec = E->getInstanceReceiver();
130     if (!rec) return true;
131 
132     Transaction Trans(Pass.TA);
133     clearDiagnostics(rec->getExprLoc());
134 
135     ObjCMessageExpr *Msg = E;
136     Expr *RecContainer = Msg;
137     SourceRange RecRange = rec->getSourceRange();
138     checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
139 
140     if (Msg->getMethodFamily() == OMF_release &&
141         isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
142       // Change the -release to "receiver = nil" in a finally to avoid a leak
143       // when an exception is thrown.
144       Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
145       std::string str = " = ";
146       str += getNilString(Pass.Ctx);
147       Pass.TA.insertAfterToken(RecRange.getEnd(), str);
148       return true;
149     }
150 
151     if (!hasSideEffects(rec, Pass.Ctx)) {
152       if (tryRemoving(RecContainer))
153         return true;
154     }
155     Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
156 
157     return true;
158   }
159 
160 private:
161   /// \brief Checks for idioms where an unused -autorelease is common.
162   ///
163   /// Currently only returns true for this idiom which is common in property
164   /// setters:
165   ///
166   ///   [backingValue autorelease];
167   ///   backingValue = [newValue retain]; // in general a +1 assign
168   ///
169   bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
170     Expr *Rec = E->getInstanceReceiver();
171     if (!Rec)
172       return false;
173 
174     Decl *RefD = getReferencedDecl(Rec);
175     if (!RefD)
176       return false;
177 
178     Stmt *OuterS = E, *InnerS;
179     do {
180       InnerS = OuterS;
181       OuterS = StmtMap->getParent(InnerS);
182     }
183     while (OuterS && (isa<ParenExpr>(OuterS) ||
184                       isa<CastExpr>(OuterS) ||
185                       isa<ExprWithCleanups>(OuterS)));
186 
187     if (!OuterS)
188       return false;
189 
190     // Find next statement after the -autorelease.
191 
192     Stmt::child_iterator currChildS = OuterS->child_begin();
193     Stmt::child_iterator childE = OuterS->child_end();
194     for (; currChildS != childE; ++currChildS) {
195       if (*currChildS == InnerS)
196         break;
197     }
198     if (currChildS == childE)
199       return false;
200     ++currChildS;
201     if (currChildS == childE)
202       return false;
203 
204     Stmt *nextStmt = *currChildS;
205     if (!nextStmt)
206       return false;
207     nextStmt = nextStmt->IgnoreImplicit();
208 
209     // Check for "RefD = [+1 retained object];".
210 
211     if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) {
212       if (RefD != getReferencedDecl(Bop->getLHS()))
213         return false;
214       if (isPlusOneAssign(Bop))
215         return true;
216     }
217     return false;
218   }
219 
220   Decl *getReferencedDecl(Expr *E) {
221     if (!E)
222       return 0;
223 
224     E = E->IgnoreParenCasts();
225     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
226       return DRE->getDecl();
227     if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
228       return ME->getMemberDecl();
229     if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
230       return IRE->getDecl();
231 
232     return 0;
233   }
234 
235   /// \brief Check if the retain/release is due to a GCD/XPC macro that are
236   /// defined as:
237   ///
238   /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
239   /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
240   /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
241   /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
242   ///
243   /// and return the top container which is the StmtExpr and the macro argument
244   /// expression.
245   void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
246                         Expr *&Rec, SourceRange &RecRange) {
247     SourceLocation Loc = Msg->getExprLoc();
248     if (!Loc.isMacroID())
249       return;
250     SourceManager &SM = Pass.Ctx.getSourceManager();
251     StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
252                                                      Pass.Ctx.getLangOpts());
253     bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
254         .Case("dispatch_retain", true)
255         .Case("dispatch_release", true)
256         .Case("xpc_retain", true)
257         .Case("xpc_release", true)
258         .Default(false);
259     if (!isGCDOrXPC)
260       return;
261 
262     StmtExpr *StmtE = 0;
263     Stmt *S = Msg;
264     while (S) {
265       if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
266         StmtE = SE;
267         break;
268       }
269       S = StmtMap->getParent(S);
270     }
271 
272     if (!StmtE)
273       return;
274 
275     Stmt::child_range StmtExprChild = StmtE->children();
276     if (!StmtExprChild)
277       return;
278     CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
279     if (!CompS)
280       return;
281 
282     Stmt::child_range CompStmtChild = CompS->children();
283     if (!CompStmtChild)
284       return;
285     DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
286     if (!DeclS)
287       return;
288     if (!DeclS->isSingleDecl())
289       return;
290     VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
291     if (!VD)
292       return;
293     Expr *Init = VD->getInit();
294     if (!Init)
295       return;
296 
297     RecContainer = StmtE;
298     Rec = Init->IgnoreParenImpCasts();
299     if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
300       Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
301     RecRange = Rec->getSourceRange();
302     if (SM.isMacroArgExpansion(RecRange.getBegin()))
303       RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
304     if (SM.isMacroArgExpansion(RecRange.getEnd()))
305       RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
306   }
307 
308   void clearDiagnostics(SourceLocation loc) const {
309     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
310                             diag::err_unavailable,
311                             diag::err_unavailable_message,
312                             loc);
313   }
314 
315   bool isDelegateMessage(Expr *E) const {
316     if (!E) return false;
317 
318     E = E->IgnoreParenCasts();
319 
320     // Also look through property-getter sugar.
321     if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
322       E = pseudoOp->getResultExpr()->IgnoreImplicit();
323 
324     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
325       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
326 
327     return false;
328   }
329 
330   bool isInAtFinally(Expr *E) const {
331     assert(E);
332     Stmt *S = E;
333     while (S) {
334       if (isa<ObjCAtFinallyStmt>(S))
335         return true;
336       S = StmtMap->getParent(S);
337     }
338 
339     return false;
340   }
341 
342   bool isRemovable(Expr *E) const {
343     return Removables.count(E);
344   }
345 
346   bool tryRemoving(Expr *E) const {
347     if (isRemovable(E)) {
348       Pass.TA.removeStmt(E);
349       return true;
350     }
351 
352     Stmt *parent = StmtMap->getParent(E);
353 
354     if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
355       return tryRemoving(castE);
356 
357     if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
358       return tryRemoving(parenE);
359 
360     if (BinaryOperator *
361           bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
362       if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
363           isRemovable(bopE)) {
364         Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
365         return true;
366       }
367     }
368 
369     return false;
370   }
371 
372 };
373 
374 } // anonymous namespace
375 
376 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) {
377   BodyTransform<RetainReleaseDeallocRemover> trans(pass);
378   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
379 }
380