TransRetainReleaseDealloc.cpp revision e0e40768cc8c4b2a9093dac3d777e0d362cb7a88
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
25using namespace clang;
26using namespace arcmt;
27using namespace trans;
28using llvm::StringRef;
29
30namespace {
31
32class RetainReleaseDeallocRemover :
33                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
34  Stmt *Body;
35  MigrationPass &Pass;
36
37  ExprSet Removables;
38  llvm::OwningPtr<ParentMap> StmtMap;
39
40public:
41  RetainReleaseDeallocRemover(MigrationPass &pass)
42    : Body(0), Pass(pass) { }
43
44  void transformBody(Stmt *body) {
45    Body = body;
46    collectRemovables(body, Removables);
47    StmtMap.reset(new ParentMap(body));
48    TraverseStmt(body);
49  }
50
51  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
52    switch (E->getMethodFamily()) {
53    default:
54      return true;
55    case OMF_autorelease:
56      if (isRemovable(E)) {
57        // An unused autorelease is badness. If we remove it the receiver
58        // will likely die immediately while previously it was kept alive
59        // by the autorelease pool. This is bad practice in general, leave it
60        // and emit an error to force the user to restructure his code.
61        std::string err = "it is not safe to remove an unused '";
62        err += E->getSelector().getAsString() + "'; its receiver may be "
63            "destroyed immediately";
64        Pass.TA.reportError(err, E->getLocStart(), E->getSourceRange());
65        return true;
66      }
67      // Pass through.
68    case OMF_retain:
69    case OMF_release:
70      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
71        if (Expr *rec = E->getInstanceReceiver()) {
72          rec = rec->IgnoreParenImpCasts();
73          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
74            std::string err = "it is not safe to remove '";
75            err += E->getSelector().getAsString() + "' message on "
76                "an __unsafe_unretained type";
77            Pass.TA.reportError(err, rec->getLocStart());
78            return true;
79          }
80        }
81    case OMF_dealloc:
82      break;
83    }
84
85    switch (E->getReceiverKind()) {
86    default:
87      return true;
88    case ObjCMessageExpr::SuperInstance: {
89      Transaction Trans(Pass.TA);
90      Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
91                              diag::err_unavailable,
92                              diag::err_unavailable_message,
93                              E->getSuperLoc());
94      if (tryRemoving(E))
95        return true;
96      Pass.TA.replace(E->getSourceRange(), "self");
97      return true;
98    }
99    case ObjCMessageExpr::Instance:
100      break;
101    }
102
103    Expr *rec = E->getInstanceReceiver();
104    if (!rec) return true;
105
106    Transaction Trans(Pass.TA);
107    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
108                            diag::err_unavailable,
109                            diag::err_unavailable_message,
110                            rec->getExprLoc());
111    if (!hasSideEffects(E, Pass.Ctx)) {
112      if (tryRemoving(E))
113        return true;
114    }
115    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
116
117    return true;
118  }
119
120private:
121  bool isRemovable(Expr *E) const {
122    return Removables.count(E);
123  }
124
125  bool tryRemoving(Expr *E) const {
126    if (isRemovable(E)) {
127      Pass.TA.removeStmt(E);
128      return true;
129    }
130
131    Stmt *parent = StmtMap->getParent(E);
132
133    if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
134      return tryRemoving(castE);
135
136    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
137      return tryRemoving(parenE);
138
139    if (BinaryOperator *
140          bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
141      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
142          isRemovable(bopE)) {
143        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
144        return true;
145      }
146    }
147
148    return false;
149  }
150
151};
152
153} // anonymous namespace
154
155void trans::removeRetainReleaseDealloc(MigrationPass &pass) {
156  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
157  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
158}
159