TransRetainReleaseDealloc.cpp revision 2c18ca0575b60082f2a9f4563b4071071960d37c
17196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===//
27196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
37196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//                     The LLVM Compiler Infrastructure
47196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
57196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source
67196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// License. See LICENSE.TXT for details.
77196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
87196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
97196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// removeRetainReleaseDealloc:
117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
127196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// Removes retain/release/autorelease/dealloc messages.
137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//  return [[foo retain] autorelease];
157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// ---->
167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//  return foo;
177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//
187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "Transforms.h"
217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "Internals.h"
227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "clang/Sema/SemaDiagnostic.h"
237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "clang/AST/ParentMap.h"
247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace clang;
267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace arcmt;
277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing namespace trans;
287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisusing llvm::StringRef;
297196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
307196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisnamespace {
317196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisclass RetainReleaseDeallocRemover :
337196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
347196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  Stmt *Body;
357196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  MigrationPass &Pass;
367196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
377196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  ExprSet Removables;
387196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  llvm::OwningPtr<ParentMap> StmtMap;
397196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
407196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidispublic:
41b1094a0621c3bf91141f7cd9684ca80b357ae61eArgyrios Kyrtzidis  RetainReleaseDeallocRemover(MigrationPass &pass)
42b1094a0621c3bf91141f7cd9684ca80b357ae61eArgyrios Kyrtzidis    : Body(0), Pass(pass) { }
437196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
447196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  void transformBody(Stmt *body) {
457196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    Body = body;
467196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    collectRemovables(body, Removables);
477196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    StmtMap.reset(new ParentMap(body));
487196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    TraverseStmt(body);
497196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
507196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
517196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
527196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    switch (E->getMethodFamily()) {
537196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    default:
547196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return true;
55e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis    case OMF_autorelease:
56e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis      if (isRemovable(E)) {
57e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        // An unused autorelease is badness. If we remove it the receiver
58e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        // will likely die immediately while previously it was kept alive
59e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        // by the autorelease pool. This is bad practice in general, leave it
60e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        // and emit an error to force the user to restructure his code.
61e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        std::string err = "it is not safe to remove an unused '";
62e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        err += E->getSelector().getAsString() + "'; its receiver may be "
63e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis            "destroyed immediately";
64e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        Pass.TA.reportError(err, E->getLocStart(), E->getSourceRange());
65e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis        return true;
66e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis      }
67e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis      // Pass through.
687196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case OMF_retain:
697196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case OMF_release:
707196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
717196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        if (Expr *rec = E->getInstanceReceiver()) {
727196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          rec = rec->IgnoreParenImpCasts();
732cd5366ff52b4592776ee4db27012d16fb995c62Argyrios Kyrtzidis          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
742cd5366ff52b4592776ee4db27012d16fb995c62Argyrios Kyrtzidis              (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
75e0e40768cc8c4b2a9093dac3d777e0d362cb7a88Argyrios Kyrtzidis            std::string err = "it is not safe to remove '";
767196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis            err += E->getSelector().getAsString() + "' message on "
777196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                "an __unsafe_unretained type";
787196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis            Pass.TA.reportError(err, rec->getLocStart());
797196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis            return true;
807196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          }
812c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis
822c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis          if (isGlobalVar(rec) &&
832c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis              (E->getMethodFamily() != OMF_retain || isRemovable(E))) {
842c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis            std::string err = "it is not safe to remove '";
852c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis            err += E->getSelector().getAsString() + "' message on "
862c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis                "a global variable";
872c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis            Pass.TA.reportError(err, rec->getLocStart());
882c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis            return true;
892c18ca0575b60082f2a9f4563b4071071960d37cArgyrios Kyrtzidis          }
907196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        }
917196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case OMF_dealloc:
927196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      break;
937196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
947196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
957196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    switch (E->getReceiverKind()) {
967196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    default:
977196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return true;
987196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case ObjCMessageExpr::SuperInstance: {
997196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      Transaction Trans(Pass.TA);
1007196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
1017196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                              diag::err_unavailable,
1027196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                              diag::err_unavailable_message,
1037196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                              E->getSuperLoc());
1047196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      if (tryRemoving(E))
1057196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        return true;
1067196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      Pass.TA.replace(E->getSourceRange(), "self");
1077196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return true;
1087196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1097196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case ObjCMessageExpr::Instance:
1107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      break;
1117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1127196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    Expr *rec = E->getInstanceReceiver();
1147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    if (!rec) return true;
1157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    Transaction Trans(Pass.TA);
1177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
1187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                            diag::err_unavailable,
1197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                            diag::err_unavailable_message,
1207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                            rec->getExprLoc());
1217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    if (!hasSideEffects(E, Pass.Ctx)) {
1227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      if (tryRemoving(E))
1237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        return true;
1247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
1267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return true;
1287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1297196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1307196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisprivate:
1317196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool isRemovable(Expr *E) const {
1327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return Removables.count(E);
1337196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1347196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1357196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  bool tryRemoving(Expr *E) const {
1367196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    if (isRemovable(E)) {
1377196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      Pass.TA.removeStmt(E);
1387196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return true;
1397196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1407196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1417e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall    Stmt *parent = StmtMap->getParent(E);
1427e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall
1437e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall    if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent))
1447e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall      return tryRemoving(castE);
1457e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall
1467e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent))
1477196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return tryRemoving(parenE);
1487196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1497196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    if (BinaryOperator *
1507e5e5f4cc36fe50f46ad76dca7a266434c94f475John McCall          bopE = dyn_cast_or_null<BinaryOperator>(parent)) {
1517196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
1527196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          isRemovable(bopE)) {
1537196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
1547196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis        return true;
1557196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      }
1567196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    }
1577196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1587196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    return false;
1597196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
1607196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1617196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis};
1627196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1637196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis} // anonymous namespace
1647196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1657196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisvoid trans::removeRetainReleaseDealloc(MigrationPass &pass) {
1667196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
1677196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1687196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
169