Path: blob/main/contrib/llvm-project/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
35236 views
//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// removeZeroOutPropsInDealloc:9//10// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.11//12//===----------------------------------------------------------------------===//1314#include "Transforms.h"15#include "Internals.h"16#include "clang/AST/ASTContext.h"1718using namespace clang;19using namespace arcmt;20using namespace trans;2122namespace {2324class ZeroOutInDeallocRemover :25public RecursiveASTVisitor<ZeroOutInDeallocRemover> {26typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;2728MigrationPass &Pass;2930llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;31ImplicitParamDecl *SelfD;32ExprSet Removables;33Selector FinalizeSel;3435public:36ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(nullptr) {37FinalizeSel =38Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));39}4041bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {42ASTContext &Ctx = Pass.Ctx;43TransformActions &TA = Pass.TA;4445if (ME->getReceiverKind() != ObjCMessageExpr::Instance)46return true;47Expr *receiver = ME->getInstanceReceiver();48if (!receiver)49return true;5051DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());52if (!refE || refE->getDecl() != SelfD)53return true;5455bool BackedBySynthesizeSetter = false;56for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator57P = SynthesizedProperties.begin(),58E = SynthesizedProperties.end(); P != E; ++P) {59ObjCPropertyDecl *PropDecl = P->first;60if (PropDecl->getSetterName() == ME->getSelector()) {61BackedBySynthesizeSetter = true;62break;63}64}65if (!BackedBySynthesizeSetter)66return true;6768// Remove the setter message if RHS is null69Transaction Trans(TA);70Expr *RHS = ME->getArg(0);71bool RHSIsNull =72RHS->isNullPointerConstant(Ctx,73Expr::NPC_ValueDependentIsNull);74if (RHSIsNull && isRemovable(ME))75TA.removeStmt(ME);7677return true;78}7980bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {81if (isZeroingPropIvar(POE) && isRemovable(POE)) {82Transaction Trans(Pass.TA);83Pass.TA.removeStmt(POE);84}8586return true;87}8889bool VisitBinaryOperator(BinaryOperator *BOE) {90if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {91Transaction Trans(Pass.TA);92Pass.TA.removeStmt(BOE);93}9495return true;96}9798bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {99if (D->getMethodFamily() != OMF_dealloc &&100!(D->isInstanceMethod() && D->getSelector() == FinalizeSel))101return true;102if (!D->hasBody())103return true;104105ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());106if (!IMD)107return true;108109SelfD = D->getSelfDecl();110collectRemovables(D->getBody(), Removables);111112// For a 'dealloc' method use, find all property implementations in113// this class implementation.114for (auto *PID : IMD->property_impls()) {115if (PID->getPropertyImplementation() ==116ObjCPropertyImplDecl::Synthesize) {117ObjCPropertyDecl *PD = PID->getPropertyDecl();118ObjCMethodDecl *setterM = PD->getSetterMethodDecl();119if (!(setterM && setterM->isDefined())) {120ObjCPropertyAttribute::Kind AttrKind = PD->getPropertyAttributes();121if (AttrKind & (ObjCPropertyAttribute::kind_retain |122ObjCPropertyAttribute::kind_copy |123ObjCPropertyAttribute::kind_strong))124SynthesizedProperties[PD] = PID;125}126}127}128129// Now, remove all zeroing of ivars etc.130base::TraverseObjCMethodDecl(D);131132// clear out for next method.133SynthesizedProperties.clear();134SelfD = nullptr;135Removables.clear();136return true;137}138139bool TraverseFunctionDecl(FunctionDecl *D) { return true; }140bool TraverseBlockDecl(BlockDecl *block) { return true; }141bool TraverseBlockExpr(BlockExpr *block) { return true; }142143private:144bool isRemovable(Expr *E) const {145return Removables.count(E);146}147148bool isZeroingPropIvar(Expr *E) {149E = E->IgnoreParens();150if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))151return isZeroingPropIvar(BO);152if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))153return isZeroingPropIvar(PO);154return false;155}156157bool isZeroingPropIvar(BinaryOperator *BOE) {158if (BOE->getOpcode() == BO_Comma)159return isZeroingPropIvar(BOE->getLHS()) &&160isZeroingPropIvar(BOE->getRHS());161162if (BOE->getOpcode() != BO_Assign)163return false;164165Expr *LHS = BOE->getLHS();166if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {167ObjCIvarDecl *IVDecl = IV->getDecl();168if (!IVDecl->getType()->isObjCObjectPointerType())169return false;170bool IvarBacksPropertySynthesis = false;171for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator172P = SynthesizedProperties.begin(),173E = SynthesizedProperties.end(); P != E; ++P) {174ObjCPropertyImplDecl *PropImpDecl = P->second;175if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {176IvarBacksPropertySynthesis = true;177break;178}179}180if (!IvarBacksPropertySynthesis)181return false;182}183else184return false;185186return isZero(BOE->getRHS());187}188189bool isZeroingPropIvar(PseudoObjectExpr *PO) {190BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());191if (!BO) return false;192if (BO->getOpcode() != BO_Assign) return false;193194ObjCPropertyRefExpr *PropRefExp =195dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());196if (!PropRefExp) return false;197198// TODO: Using implicit property decl.199if (PropRefExp->isImplicitProperty())200return false;201202if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {203if (!SynthesizedProperties.count(PDecl))204return false;205}206207return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());208}209210bool isZero(Expr *E) {211if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))212return true;213214return isZeroingPropIvar(E);215}216};217218} // anonymous namespace219220void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) {221ZeroOutInDeallocRemover trans(pass);222trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());223}224225226