clang  6.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("it is not safe to remove an unused 'autorelease' "
75  "message; its receiver may be destroyed immediately",
76  E->getLocStart(), E->getSourceRange());
77  return true;
78  }
79  }
80  // Pass through.
81  LLVM_FALLTHROUGH;
82  case OMF_retain:
83  case OMF_release:
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());
93  return true;
94  }
95 
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 "
100  "a global variable";
101  Pass.TA.reportError(err, rec->getLocStart());
102  return true;
103  }
104 
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());
110  return true;
111  }
112  }
113  case OMF_dealloc:
114  break;
115  }
116 
117  switch (E->getReceiverKind()) {
118  default:
119  return true;
121  Transaction Trans(Pass.TA);
122  clearDiagnostics(E->getSelectorLoc(0));
123  if (tryRemoving(E))
124  return true;
125  Pass.TA.replace(E->getSourceRange(), "self");
126  return true;
127  }
129  break;
130  }
131 
132  Expr *rec = E->getInstanceReceiver();
133  if (!rec) return true;
134 
135  Transaction Trans(Pass.TA);
136  clearDiagnostics(E->getSelectorLoc(0));
137 
138  ObjCMessageExpr *Msg = E;
139  Expr *RecContainer = Msg;
140  SourceRange RecRange = rec->getSourceRange();
141  checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
142 
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);
151  return true;
152  }
153 
154  if (hasSideEffects(rec, Pass.Ctx) || !tryRemoving(RecContainer))
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  /// 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  /// For these as well:
170  ///
171  /// [[var retain] autorelease];
172  /// return var;
173  ///
174  bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
175  return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
176  isReturnedAfterAutorelease(E);
177  }
178 
179  bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
180  Expr *Rec = E->getInstanceReceiver();
181  if (!Rec)
182  return false;
183 
184  Decl *RefD = getReferencedDecl(Rec);
185  if (!RefD)
186  return false;
187 
188  Stmt *nextStmt = getNextStmt(E);
189  if (!nextStmt)
190  return false;
191 
192  // Check for "return <variable>;".
193 
194  if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
195  return RefD == getReferencedDecl(RetS->getRetValue());
196 
197  return false;
198  }
199 
200  bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
201  Expr *Rec = E->getInstanceReceiver();
202  if (!Rec)
203  return false;
204 
205  Decl *RefD = getReferencedDecl(Rec);
206  if (!RefD)
207  return false;
208 
209  Stmt *prevStmt, *nextStmt;
210  std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
211 
212  return isPlusOneAssignToVar(prevStmt, RefD) ||
213  isPlusOneAssignToVar(nextStmt, RefD);
214  }
215 
216  bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
217  if (!S)
218  return false;
219 
220  // Check for "RefD = [+1 retained object];".
221 
222  if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
223  return (RefD == getReferencedDecl(Bop->getLHS())) && isPlusOneAssign(Bop);
224  }
225 
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());
230  }
231  return false;
232  }
233 
234  return false;
235  }
236 
237  Stmt *getNextStmt(Expr *E) {
238  return getPreviousAndNextStmt(E).second;
239  }
240 
241  std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
242  Stmt *prevStmt = nullptr, *nextStmt = nullptr;
243  if (!E)
244  return std::make_pair(prevStmt, nextStmt);
245 
246  Stmt *OuterS = E, *InnerS;
247  do {
248  InnerS = OuterS;
249  OuterS = StmtMap->getParent(InnerS);
250  }
251  while (OuterS && (isa<ParenExpr>(OuterS) ||
252  isa<CastExpr>(OuterS) ||
253  isa<ExprWithCleanups>(OuterS)));
254 
255  if (!OuterS)
256  return std::make_pair(prevStmt, nextStmt);
257 
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)
263  break;
264  prevChildS = currChildS;
265  }
266 
267  if (prevChildS != childE) {
268  prevStmt = *prevChildS;
269  if (prevStmt)
270  prevStmt = prevStmt->IgnoreImplicit();
271  }
272 
273  if (currChildS == childE)
274  return std::make_pair(prevStmt, nextStmt);
275  ++currChildS;
276  if (currChildS == childE)
277  return std::make_pair(prevStmt, nextStmt);
278 
279  nextStmt = *currChildS;
280  if (nextStmt)
281  nextStmt = nextStmt->IgnoreImplicit();
282 
283  return std::make_pair(prevStmt, nextStmt);
284  }
285 
286  Decl *getReferencedDecl(Expr *E) {
287  if (!E)
288  return nullptr;
289 
290  E = E->IgnoreParenCasts();
291  if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
292  switch (ME->getMethodFamily()) {
293  case OMF_copy:
294  case OMF_autorelease:
295  case OMF_release:
296  case OMF_retain:
297  return getReferencedDecl(ME->getInstanceReceiver());
298  default:
299  return nullptr;
300  }
301  }
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();
308 
309  return nullptr;
310  }
311 
312  /// \brief Check if the retain/release is due to a GCD/XPC macro that are
313  /// defined as:
314  ///
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]; })
319  ///
320  /// and return the top container which is the StmtExpr and the macro argument
321  /// expression.
322  void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
323  Expr *&Rec, SourceRange &RecRange) {
324  SourceLocation Loc = Msg->getExprLoc();
325  if (!Loc.isMacroID())
326  return;
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)
335  .Default(false);
336  if (!isGCDOrXPC)
337  return;
338 
339  StmtExpr *StmtE = nullptr;
340  Stmt *S = Msg;
341  while (S) {
342  if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
343  StmtE = SE;
344  break;
345  }
346  S = StmtMap->getParent(S);
347  }
348 
349  if (!StmtE)
350  return;
351 
352  Stmt::child_range StmtExprChild = StmtE->children();
353  if (StmtExprChild.begin() == StmtExprChild.end())
354  return;
355  auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
356  if (!CompS)
357  return;
358 
359  Stmt::child_range CompStmtChild = CompS->children();
360  if (CompStmtChild.begin() == CompStmtChild.end())
361  return;
362  auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
363  if (!DeclS)
364  return;
365  if (!DeclS->isSingleDecl())
366  return;
367  VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
368  if (!VD)
369  return;
370  Expr *Init = VD->getInit();
371  if (!Init)
372  return;
373 
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()));
383  }
384 
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,
389  loc);
390  }
391 
392  bool isDelegateMessage(Expr *E) const {
393  if (!E) return false;
394 
395  E = E->IgnoreParenCasts();
396 
397  // Also look through property-getter sugar.
398  if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
399  E = pseudoOp->getResultExpr()->IgnoreImplicit();
400 
401  if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
402  return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
403 
404  return false;
405  }
406 
407  bool isInAtFinally(Expr *E) const {
408  assert(E);
409  Stmt *S = E;
410  while (S) {
411  if (isa<ObjCAtFinallyStmt>(S))
412  return true;
413  S = StmtMap->getParent(S);
414  }
415 
416  return false;
417  }
418 
419  bool isRemovable(Expr *E) const {
420  return Removables.count(E);
421  }
422 
423  bool tryRemoving(Expr *E) const {
424  if (isRemovable(E)) {
425  Pass.TA.removeStmt(E);
426  return true;
427  }
428 
429  Stmt *parent = StmtMap->getParent(E);
430 
431  if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
432  return tryRemoving(castE);
433 
434  if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
435  return tryRemoving(parenE);
436 
437  if (BinaryOperator *
438  bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
439  if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
440  isRemovable(bopE)) {
441  Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
442  return true;
443  }
444  }
445 
446  return false;
447  }
448 
449 };
450 
451 } // anonymous namespace
452 
456 }
child_iterator child_begin()
Definition: Stmt.h:452
The receiver is the instance of the superclass object.
Definition: ExprObjC.h:1060
Defines the clang::ASTContext interface.
The receiver is an object instance.
Definition: ExprObjC.h:1054
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:86
ParenExpr - This represents a parethesized expression, e.g.
Definition: Expr.h:1665
llvm::iterator_range< child_iterator > child_range
Definition: Stmt.h:443
Stmt * IgnoreImplicit()
Skip past any implicit AST nodes which might surround this statement, such as ExprWithCleanups or Imp...
Definition: Stmt.cpp:112
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:806
Expr * IgnoreImplicit() LLVM_READONLY
IgnoreImplicit - Skip past any implicit AST nodes which might surround this expression.
Definition: Expr.h:734
void setBegin(SourceLocation b)
Represents an expression – generally a full-expression – that introduces cleanups to be run at the ...
Definition: ExprCXX.h:3000
child_range children()
Definition: Expr.h:3521
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument&#39;s dynamic ty...
bool isGlobalVar(Expr *E)
Definition: Transforms.cpp:197
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
IdentifierTable & Idents
Definition: ASTContext.h:537
Selector getNullarySelector(IdentifierInfo *ID)
void removeRetainReleaseDeallocFinalize(MigrationPass &pass)
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:2985
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2465
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:173
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. ...
Expr - 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:1413
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:903
SourceLocation getEnd() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
Definition: ExprObjC.h:1187
const SourceManager & SM
Definition: Format.cpp:1337
std::string getAsString() const
Derive the full selector name (e.g.
SelectorTable & Selectors
Definition: ASTContext.h:538
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Definition: Expr.h:4969
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:1321
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Definition: Stmt.h:487
SourceLocation getSelectorLoc(unsigned Index) const
Definition: ExprObjC.h:1371
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:2822
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition: Expr.h:3488
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
Definition: Lexer.cpp:971
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:216
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1206
Dataflow Directional Tag Classes.
bool hasSideEffects(Expr *E, ASTContext &Ctx)
Definition: Transforms.cpp:168
SourceLocation getLocStart() const LLVM_READONLY
Definition: ExprObjC.h:1398
const Expr * getInit() const
Definition: Decl.h:1212
bool isPlusOne(const Expr *E)
Definition: Transforms.cpp:74
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
Definition: Expr.cpp:2552
bool isMacroID() const
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:643
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:989
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2387
void replace(SourceRange range, StringRef text)
TransformActions & TA
Definition: Internals.h:151
void setEnd(SourceLocation e)
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:956
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:1194
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
Definition: ASTContext.h:688
This class handles loading and caching of source files into memory.
child_iterator child_end()
Definition: Stmt.h:453