diff options
Diffstat (limited to 'clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp')
-rw-r--r-- | clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp new file mode 100644 index 0000000..d1f08aa --- /dev/null +++ b/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp @@ -0,0 +1,228 @@ +//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// removeZeroOutPropsInDealloc: +// +// Removes zero'ing out "strong" @synthesized properties in a -dealloc method. +// +//===----------------------------------------------------------------------===// + +#include "Transforms.h" +#include "Internals.h" + +using namespace clang; +using namespace arcmt; +using namespace trans; + +namespace { + +class ZeroOutInDeallocRemover : + public RecursiveASTVisitor<ZeroOutInDeallocRemover> { + typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base; + + MigrationPass &Pass; + + llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties; + ImplicitParamDecl *SelfD; + ExprSet Removables; + Selector FinalizeSel; + +public: + ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { + FinalizeSel = + Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { + ASTContext &Ctx = Pass.Ctx; + TransformActions &TA = Pass.TA; + + if (ME->getReceiverKind() != ObjCMessageExpr::Instance) + return true; + Expr *receiver = ME->getInstanceReceiver(); + if (!receiver) + return true; + + DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts()); + if (!refE || refE->getDecl() != SelfD) + return true; + + bool BackedBySynthesizeSetter = false; + for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator + P = SynthesizedProperties.begin(), + E = SynthesizedProperties.end(); P != E; ++P) { + ObjCPropertyDecl *PropDecl = P->first; + if (PropDecl->getSetterName() == ME->getSelector()) { + BackedBySynthesizeSetter = true; + break; + } + } + if (!BackedBySynthesizeSetter) + return true; + + // Remove the setter message if RHS is null + Transaction Trans(TA); + Expr *RHS = ME->getArg(0); + bool RHSIsNull = + RHS->isNullPointerConstant(Ctx, + Expr::NPC_ValueDependentIsNull); + if (RHSIsNull && isRemovable(ME)) + TA.removeStmt(ME); + + return true; + } + + bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + if (isZeroingPropIvar(POE) && isRemovable(POE)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(POE); + } + + return true; + } + + bool VisitBinaryOperator(BinaryOperator *BOE) { + if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { + Transaction Trans(Pass.TA); + Pass.TA.removeStmt(BOE); + } + + return true; + } + + bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { + if (D->getMethodFamily() != OMF_dealloc && + !(D->isInstanceMethod() && D->getSelector() == FinalizeSel)) + return true; + if (!D->hasBody()) + return true; + + ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext()); + if (!IMD) + return true; + + SelfD = D->getSelfDecl(); + collectRemovables(D->getBody(), Removables); + + // For a 'dealloc' method use, find all property implementations in + // this class implementation. + for (ObjCImplDecl::propimpl_iterator + I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { + ObjCPropertyImplDecl *PID = *I; + if (PID->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize) { + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); + if (!(setterM && setterM->isDefined())) { + ObjCPropertyDecl::PropertyAttributeKind AttrKind = + PD->getPropertyAttributes(); + if (AttrKind & + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_strong)) + SynthesizedProperties[PD] = PID; + } + } + } + + // Now, remove all zeroing of ivars etc. + base::TraverseObjCMethodDecl(D); + + // clear out for next method. + SynthesizedProperties.clear(); + SelfD = 0; + Removables.clear(); + return true; + } + + bool TraverseFunctionDecl(FunctionDecl *D) { return true; } + bool TraverseBlockDecl(BlockDecl *block) { return true; } + bool TraverseBlockExpr(BlockExpr *block) { return true; } + +private: + bool isRemovable(Expr *E) const { + return Removables.count(E); + } + + bool isZeroingPropIvar(Expr *E) { + E = E->IgnoreParens(); + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) + return isZeroingPropIvar(BO); + if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) + return isZeroingPropIvar(PO); + return false; + } + + bool isZeroingPropIvar(BinaryOperator *BOE) { + if (BOE->getOpcode() == BO_Comma) + return isZeroingPropIvar(BOE->getLHS()) && + isZeroingPropIvar(BOE->getRHS()); + + if (BOE->getOpcode() != BO_Assign) + return false; + + Expr *LHS = BOE->getLHS(); + if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { + ObjCIvarDecl *IVDecl = IV->getDecl(); + if (!IVDecl->getType()->isObjCObjectPointerType()) + return false; + bool IvarBacksPropertySynthesis = false; + for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator + P = SynthesizedProperties.begin(), + E = SynthesizedProperties.end(); P != E; ++P) { + ObjCPropertyImplDecl *PropImpDecl = P->second; + if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { + IvarBacksPropertySynthesis = true; + break; + } + } + if (!IvarBacksPropertySynthesis) + return false; + } + else + return false; + + return isZero(BOE->getRHS()); + } + + bool isZeroingPropIvar(PseudoObjectExpr *PO) { + BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm()); + if (!BO) return false; + if (BO->getOpcode() != BO_Assign) return false; + + ObjCPropertyRefExpr *PropRefExp = + dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens()); + if (!PropRefExp) return false; + + // TODO: Using implicit property decl. + if (PropRefExp->isImplicitProperty()) + return false; + + if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { + if (!SynthesizedProperties.count(PDecl)) + return false; + } + + return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr()); + } + + bool isZero(Expr *E) { + if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull)) + return true; + + return isZeroingPropIvar(E); + } +}; + +} // anonymous namespace + +void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) { + ZeroOutInDeallocRemover trans(pass); + trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +} |