27 #include "llvm/ADT/StringSwitch.h" 29 using namespace clang;
30 using namespace arcmt;
31 using namespace trans;
35 class RetainReleaseDeallocRemover :
41 std::unique_ptr<ParentMap> StmtMap;
47 : Body(nullptr), Pass(pass) {
54 void transformBody(
Stmt *body,
Decl *ParentD) {
69 if (!isCommonUnusedAutorelease(E)) {
75 "it is not safe to remove an unused 'autorelease' " 76 "message; its receiver may be destroyed immediately",
87 rec = rec->IgnoreParenImpCasts();
90 std::string err =
"it is not safe to remove '";
92 "an __unsafe_unretained type";
99 std::string err =
"it is not safe to remove '";
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 " 137 if (!rec)
return true;
143 Expr *RecContainer = Msg;
145 checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
148 isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
152 std::string
str =
" = ";
179 return isPlusOneAssignBeforeOrAfterAutorelease(E) ||
180 isReturnedAfterAutorelease(E);
188 Decl *RefD = getReferencedDecl(Rec);
192 Stmt *nextStmt = getNextStmt(E);
198 if (
ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
199 return RefD == getReferencedDecl(RetS->getRetValue());
209 Decl *RefD = getReferencedDecl(Rec);
213 Stmt *prevStmt, *nextStmt;
214 std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
216 return isPlusOneAssignToVar(prevStmt, RefD) ||
217 isPlusOneAssignToVar(nextStmt, RefD);
220 bool isPlusOneAssignToVar(
Stmt *S,
Decl *RefD) {
227 return (RefD == getReferencedDecl(Bop->getLHS())) &&
isPlusOneAssign(Bop);
230 if (
DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
231 if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
232 if (
VarDecl *VD = dyn_cast<VarDecl>(RefD))
242 return getPreviousAndNextStmt(E).second;
245 std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(
Expr *E) {
246 Stmt *prevStmt =
nullptr, *nextStmt =
nullptr;
248 return std::make_pair(prevStmt, nextStmt);
250 Stmt *OuterS = E, *InnerS;
253 OuterS = StmtMap->getParent(InnerS);
255 while (OuterS && (isa<ParenExpr>(OuterS) ||
256 isa<CastExpr>(OuterS) ||
257 isa<FullExpr>(OuterS)));
260 return std::make_pair(prevStmt, nextStmt);
265 for (; currChildS != childE; ++currChildS) {
266 if (*currChildS == InnerS)
268 prevChildS = currChildS;
271 if (prevChildS != childE) {
272 prevStmt = *prevChildS;
277 if (currChildS == childE)
278 return std::make_pair(prevStmt, nextStmt);
280 if (currChildS == childE)
281 return std::make_pair(prevStmt, nextStmt);
283 nextStmt = *currChildS;
287 return std::make_pair(prevStmt, nextStmt);
296 switch (ME->getMethodFamily()) {
301 return getReferencedDecl(ME->getInstanceReceiver());
307 return DRE->getDecl();
309 return ME->getMemberDecl();
311 return IRE->getDecl();
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)
346 if (
StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
350 S = StmtMap->getParent(S);
357 if (StmtExprChild.begin() == StmtExprChild.end())
359 auto *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild.begin());
364 if (CompStmtChild.begin() == CompStmtChild.end())
366 auto *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild.begin());
369 if (!DeclS->isSingleDecl())
371 VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
378 RecContainer = StmtE;
380 if (
FullExpr *FE = dyn_cast<FullExpr>(Rec))
391 diag::err_unavailable,
392 diag::err_unavailable_message,
396 bool isDelegateMessage(
Expr *E)
const {
397 if (!E)
return false;
406 return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
411 bool isInAtFinally(
Expr *E)
const {
415 if (isa<ObjCAtFinallyStmt>(S))
417 S = StmtMap->getParent(S);
423 bool isRemovable(
Expr *E)
const {
424 return Removables.count(E);
427 bool tryRemoving(
Expr *E)
const {
428 if (isRemovable(E)) {
433 Stmt *parent = StmtMap->getParent(E);
436 return tryRemoving(castE);
438 if (
ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
439 return tryRemoving(parenE);
442 bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
443 if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
445 Pass.
TA.
replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
child_iterator child_begin()
The receiver is the instance of the superclass object.
Defines the clang::ASTContext interface.
The receiver is an object instance.
Smart pointer class that efficiently represents Objective-C method names.
Selector getSelector() const
Stmt - This represents one statement.
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
ParenExpr - This represents a parethesized expression, e.g.
llvm::iterator_range< child_iterator > child_range
Stmt * IgnoreImplicit()
Skip past any implicit AST nodes which might surround this statement, such as ExprWithCleanups or Imp...
Represents a variable declaration or definition.
Expr * IgnoreImplicit() LLVM_READONLY
IgnoreImplicit - Skip past any implicit AST nodes which might surround this expression.
void setBegin(SourceLocation b)
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
FullExpr - Represents a "full-expression" node.
bool isGlobalVar(Expr *E)
Selector getNullarySelector(IdentifierInfo *ID)
void removeRetainReleaseDeallocFinalize(MigrationPass &pass)
A builtin binary operation expression such as "x + y" or "x <= y".
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool isPlusOneAssign(const BinaryOperator *E)
This object can be modified without requiring retains or releases.
StringRef getNilString(MigrationPass &Pass)
Returns "nil" or "0" if 'nil' macro is not actually defined.
void collectRemovables(Stmt *S, ExprSet &exprs)
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
This represents one expression.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
An expression that sends a message to the given Objective-C object or class.
SourceLocation getEnd() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
std::string getAsString() const
Derive the full selector name (e.g.
SelectorTable & Selectors
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Encodes a location in the source.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
ObjCMethodFamily getMethodFamily() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
SourceLocation getSelectorLoc(unsigned Index) const
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Dataflow Directional Tag Classes.
bool hasSideEffects(Expr *E, ASTContext &Ctx)
const Expr * getInit() const
bool isPlusOne(const Expr *E)
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
ObjCIvarRefExpr - A reference to an ObjC instance variable.
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
void setEnd(SourceLocation e)
SourceLocation getBeginLoc() const LLVM_READONLY
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
A reference to a declared variable, function, enum, etc.
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.
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
child_iterator child_end()