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