clang  8.0.0svn
TransRetainReleaseDealloc.cpp
Go to the documentation of this file.
1 //===--- TransRetainReleaseDealloc.cpp - Transformations 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/AST/ASTContext.h"
23 #include "clang/AST/ParentMap.h"
25 #include "clang/Lex/Lexer.h"
27 #include "llvm/ADT/StringSwitch.h"
28 
29 using namespace clang;
30 using namespace arcmt;
31 using namespace trans;
32 
33 namespace {
34 
35 class RetainReleaseDeallocRemover :
36  public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
37  Stmt *Body;
38  MigrationPass &Pass;
39 
40  ExprSet Removables;
41  std::unique_ptr<ParentMap> StmtMap;
42 
43  Selector DelegateSel, FinalizeSel;
44 
45 public:
46  RetainReleaseDeallocRemover(MigrationPass &pass)
47  : Body(nullptr), Pass(pass) {
48  DelegateSel =
49  Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
50  FinalizeSel =
51  Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
52  }
53 
54  void transformBody(Stmt *body, Decl *ParentD) {
55  Body = body;
56  collectRemovables(body, Removables);
57  StmtMap.reset(new ParentMap(body));
58  TraverseStmt(body);
59  }
60 
61  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
62  switch (E->getMethodFamily()) {
63  default:
64  if (E->isInstanceMessage() && E->getSelector() == FinalizeSel)
65  break;
66  return true;
67  case OMF_autorelease:
68  if (isRemovable(E)) {
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(
75  "it is not safe to remove an unused 'autorelease' "
76  "message; its receiver may be destroyed immediately",
77  E->getBeginLoc(), E->getSourceRange());
78  return true;
79  }
80  }
81  // Pass through.
82  LLVM_FALLTHROUGH;
83  case OMF_retain:
84  case OMF_release:
86  if (Expr *rec = E->getInstanceReceiver()) {
87  rec = rec->IgnoreParenImpCasts();
88  if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
89  (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
90  std::string err = "it is not safe to remove '";
91  err += E->getSelector().getAsString() + "' message on "
92  "an __unsafe_unretained type";
93  Pass.TA.reportError(err, rec->getBeginLoc());
94  return true;
95  }
96 
97  if (isGlobalVar(rec) &&
98  (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
99  std::string err = "it is not safe to remove '";
100  err += E->getSelector().getAsString() + "' message on "
101  "a global variable";
102  Pass.TA.reportError(err, rec->getBeginLoc());
103  return true;
104  }
105 
106  if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) {
107  Pass.TA.reportError(
108  "it is not safe to remove 'retain' "
109  "message on the result of a 'delegate' message; "
110  "the object that was passed to 'setDelegate:' may not be "
111  "properly retained",
112  rec->getBeginLoc());
113  return true;
114  }
115  }
116  break;
117  case OMF_dealloc:
118  break;
119  }
120 
121  switch (E->getReceiverKind()) {
122  default:
123  return true;
125  Transaction Trans(Pass.TA);
126  clearDiagnostics(E->getSelectorLoc(0));
127  if (tryRemoving(E))
128  return true;
129  Pass.TA.replace(E->getSourceRange(), "self");
130  return true;
131  }
133  break;
134  }
135 
136  Expr *rec = E->getInstanceReceiver();
137  if (!rec) return true;
138 
139  Transaction Trans(Pass.TA);
140  clearDiagnostics(E->getSelectorLoc(0));
141 
142  ObjCMessageExpr *Msg = E;
143  Expr *RecContainer = Msg;
144  SourceRange RecRange = rec->getSourceRange();
145  checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
146 
147  if (Msg->getMethodFamily() == OMF_release &&
148  isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
149  // Change the -release to "receiver = nil" in a finally to avoid a leak
150  // when an exception is thrown.
151  Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
152  std::string str = " = ";
153  str += getNilString(Pass);
154  Pass.TA.insertAfterToken(RecRange.getEnd(), str);
155  return true;
156  }
157 
158  if (hasSideEffects(rec, Pass.Ctx) || !tryRemoving(RecContainer))
159  Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
160 
161  return true;
162  }
163 
164 private:
165  /// Checks for idioms where an unused -autorelease is common.
166  ///
167  /// Returns true for this idiom which is common in property
168  /// setters:
169  ///
170  /// [backingValue autorelease];
171  /// backingValue = [newValue retain]; // in general a +1 assign
172  ///
173  /// For these as well:
174  ///
175  /// [[var retain] autorelease];
176  /// return var;
177  ///
178  bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
179  return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
180  isReturnedAfterAutorelease(E);
181  }
182 
183  bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
184  Expr *Rec = E->getInstanceReceiver();
185  if (!Rec)
186  return false;
187 
188  Decl *RefD = getReferencedDecl(Rec);
189  if (!RefD)
190  return false;
191 
192  Stmt *nextStmt = getNextStmt(E);
193  if (!nextStmt)
194  return false;
195 
196  // Check for "return <variable>;".
197 
198  if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
199  return RefD == getReferencedDecl(RetS->getRetValue());
200 
201  return false;
202  }
203 
204  bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
205  Expr *Rec = E->getInstanceReceiver();
206  if (!Rec)
207  return false;
208 
209  Decl *RefD = getReferencedDecl(Rec);
210  if (!RefD)
211  return false;
212 
213  Stmt *prevStmt, *nextStmt;
214  std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
215 
216  return isPlusOneAssignToVar(prevStmt, RefD) ||
217  isPlusOneAssignToVar(nextStmt, RefD);
218  }
219 
220  bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
221  if (!S)
222  return false;
223 
224  // Check for "RefD = [+1 retained object];".
225 
226  if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
227  return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop);
228  }
229 
230  if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
231  if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
232  if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
233  return isPlusOne(VD->getInit());
234  }
235  return false;
236  }
237 
238  return false;
239  }
240 
241  Stmt *getNextStmt(Expr *E) {
242  return getPreviousAndNextStmt(E).second;
243  }
244 
245  std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
246  Stmt *prevStmt = nullptr, *nextStmt = nullptr;
247  if (!E)
248  return std::make_pair(prevStmt, nextStmt);
249 
250  Stmt *OuterS = E, *InnerS;
251  do {
252  InnerS = OuterS;
253  OuterS = StmtMap->getParent(InnerS);
254  }
255  while (OuterS && (isa<ParenExpr>(OuterS) ||
256  isa<CastExpr>(OuterS) ||
257  isa<FullExpr>(OuterS)));
258 
259  if (!OuterS)
260  return std::make_pair(prevStmt, nextStmt);
261 
262  Stmt::child_iterator currChildS = OuterS->child_begin();
263  Stmt::child_iterator childE = OuterS->child_end();
264  Stmt::child_iterator prevChildS = childE;
265  for (; currChildS != childE; ++currChildS) {
266  if (*currChildS == InnerS)
267  break;
268  prevChildS = currChildS;
269  }
270 
271  if (prevChildS != childE) {
272  prevStmt = *prevChildS;
273  if (prevStmt)
274  prevStmt = prevStmt->IgnoreImplicit();
275  }
276 
277  if (currChildS == childE)
278  return std::make_pair(prevStmt, nextStmt);
279  ++currChildS;
280  if (currChildS == childE)
281  return std::make_pair(prevStmt, nextStmt);
282 
283  nextStmt = *currChildS;
284  if (nextStmt)
285  nextStmt = nextStmt->IgnoreImplicit();
286 
287  return std::make_pair(prevStmt, nextStmt);
288  }
289 
290  Decl *getReferencedDecl(Expr *E) {
291  if (!E)
292  return nullptr;
293 
294  E = E->IgnoreParenCasts();
295  if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
296  switch (ME->getMethodFamily()) {
297  case OMF_copy:
298  case OMF_autorelease:
299  case OMF_release:
300  case OMF_retain:
301  return getReferencedDecl(ME->getInstanceReceiver());
302  default:
303  return nullptr;
304  }
305  }
306  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
307  return DRE->getDecl();
308  if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
309  return ME->getMemberDecl();
310  if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
311  return IRE->getDecl();
312 
313  return nullptr;
314  }
315 
316  /// Check if the retain/release is due to a GCD/XPC macro that are
317  /// defined as:
318  ///
319  /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
320  /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
321  /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
322  /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
323  ///
324  /// and return the top container which is the StmtExpr and the macro argument
325  /// expression.
326  void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
327  Expr *&Rec, SourceRange &RecRange) {
328  SourceLocation Loc = Msg->getExprLoc();
329  if (!Loc.isMacroID())
330  return;
332  StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
333  Pass.Ctx.getLangOpts());
334  bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
335  .Case("dispatch_retain", true)
336  .Case("dispatch_release", true)
337  .Case("xpc_retain", true)
338  .Case("xpc_release", true)
339  .Default(false);
340  if (!isGCDOrXPC)
341  return;
342 
343  StmtExpr *StmtE = nullptr;
344  Stmt *S = Msg;
345  while (S) {
346  if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
347  StmtE = SE;
348  break;
349  }
350  S = StmtMap->getParent(S);
351  }
352 
353  if (!StmtE)
354  return;
355 
356  Stmt::child_range StmtExprChild = StmtE->children();
357  if (StmtExprChild.begin() == StmtExprChild.end())
358  return;
359  auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
360  if (!CompS)
361  return;
362 
363  Stmt::child_range CompStmtChild = CompS->children();
364  if (CompStmtChild.begin() == CompStmtChild.end())
365  return;
366  auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
367  if (!DeclS)
368  return;
369  if (!DeclS->isSingleDecl())
370  return;
371  VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
372  if (!VD)
373  return;
374  Expr *Init = VD->getInit();
375  if (!Init)
376  return;
377 
378  RecContainer = StmtE;
379  Rec = Init->IgnoreParenImpCasts();
380  if (FullExpr *FE = dyn_cast<FullExpr>(Rec))
381  Rec = FE->getSubExpr()->IgnoreParenImpCasts();
382  RecRange = Rec->getSourceRange();
383  if (SM.isMacroArgExpansion(RecRange.getBegin()))
384  RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
385  if (SM.isMacroArgExpansion(RecRange.getEnd()))
386  RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
387  }
388 
389  void clearDiagnostics(SourceLocation loc) const {
390  Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
391  diag::err_unavailable,
392  diag::err_unavailable_message,
393  loc);
394  }
395 
396  bool isDelegateMessage(Expr *E) const {
397  if (!E) return false;
398 
399  E = E->IgnoreParenCasts();
400 
401  // Also look through property-getter sugar.
402  if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
403  E = pseudoOp->getResultExpr()->IgnoreImplicit();
404 
405  if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
406  return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
407 
408  return false;
409  }
410 
411  bool isInAtFinally(Expr *E) const {
412  assert(E);
413  Stmt *S = E;
414  while (S) {
415  if (isa<ObjCAtFinallyStmt>(S))
416  return true;
417  S = StmtMap->getParent(S);
418  }
419 
420  return false;
421  }
422 
423  bool isRemovable(Expr *E) const {
424  return Removables.count(E);
425  }
426 
427  bool tryRemoving(Expr *E) const {
428  if (isRemovable(E)) {
429  Pass.TA.removeStmt(E);
430  return true;
431  }
432 
433  Stmt *parent = StmtMap->getParent(E);
434 
435  if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
436  return tryRemoving(castE);
437 
438  if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
439  return tryRemoving(parenE);
440 
441  if (BinaryOperator *
442  bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
443  if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
444  isRemovable(bopE)) {
445  Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
446  return true;
447  }
448  }
449 
450  return false;
451  }
452 
453 };
454 
455 } // anonymous namespace
456 
460 }
child_iterator child_begin()
Definition: Stmt.h:891
The receiver is the instance of the superclass object.
Definition: ExprObjC.h:1061
Defines the clang::ASTContext interface.
The receiver is an object instance.
Definition: ExprObjC.h:1055
Smart pointer class that efficiently represents Objective-C method names.
Selector getSelector() const
Definition: ExprObjC.cpp:312
Stmt - This represents one statement.
Definition: Stmt.h:66
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:87
ParenExpr - This represents a parethesized expression, e.g.
Definition: Expr.h:1855
llvm::iterator_range< child_iterator > child_range
Definition: Stmt.h:881
Stmt * IgnoreImplicit()
Skip past any implicit AST nodes which might surround this statement, such as ExprWithCleanups or Imp...
Definition: Stmt.cpp:121
Represents a variable declaration or definition.
Definition: Decl.h:812
Expr * IgnoreImplicit() LLVM_READONLY
IgnoreImplicit - Skip past any implicit AST nodes which might surround this expression.
Definition: Expr.h:747
void setBegin(SourceLocation b)
child_range children()
Definition: Expr.h:3795
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument&#39;s dynamic ty...
FullExpr - Represents a "full-expression" node.
Definition: Expr.h:877
bool isGlobalVar(Expr *E)
Definition: Transforms.cpp:197
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
IdentifierTable & Idents
Definition: ASTContext.h:565
Selector getNullarySelector(IdentifierInfo *ID)
void removeRetainReleaseDeallocFinalize(MigrationPass &pass)
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3248
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2556
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool isPlusOneAssign(const BinaryOperator *E)
Definition: Transforms.cpp:67
This object can be modified without requiring retains or releases.
Definition: Type.h:162
return Out str()
StringRef getNilString(MigrationPass &Pass)
Returns "nil" or "0" if &#39;nil&#39; macro is not actually defined.
Definition: Transforms.cpp:209
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
void collectRemovables(Stmt *S, ExprSet &exprs)
Definition: Transforms.cpp:308
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
This represents one expression.
Definition: Expr.h:106
void insertAfterToken(SourceLocation loc, StringRef text)
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Definition: Stmt.h:2226
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:904
SourceLocation getEnd() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition: ExprObjC.h:1188
const SourceManager & SM
Definition: Format.cpp:1490
std::string getAsString() const
Derive the full selector name (e.g.
SelectorTable & Selectors
Definition: ASTContext.h:566
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Definition: Expr.h:5260
Encodes a location in the source.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
ObjCMethodFamily getMethodFamily() const
Definition: ExprObjC.h:1322
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Definition: Stmt.h:926
SourceLocation getSelectorLoc(unsigned Index) const
Definition: ExprObjC.h:1372
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:3066
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition: Expr.h:3762
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
Definition: Lexer.cpp:968
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:215
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1207
Dataflow Directional Tag Classes.
bool hasSideEffects(Expr *E, ASTContext &Ctx)
Definition: Transforms.cpp:168
const Expr * getInit() const
Definition: Decl.h:1219
bool isPlusOne(const Expr *E)
Definition: Transforms.cpp:74
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
Definition: Expr.cpp:2654
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument&#39;s expansion into the function-lik...
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:513
SourceManager & getSourceManager()
Definition: ASTContext.h:661
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1008
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2616
void replace(SourceRange range, StringRef text)
TransformActions & TA
Definition: Internals.h:151
void setEnd(SourceLocation e)
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: ExprObjC.h:1399
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:276
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1042
A trivial tuple used to represent a source range.
bool isInstanceMessage() const
Determine whether this is an instance message to either a computed object or to super.
Definition: ExprObjC.h:1195
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
Definition: ASTContext.h:706
This class handles loading and caching of source files into memory.
child_iterator child_end()
Definition: Stmt.h:892