property references to use a new PseudoObjectExpr expression which pairs a syntactic form of the expression with a set of semantic expressions implementing it. This should significantly reduce the complexity required elsewhere in the compiler to deal with these kinds of expressions (e.g. IR generation's special l-value kind, the static analyzer's Message abstraction), at the lower cost of specifically dealing with the odd AST structure of these expressions. It should also greatly simplify efforts to implement similar language features in the future, most notably Managed C++'s properties and indexed properties. Most of the effort here is in dealing with the various clients of the AST. I've gone ahead and simplified the ObjC rewriter's use of properties; other clients, like IR-gen and the static analyzer, have all the old complexity *and* all the new complexity, at least temporarily. Many thanks to Ted for writing and advising on the necessary changes to the static analyzer. I've xfailed a small diagnostics regression in the static analyzer at Ted's request. llvm-svn: 143867
229 lines
6.8 KiB
C++
229 lines
6.8 KiB
C++
//===--- 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());
|
|
}
|