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) {
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) {
69 if (!isCommonUnusedAutorelease(E)) {
74 Pass.TA.reportError(
"it is not safe to remove an unused 'autorelease' "
75 "message; its receiver may be destroyed immediately",
85 rec = rec->IgnoreParenImpCasts();
88 std::string err =
"it is not safe to remove '";
90 "an __unsafe_unretained type";
91 Pass.TA.reportError(err, rec->getLocStart());
97 std::string err =
"it is not safe to remove '";
100 Pass.TA.reportError(err, rec->getLocStart());
105 Pass.TA.reportError(
"it is not safe to remove 'retain' "
106 "message on the result of a 'delegate' message; "
107 "the object that was passed to 'setDelegate:' may not be "
108 "properly retained", rec->getLocStart());
124 Pass.TA.replace(E->getSourceRange(),
"self");
132 if (!rec)
return true;
138 Expr *RecContainer = Msg;
140 checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
143 isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
146 Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
147 std::string str =
" = ";
149 Pass.TA.insertAfterToken(RecRange.
getEnd(), str);
154 if (tryRemoving(RecContainer))
157 Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
177 if (isPlusOneAssignBeforeOrAfterAutorelease(E))
179 if (isReturnedAfterAutorelease(E))
189 Decl *RefD = getReferencedDecl(Rec);
193 Stmt *nextStmt = getNextStmt(E);
199 if (
ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
200 return RefD == getReferencedDecl(RetS->getRetValue());
210 Decl *RefD = getReferencedDecl(Rec);
214 Stmt *prevStmt, *nextStmt;
215 std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
217 return isPlusOneAssignToVar(prevStmt, RefD) ||
218 isPlusOneAssignToVar(nextStmt, RefD);
221 bool isPlusOneAssignToVar(
Stmt *
S,
Decl *RefD) {
228 if (RefD != getReferencedDecl(Bop->getLHS()))
235 if (
DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
236 if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
237 if (
VarDecl *VD = dyn_cast<VarDecl>(RefD))
247 return getPreviousAndNextStmt(E).second;
250 std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(
Expr *E) {
251 Stmt *prevStmt =
nullptr, *nextStmt =
nullptr;
253 return std::make_pair(prevStmt, nextStmt);
255 Stmt *OuterS = E, *InnerS;
258 OuterS = StmtMap->getParent(InnerS);
260 while (OuterS && (isa<ParenExpr>(OuterS) ||
261 isa<CastExpr>(OuterS) ||
262 isa<ExprWithCleanups>(OuterS)));
265 return std::make_pair(prevStmt, nextStmt);
267 Stmt::child_iterator currChildS = OuterS->child_begin();
268 Stmt::child_iterator childE = OuterS->child_end();
269 Stmt::child_iterator prevChildS = childE;
270 for (; currChildS != childE; ++currChildS) {
271 if (*currChildS == InnerS)
273 prevChildS = currChildS;
276 if (prevChildS != childE) {
277 prevStmt = *prevChildS;
279 prevStmt = prevStmt->IgnoreImplicit();
282 if (currChildS == childE)
283 return std::make_pair(prevStmt, nextStmt);
285 if (currChildS == childE)
286 return std::make_pair(prevStmt, nextStmt);
288 nextStmt = *currChildS;
290 nextStmt = nextStmt->IgnoreImplicit();
292 return std::make_pair(prevStmt, nextStmt);
301 switch (ME->getMethodFamily()) {
306 return getReferencedDecl(ME->getInstanceReceiver());
312 return DRE->getDecl();
314 return ME->getMemberDecl();
316 return IRE->getDecl();
338 Pass.Ctx.getLangOpts());
339 bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
340 .Case(
"dispatch_retain",
true)
341 .Case(
"dispatch_release",
true)
342 .Case(
"xpc_retain",
true)
343 .Case(
"xpc_release",
true)
351 if (
StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
355 S = StmtMap->getParent(S);
361 Stmt::child_range StmtExprChild = StmtE->
children();
364 CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
368 Stmt::child_range CompStmtChild = CompS->
children();
371 DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
383 RecContainer = StmtE;
387 RecRange = Rec->getSourceRange();
395 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
396 diag::err_unavailable,
397 diag::err_unavailable_message,
401 bool isDelegateMessage(
Expr *E)
const {
402 if (!E)
return false;
411 return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
416 bool isInAtFinally(
Expr *E)
const {
420 if (isa<ObjCAtFinallyStmt>(S))
422 S = StmtMap->getParent(S);
428 bool isRemovable(
Expr *E)
const {
429 return Removables.count(E);
432 bool tryRemoving(
Expr *E)
const {
433 if (isRemovable(E)) {
434 Pass.TA.removeStmt(E);
438 Stmt *parent = StmtMap->getParent(E);
441 return tryRemoving(castE);
443 if (
ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
444 return tryRemoving(parenE);
447 bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
448 if (bopE->getOpcode() ==
BO_Comma && bopE->getLHS() == E &&
450 Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
The receiver is the instance of the superclass object.
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
The receiver is an object instance.
Smart pointer class that efficiently represents Objective-C method names.
ObjCMethodFamily getMethodFamily() const
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
Defines the SourceManager interface.
const Expr * getInit() const
Expr * IgnoreImplicit() LLVM_READONLY
void setBegin(SourceLocation b)
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool isGlobalVar(Expr *E)
void removeRetainReleaseDeallocFinalize(MigrationPass &pass)
A builtin binary operation expression such as "x + y" or "x <= y".
Selector getSelector() const
Expr * IgnoreParenCasts() LLVM_READONLY
A class that does preorder depth-first traversal on the entire Clang AST and visits each node...
bool isPlusOneAssign(const BinaryOperator *E)
StringRef getNilString(MigrationPass &Pass)
Returns "nil" or "0" if 'nil' macro is not actually defined.
bool isInstanceMessage() const
Determine whether this is an instance message to either a computed object or to super.
void collectRemovables(Stmt *S, ExprSet &exprs)
TranslationUnitDecl * getTranslationUnitDecl() const
An expression that sends a message to the given Objective-C object or class.
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isSingleDecl() const
std::string getAsString() const
Derive the full selector name (e.g. "foo:bar:") and return it as an std::string.
SourceLocation getBegin() const
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
const Decl * getSingleDecl() const
SourceLocation getExprLoc() const LLVM_READONLY
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
bool hasSideEffects(Expr *E, ASTContext &Ctx)
SourceLocation getSelectorLoc(unsigned Index) const
SourceLocation getLocStart() const LLVM_READONLY
bool isPlusOne(const Expr *E)
Expr * IgnoreParenImpCasts() LLVM_READONLY
ObjCIvarRefExpr - A reference to an ObjC instance variable.
void setEnd(SourceLocation e)
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
A trivial tuple used to represent a source range.
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
This class handles loading and caching of source files into memory.
bool isMacroArgExpansion(SourceLocation Loc) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...