clang API Documentation
00001 //===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // removeRetainReleaseDealloc: 00011 // 00012 // Removes retain/release/autorelease/dealloc messages. 00013 // 00014 // return [[foo retain] autorelease]; 00015 // ----> 00016 // return foo; 00017 // 00018 //===----------------------------------------------------------------------===// 00019 00020 #include "Transforms.h" 00021 #include "Internals.h" 00022 #include "clang/Sema/SemaDiagnostic.h" 00023 #include "clang/AST/ParentMap.h" 00024 #include "clang/Lex/Lexer.h" 00025 #include "clang/Basic/SourceManager.h" 00026 00027 using namespace clang; 00028 using namespace arcmt; 00029 using namespace trans; 00030 00031 namespace { 00032 00033 class RetainReleaseDeallocRemover : 00034 public RecursiveASTVisitor<RetainReleaseDeallocRemover> { 00035 Stmt *Body; 00036 MigrationPass &Pass; 00037 00038 ExprSet Removables; 00039 OwningPtr<ParentMap> StmtMap; 00040 00041 Selector DelegateSel, FinalizeSel; 00042 00043 public: 00044 RetainReleaseDeallocRemover(MigrationPass &pass) 00045 : Body(0), Pass(pass) { 00046 DelegateSel = 00047 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate")); 00048 FinalizeSel = 00049 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); 00050 } 00051 00052 void transformBody(Stmt *body) { 00053 Body = body; 00054 collectRemovables(body, Removables); 00055 StmtMap.reset(new ParentMap(body)); 00056 TraverseStmt(body); 00057 } 00058 00059 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 00060 switch (E->getMethodFamily()) { 00061 default: 00062 if (E->isInstanceMessage() && E->getSelector() == FinalizeSel) 00063 break; 00064 return true; 00065 case OMF_autorelease: 00066 if (isRemovable(E)) { 00067 // An unused autorelease is badness. If we remove it the receiver 00068 // will likely die immediately while previously it was kept alive 00069 // by the autorelease pool. This is bad practice in general, leave it 00070 // and emit an error to force the user to restructure his code. 00071 Pass.TA.reportError("it is not safe to remove an unused 'autorelease' " 00072 "message; its receiver may be destroyed immediately", 00073 E->getLocStart(), E->getSourceRange()); 00074 return true; 00075 } 00076 // Pass through. 00077 case OMF_retain: 00078 case OMF_release: 00079 if (E->getReceiverKind() == ObjCMessageExpr::Instance) 00080 if (Expr *rec = E->getInstanceReceiver()) { 00081 rec = rec->IgnoreParenImpCasts(); 00082 if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone && 00083 (E->getMethodFamily() != OMF_retain || isRemovable(E))) { 00084 std::string err = "it is not safe to remove '"; 00085 err += E->getSelector().getAsString() + "' message on " 00086 "an __unsafe_unretained type"; 00087 Pass.TA.reportError(err, rec->getLocStart()); 00088 return true; 00089 } 00090 00091 if (isGlobalVar(rec) && 00092 (E->getMethodFamily() != OMF_retain || isRemovable(E))) { 00093 std::string err = "it is not safe to remove '"; 00094 err += E->getSelector().getAsString() + "' message on " 00095 "a global variable"; 00096 Pass.TA.reportError(err, rec->getLocStart()); 00097 return true; 00098 } 00099 00100 if (E->getMethodFamily() == OMF_release && isDelegateMessage(rec)) { 00101 Pass.TA.reportError("it is not safe to remove 'retain' " 00102 "message on the result of a 'delegate' message; " 00103 "the object that was passed to 'setDelegate:' may not be " 00104 "properly retained", rec->getLocStart()); 00105 return true; 00106 } 00107 } 00108 case OMF_dealloc: 00109 break; 00110 } 00111 00112 switch (E->getReceiverKind()) { 00113 default: 00114 return true; 00115 case ObjCMessageExpr::SuperInstance: { 00116 Transaction Trans(Pass.TA); 00117 clearDiagnostics(E->getSuperLoc()); 00118 if (tryRemoving(E)) 00119 return true; 00120 Pass.TA.replace(E->getSourceRange(), "self"); 00121 return true; 00122 } 00123 case ObjCMessageExpr::Instance: 00124 break; 00125 } 00126 00127 Expr *rec = E->getInstanceReceiver(); 00128 if (!rec) return true; 00129 00130 Transaction Trans(Pass.TA); 00131 clearDiagnostics(rec->getExprLoc()); 00132 00133 ObjCMessageExpr *Msg = E; 00134 Expr *RecContainer = Msg; 00135 SourceRange RecRange = rec->getSourceRange(); 00136 checkForGCDOrXPC(Msg, RecContainer, rec, RecRange); 00137 00138 if (Msg->getMethodFamily() == OMF_release && 00139 isRemovable(RecContainer) && isInAtFinally(RecContainer)) { 00140 // Change the -release to "receiver = nil" in a finally to avoid a leak 00141 // when an exception is thrown. 00142 Pass.TA.replace(RecContainer->getSourceRange(), RecRange); 00143 std::string str = " = "; 00144 str += getNilString(Pass.Ctx); 00145 Pass.TA.insertAfterToken(RecRange.getEnd(), str); 00146 return true; 00147 } 00148 00149 if (!hasSideEffects(rec, Pass.Ctx)) { 00150 if (tryRemoving(RecContainer)) 00151 return true; 00152 } 00153 Pass.TA.replace(RecContainer->getSourceRange(), RecRange); 00154 00155 return true; 00156 } 00157 00158 private: 00159 /// \brief Check if the retain/release is due to a GCD/XPC macro that are 00160 /// defined as: 00161 /// 00162 /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; }) 00163 /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; }) 00164 /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; }) 00165 /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; }) 00166 /// 00167 /// and return the top container which is the StmtExpr and the macro argument 00168 /// expression. 00169 void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer, 00170 Expr *&Rec, SourceRange &RecRange) { 00171 SourceLocation Loc = Msg->getExprLoc(); 00172 if (!Loc.isMacroID()) 00173 return; 00174 SourceManager &SM = Pass.Ctx.getSourceManager(); 00175 StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, 00176 Pass.Ctx.getLangOpts()); 00177 bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName) 00178 .Case("dispatch_retain", true) 00179 .Case("dispatch_release", true) 00180 .Case("xpc_retain", true) 00181 .Case("xpc_release", true) 00182 .Default(false); 00183 if (!isGCDOrXPC) 00184 return; 00185 00186 StmtExpr *StmtE = 0; 00187 Stmt *S = Msg; 00188 while (S) { 00189 if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) { 00190 StmtE = SE; 00191 break; 00192 } 00193 S = StmtMap->getParent(S); 00194 } 00195 00196 if (!StmtE) 00197 return; 00198 00199 Stmt::child_range StmtExprChild = StmtE->children(); 00200 if (!StmtExprChild) 00201 return; 00202 CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild); 00203 if (!CompS) 00204 return; 00205 00206 Stmt::child_range CompStmtChild = CompS->children(); 00207 if (!CompStmtChild) 00208 return; 00209 DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild); 00210 if (!DeclS) 00211 return; 00212 if (!DeclS->isSingleDecl()) 00213 return; 00214 VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()); 00215 if (!VD) 00216 return; 00217 Expr *Init = VD->getInit(); 00218 if (!Init) 00219 return; 00220 00221 RecContainer = StmtE; 00222 Rec = Init->IgnoreParenImpCasts(); 00223 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec)) 00224 Rec = EWC->getSubExpr()->IgnoreParenImpCasts(); 00225 RecRange = Rec->getSourceRange(); 00226 if (SM.isMacroArgExpansion(RecRange.getBegin())) 00227 RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin())); 00228 if (SM.isMacroArgExpansion(RecRange.getEnd())) 00229 RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd())); 00230 } 00231 00232 void clearDiagnostics(SourceLocation loc) const { 00233 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, 00234 diag::err_unavailable, 00235 diag::err_unavailable_message, 00236 loc); 00237 } 00238 00239 bool isDelegateMessage(Expr *E) const { 00240 if (!E) return false; 00241 00242 E = E->IgnoreParenCasts(); 00243 00244 // Also look through property-getter sugar. 00245 if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E)) 00246 E = pseudoOp->getResultExpr()->IgnoreImplicit(); 00247 00248 if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) 00249 return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel); 00250 00251 return false; 00252 } 00253 00254 bool isInAtFinally(Expr *E) const { 00255 assert(E); 00256 Stmt *S = E; 00257 while (S) { 00258 if (isa<ObjCAtFinallyStmt>(S)) 00259 return true; 00260 S = StmtMap->getParent(S); 00261 } 00262 00263 return false; 00264 } 00265 00266 bool isRemovable(Expr *E) const { 00267 return Removables.count(E); 00268 } 00269 00270 bool tryRemoving(Expr *E) const { 00271 if (isRemovable(E)) { 00272 Pass.TA.removeStmt(E); 00273 return true; 00274 } 00275 00276 Stmt *parent = StmtMap->getParent(E); 00277 00278 if (ImplicitCastExpr *castE = dyn_cast_or_null<ImplicitCastExpr>(parent)) 00279 return tryRemoving(castE); 00280 00281 if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(parent)) 00282 return tryRemoving(parenE); 00283 00284 if (BinaryOperator * 00285 bopE = dyn_cast_or_null<BinaryOperator>(parent)) { 00286 if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E && 00287 isRemovable(bopE)) { 00288 Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange()); 00289 return true; 00290 } 00291 } 00292 00293 return false; 00294 } 00295 00296 }; 00297 00298 } // anonymous namespace 00299 00300 void trans::removeRetainReleaseDeallocFinalize(MigrationPass &pass) { 00301 BodyTransform<RetainReleaseDeallocRemover> trans(pass); 00302 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00303 }