TransRetainReleaseDealloc.cpp revision b1094a0621c3bf91141f7cd9684ca80b357ae61e
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_retain:
56    case OMF_release:
57    case OMF_autorelease:
58      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
59        if (Expr *rec = E->getInstanceReceiver()) {
60          rec = rec->IgnoreParenImpCasts();
61          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
62            std::string err = "It is not safe to remove '";
63            err += E->getSelector().getAsString() + "' message on "
64                "an __unsafe_unretained type";
65            Pass.TA.reportError(err, rec->getLocStart());
66            return true;
67          }
68        }
69    case OMF_dealloc:
70      break;
71    }
72
73    switch (E->getReceiverKind()) {
74    default:
75      return true;
76    case ObjCMessageExpr::SuperInstance: {
77      Transaction Trans(Pass.TA);
78      Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
79                              diag::err_unavailable,
80                              diag::err_unavailable_message,
81                              E->getSuperLoc());
82      if (tryRemoving(E))
83        return true;
84      Pass.TA.replace(E->getSourceRange(), "self");
85      return true;
86    }
87    case ObjCMessageExpr::Instance:
88      break;
89    }
90
91    Expr *rec = E->getInstanceReceiver();
92    if (!rec) return true;
93
94    Transaction Trans(Pass.TA);
95    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
96                            diag::err_unavailable,
97                            diag::err_unavailable_message,
98                            rec->getExprLoc());
99    if (!hasSideEffects(E, Pass.Ctx)) {
100      if (tryRemoving(E))
101        return true;
102    }
103    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
104
105    return true;
106  }
107
108private:
109  bool isRemovable(Expr *E) const {
110    return Removables.count(E);
111  }
112
113  bool tryRemoving(Expr *E) const {
114    if (isRemovable(E)) {
115      Pass.TA.removeStmt(E);
116      return true;
117    }
118
119    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E)))
120      return tryRemoving(parenE);
121
122    if (BinaryOperator *
123          bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) {
124      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
125          isRemovable(bopE)) {
126        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
127        return true;
128      }
129    }
130
131    return false;
132  }
133
134};
135
136} // anonymous namespace
137
138void trans::removeRetainReleaseDealloc(MigrationPass &pass) {
139  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
140  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
141}
142