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