forked from OSchip/llvm-project
[analyzer] [NFC] Track object type with ArgEffect in RetainCountChecker.
This would be needed in the future. https://reviews.llvm.org/D56040 llvm-svn: 350858
This commit is contained in:
parent
7e3016dec4
commit
585a210e5f
|
@ -52,9 +52,7 @@ enum class ObjKind {
|
|||
OS
|
||||
};
|
||||
|
||||
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
|
||||
/// to a function or method.
|
||||
enum ArgEffect {
|
||||
enum ArgEffectKind {
|
||||
/// There is no effect.
|
||||
DoNothing,
|
||||
|
||||
|
@ -133,6 +131,27 @@ enum ArgEffect {
|
|||
DecRefMsgAndStopTrackingHard
|
||||
};
|
||||
|
||||
/// An ArgEffect summarizes the retain count behavior on an argument or receiver
|
||||
/// to a function or method.
|
||||
class ArgEffect {
|
||||
ArgEffectKind K;
|
||||
ObjKind O;
|
||||
public:
|
||||
explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj)
|
||||
: K(K), O(O) {}
|
||||
|
||||
ArgEffectKind getKind() const { return K; }
|
||||
ObjKind getObjKind() const { return O; }
|
||||
|
||||
ArgEffect withKind(ArgEffectKind NewK) {
|
||||
return ArgEffect(NewK, O);
|
||||
}
|
||||
|
||||
bool operator==(const ArgEffect &Other) const {
|
||||
return K == Other.K && O == Other.O;
|
||||
}
|
||||
};
|
||||
|
||||
/// RetEffect summarizes a call's retain/release behavior with respect
|
||||
/// to its return value.
|
||||
class RetEffect {
|
||||
|
@ -218,7 +237,9 @@ class CallEffects {
|
|||
RetEffect Ret;
|
||||
ArgEffect Receiver;
|
||||
|
||||
CallEffects(const RetEffect &R) : Ret(R) {}
|
||||
CallEffects(const RetEffect &R,
|
||||
ArgEffect Receiver = ArgEffect(DoNothing, ObjKind::AnyObj))
|
||||
: Ret(R), Receiver(Receiver) {}
|
||||
|
||||
public:
|
||||
/// Returns the argument effects for a call.
|
||||
|
@ -263,7 +284,8 @@ namespace llvm {
|
|||
|
||||
template <> struct FoldingSetTrait<ArgEffect> {
|
||||
static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
|
||||
ID.AddInteger((unsigned) X);
|
||||
ID.AddInteger((unsigned) X.getKind());
|
||||
ID.AddInteger((unsigned) X.getObjKind());
|
||||
}
|
||||
};
|
||||
template <> struct FoldingSetTrait<RetEffect> {
|
||||
|
@ -377,8 +399,8 @@ public:
|
|||
void setThisEffect(ArgEffect e) { This = e; }
|
||||
|
||||
bool isNoop() const {
|
||||
return Ret == RetEffect::MakeNoRet() && Receiver == DoNothing
|
||||
&& DefaultArgEffect == MayEscape && This == DoNothing
|
||||
return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing
|
||||
&& DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing
|
||||
&& Args.isEmpty();
|
||||
}
|
||||
|
||||
|
@ -547,32 +569,31 @@ class RetainSummaryManager {
|
|||
|
||||
const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm);
|
||||
|
||||
const RetainSummary *getPersistentSummary(RetEffect RetEff,
|
||||
ArgEffects ScratchArgs,
|
||||
ArgEffect ReceiverEff = DoNothing,
|
||||
ArgEffect DefaultEff = MayEscape,
|
||||
ArgEffect ThisEff = DoNothing) {
|
||||
RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff,
|
||||
ThisEff);
|
||||
const RetainSummary *
|
||||
getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs,
|
||||
ArgEffect ReceiverEff = ArgEffect(DoNothing),
|
||||
ArgEffect DefaultEff = ArgEffect(MayEscape),
|
||||
ArgEffect ThisEff = ArgEffect(DoNothing)) {
|
||||
RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff);
|
||||
return getPersistentSummary(Summ);
|
||||
}
|
||||
|
||||
const RetainSummary *getDoNothingSummary() {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ArgEffects(AF.getEmptyMap()),
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
}
|
||||
|
||||
const RetainSummary *getDefaultSummary() {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ArgEffects(AF.getEmptyMap()),
|
||||
DoNothing, MayEscape);
|
||||
ArgEffect(DoNothing), ArgEffect(MayEscape));
|
||||
}
|
||||
|
||||
const RetainSummary *getPersistentStopSummary() {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ArgEffects(AF.getEmptyMap()),
|
||||
StopTracking, StopTracking);
|
||||
return getPersistentSummary(
|
||||
RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()),
|
||||
ArgEffect(StopTracking), ArgEffect(StopTracking));
|
||||
}
|
||||
|
||||
void InitializeClassMethodSummaries();
|
||||
|
|
|
@ -1484,13 +1484,13 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
|
|||
pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
ArgEffect AE = AEArgs[i];
|
||||
if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
|
||||
if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
|
||||
NSAPIObj->isMacroDefined("CF_CONSUMED")) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
|
||||
Editor->commit(commit);
|
||||
}
|
||||
else if (AE == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() &&
|
||||
else if (AE.getKind() == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() &&
|
||||
NSAPIObj->isMacroDefined("NS_CONSUMED")) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
|
||||
|
@ -1536,13 +1536,13 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
|
|||
pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
ArgEffect AE = AEArgs[i];
|
||||
if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
|
||||
if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>())
|
||||
if (AE.getKind() == DecRef /*CFConsumed annotated*/ ||
|
||||
AE.getKind() == IncRef) {
|
||||
if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>())
|
||||
ArgCFAudited = true;
|
||||
else if (AE == IncRef)
|
||||
else if (AE.getKind() == IncRef)
|
||||
ArgCFAudited = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
QualType AT = pd->getType();
|
||||
if (!AuditedType(AT)) {
|
||||
AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated);
|
||||
|
@ -1610,7 +1610,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
|
|||
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
ArgEffect AE = AEArgs[i];
|
||||
if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
|
||||
if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
|
||||
NSAPIObj->isMacroDefined("CF_CONSUMED")) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
|
||||
|
@ -1626,13 +1626,14 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
|
|||
return;
|
||||
|
||||
CallEffects CE = CallEffects::getEffect(MethodDecl);
|
||||
bool MethodIsReturnAnnotated = (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
|
||||
bool MethodIsReturnAnnotated =
|
||||
(MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
|
||||
MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
|
||||
|
||||
if (CE.getReceiver() == DecRefMsg &&
|
||||
if (CE.getReceiver().getKind() == DecRefMsg &&
|
||||
!MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
|
||||
MethodDecl->getMethodFamily() != OMF_init &&
|
||||
MethodDecl->getMethodFamily() != OMF_release &&
|
||||
|
@ -1666,8 +1667,8 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
|
|||
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
ArgEffect AE = AEArgs[i];
|
||||
if ((AE == DecRef && !pd->hasAttr<CFConsumedAttr>()) || AE == IncRef ||
|
||||
!AuditedType(pd->getType())) {
|
||||
if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) ||
|
||||
AE.getKind() == IncRef || !AuditedType(pd->getType())) {
|
||||
AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
|
|||
if (!BE)
|
||||
return;
|
||||
|
||||
ArgEffect AE = IncRef;
|
||||
ArgEffectKind AE = IncRef;
|
||||
|
||||
switch (BE->getBridgeKind()) {
|
||||
case OBC_Bridge:
|
||||
|
@ -534,7 +534,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
|
|||
SVal V = CallOrMsg.getArgSVal(idx);
|
||||
|
||||
if (SymbolRef Sym = V.getAsLocSymbol()) {
|
||||
bool ShouldRemoveBinding = Summ.getArg(idx) == StopTrackingHard;
|
||||
bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
|
||||
if (const RefVal *T = getRefBinding(state, Sym))
|
||||
if (shouldEscapeArgumentOnCall(CallOrMsg, idx, T))
|
||||
ShouldRemoveBinding = true;
|
||||
|
@ -547,7 +547,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
|
|||
// Evaluate the effect on the message receiver.
|
||||
if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
|
||||
if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
|
||||
if (Summ.getReceiverEffect() == StopTrackingHard) {
|
||||
if (Summ.getReceiverEffect().getKind() == StopTrackingHard) {
|
||||
state = removeRefBinding(state, Sym);
|
||||
}
|
||||
}
|
||||
|
@ -566,7 +566,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
|
|||
|
||||
static ProgramStateRef updateOutParameter(ProgramStateRef State,
|
||||
SVal ArgVal,
|
||||
ArgEffect Effect) {
|
||||
ArgEffectKind Effect) {
|
||||
auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
|
||||
if (!ArgRegion)
|
||||
return State;
|
||||
|
@ -611,7 +611,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
|
||||
SVal V = CallOrMsg.getArgSVal(idx);
|
||||
|
||||
ArgEffect Effect = Summ.getArg(idx);
|
||||
ArgEffectKind Effect = Summ.getArg(idx).getKind();
|
||||
if (Effect == RetainedOutParameter || Effect == UnretainedOutParameter) {
|
||||
state = updateOutParameter(state, V, Effect);
|
||||
} else if (SymbolRef Sym = V.getAsLocSymbol()) {
|
||||
|
@ -637,8 +637,8 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
|
||||
if (const RefVal *T = getRefBinding(state, Sym)) {
|
||||
ReceiverIsTracked = true;
|
||||
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
|
||||
hasErr, C);
|
||||
state = updateSymbol(state, Sym, *T,
|
||||
Summ.getReceiverEffect().getKind(), hasErr, C);
|
||||
if (hasErr) {
|
||||
ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
|
||||
ErrorSym = Sym;
|
||||
|
@ -648,7 +648,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
} else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
|
||||
if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
|
||||
if (const RefVal *T = getRefBinding(state, Sym)) {
|
||||
state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
|
||||
state = updateSymbol(state, Sym, *T, Summ.getThisEffect().getKind(),
|
||||
hasErr, C);
|
||||
if (hasErr) {
|
||||
ErrorRange = MCall->getOriginExpr()->getSourceRange();
|
||||
|
@ -707,10 +707,11 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
}
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const {
|
||||
ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
|
||||
SymbolRef sym, RefVal V,
|
||||
ArgEffectKind E,
|
||||
RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const {
|
||||
bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
|
||||
switch (E) {
|
||||
default:
|
||||
|
@ -1405,7 +1406,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
|
|||
|
||||
QualType Ty = Param->getType();
|
||||
const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
|
||||
if (AE && *AE == DecRef && isISLObjectRef(Ty)) {
|
||||
if (AE && AE->getKind() == DecRef && isISLObjectRef(Ty)) {
|
||||
state = setRefBinding(
|
||||
state, Sym, RefVal::makeOwned(ObjKind::Generalized, Ty));
|
||||
} else if (isISLObjectRef(Ty)) {
|
||||
|
|
|
@ -347,7 +347,7 @@ public:
|
|||
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
|
||||
|
||||
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
RefVal V, ArgEffectKind E, RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const;
|
||||
|
||||
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
|
||||
|
|
|
@ -48,7 +48,9 @@ static bool shouldGenerateNote(llvm::raw_string_ostream &os,
|
|||
RefVal PrevV = *PrevT;
|
||||
|
||||
// Specially handle -dealloc.
|
||||
if (std::find(AEffects.begin(), AEffects.end(), Dealloc) != AEffects.end()) {
|
||||
if (std::find_if(AEffects.begin(), AEffects.end(), [](ArgEffect &E) {
|
||||
return E.getKind() == Dealloc;
|
||||
}) != AEffects.end()) {
|
||||
// Determine if the object's reference count was pushed to zero.
|
||||
assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
|
||||
// We may not have transitioned to 'release' if we hit an error.
|
||||
|
|
|
@ -201,8 +201,8 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
|
|||
// Part of: <rdar://problem/39390714>.
|
||||
return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
|
||||
ScratchArgs,
|
||||
DoNothing,
|
||||
DoNothing);
|
||||
ArgEffect(DoNothing),
|
||||
ArgEffect(DoNothing));
|
||||
} else if (FName == "CFPlugInInstanceCreate") {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs);
|
||||
} else if (FName == "IORegistryEntrySearchCFProperty" ||
|
||||
|
@ -213,25 +213,25 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
|
|||
FName == "IOOpenFirmwarePathMatching"))) {
|
||||
// Part of <rdar://problem/6961230>. (IOKit)
|
||||
// This should be addressed using a API table.
|
||||
return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
|
||||
ScratchArgs, DoNothing, DoNothing);
|
||||
return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "IOServiceGetMatchingService" ||
|
||||
FName == "IOServiceGetMatchingServices") {
|
||||
// FIXES: <rdar://problem/6326900>
|
||||
// This should be addressed using a API table. This strcmp is also
|
||||
// a little gross, but there is no need to super optimize here.
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, DecRef);
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(DecRef, ObjKind::CF));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "IOServiceAddNotification" ||
|
||||
FName == "IOServiceAddMatchingNotification") {
|
||||
// Part of <rdar://problem/6961230>. (IOKit)
|
||||
// This should be addressed using a API table.
|
||||
ScratchArgs = AF.add(ScratchArgs, 2, DecRef);
|
||||
ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(DecRef, ObjKind::CF));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "CVPixelBufferCreateWithBytes") {
|
||||
// FIXES: <rdar://problem/7283567>
|
||||
// Eventually this can be improved by recognizing that the pixel
|
||||
|
@ -239,38 +239,38 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
|
|||
// a callback and doing full IPA to make sure this is done correctly.
|
||||
// FIXME: This function has an out parameter that returns an
|
||||
// allocated object.
|
||||
ScratchArgs = AF.add(ScratchArgs, 7, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 7, ArgEffect(StopTracking));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "CGBitmapContextCreateWithData") {
|
||||
// FIXES: <rdar://problem/7358899>
|
||||
// Eventually this can be improved by recognizing that 'releaseInfo'
|
||||
// passed to CGBitmapContextCreateWithData is released via
|
||||
// a callback and doing full IPA to make sure this is done correctly.
|
||||
ScratchArgs = AF.add(ScratchArgs, 8, StopTracking);
|
||||
return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF),
|
||||
ScratchArgs, DoNothing, DoNothing);
|
||||
ScratchArgs = AF.add(ScratchArgs, 8, ArgEffect(ArgEffect(StopTracking)));
|
||||
return getPersistentSummary(RetEffect::MakeOwned(ObjKind::CF), ScratchArgs,
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
|
||||
// FIXES: <rdar://problem/7283567>
|
||||
// Eventually this can be improved by recognizing that the pixel
|
||||
// buffer passed to CVPixelBufferCreateWithPlanarBytes is released
|
||||
// via a callback and doing full IPA to make sure this is done
|
||||
// correctly.
|
||||
ScratchArgs = AF.add(ScratchArgs, 12, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 12, ArgEffect(StopTracking));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "VTCompressionSessionEncodeFrame") {
|
||||
// The context argument passed to VTCompressionSessionEncodeFrame()
|
||||
// is passed to the callback specified when creating the session
|
||||
// (e.g. with VTCompressionSessionCreate()) which can release it.
|
||||
// To account for this possibility, conservatively stop tracking
|
||||
// the context.
|
||||
ScratchArgs = AF.add(ScratchArgs, 5, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 5, ArgEffect(StopTracking));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName == "dispatch_set_context" ||
|
||||
FName == "xpc_connection_set_context") {
|
||||
// <rdar://problem/11059275> - The analyzer currently doesn't have
|
||||
|
@ -279,20 +279,21 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
|
|||
// <rdar://problem/13783514> - Same problem, but for XPC.
|
||||
// FIXME: this hack should possibly go away once we can handle
|
||||
// libdispatch and XPC finalizers.
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
} else if (FName.startswith("NSLog")) {
|
||||
return getDoNothingSummary();
|
||||
} else if (FName.startswith("NS") &&
|
||||
(FName.find("Insert") != StringRef::npos)) {
|
||||
// Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
|
||||
// be deallocated by NSMapRemove. (radar://11152419)
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 2, StopTracking);
|
||||
ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking));
|
||||
ScratchArgs = AF.add(ScratchArgs, 2, ArgEffect(StopTracking));
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs, DoNothing, DoNothing);
|
||||
ScratchArgs, ArgEffect(DoNothing),
|
||||
ArgEffect(DoNothing));
|
||||
}
|
||||
|
||||
if (RetTy->isPointerType()) {
|
||||
|
@ -367,16 +368,17 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject(
|
|||
// "AppendValue", or "SetAttribute", then we assume that arguments may
|
||||
// "escape." This means that something else holds on to the object,
|
||||
// allowing it be used even after its local retain count drops to 0.
|
||||
ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
|
||||
? MayEscape
|
||||
: DoNothing;
|
||||
ArgEffectKind E =
|
||||
(StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "AppendValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
|
||||
? MayEscape
|
||||
: DoNothing;
|
||||
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
|
||||
DoNothing, E);
|
||||
ArgEffect(DoNothing), ArgEffect(E, ObjKind::CF));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,8 +417,9 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
|
|||
if (!(TrackOSObjects && isOSObjectRelated(MD)))
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ArgEffects(AF.getEmptyMap()),
|
||||
DoNothing, StopTracking,
|
||||
DoNothing);
|
||||
ArgEffect(DoNothing),
|
||||
ArgEffect(StopTracking),
|
||||
ArgEffect(DoNothing));
|
||||
|
||||
return getDefaultSummary();
|
||||
}
|
||||
|
@ -449,7 +452,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
|
||||
switch (E) {
|
||||
switch (E.getKind()) {
|
||||
case DoNothing:
|
||||
case Autorelease:
|
||||
case DecRefBridgedTransferred:
|
||||
|
@ -461,15 +464,15 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
|
|||
case MayEscape:
|
||||
case StopTracking:
|
||||
case StopTrackingHard:
|
||||
return StopTrackingHard;
|
||||
return E.withKind(StopTrackingHard);
|
||||
case DecRef:
|
||||
case DecRefAndStopTrackingHard:
|
||||
return DecRefAndStopTrackingHard;
|
||||
return E.withKind(DecRefAndStopTrackingHard);
|
||||
case DecRefMsg:
|
||||
case DecRefMsgAndStopTrackingHard:
|
||||
return DecRefMsgAndStopTrackingHard;
|
||||
return E.withKind(DecRefMsgAndStopTrackingHard);
|
||||
case Dealloc:
|
||||
return Dealloc;
|
||||
return E.withKind(Dealloc);
|
||||
}
|
||||
|
||||
llvm_unreachable("Unknown ArgEffect kind");
|
||||
|
@ -489,7 +492,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
|
|||
E = CustomArgEffects.end();
|
||||
I != E; ++I) {
|
||||
ArgEffect Translated = getStopTrackingHardEquivalent(I->second);
|
||||
if (Translated != DefEffect)
|
||||
if (Translated.getKind() != DefEffect.getKind())
|
||||
ScratchArgs = AF.add(ScratchArgs, I->first, Translated);
|
||||
}
|
||||
|
||||
|
@ -535,7 +538,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
|
|||
ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap();
|
||||
if (!PM.isConsumedExpr(ME)) {
|
||||
RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
|
||||
ModifiableSummaryTemplate->setReceiverEffect(DoNothing);
|
||||
ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing));
|
||||
ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
|
||||
}
|
||||
}
|
||||
|
@ -661,43 +664,43 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
|
|||
|
||||
ArgEffect Effect;
|
||||
switch (func) {
|
||||
case cfretain: Effect = IncRef; break;
|
||||
case cfrelease: Effect = DecRef; break;
|
||||
case cfautorelease: Effect = Autorelease; break;
|
||||
case cfmakecollectable: Effect = MakeCollectable; break;
|
||||
case cfretain: Effect = Effect.withKind(IncRef); break;
|
||||
case cfrelease: Effect = Effect.withKind(DecRef); break;
|
||||
case cfautorelease: Effect = Effect.withKind(Autorelease); break;
|
||||
case cfmakecollectable: Effect = Effect.withKind(MakeCollectable); break;
|
||||
}
|
||||
|
||||
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getOSSummaryRetainRule(const FunctionDecl *FD) {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
AF.getEmptyMap(),
|
||||
/*ReceiverEff=*/DoNothing,
|
||||
/*DefaultEff=*/DoNothing,
|
||||
/*ThisEff=*/IncRef);
|
||||
/*ReceiverEff=*/ArgEffect(DoNothing),
|
||||
/*DefaultEff=*/ArgEffect(DoNothing),
|
||||
/*ThisEff=*/ArgEffect(IncRef, ObjKind::OS));
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getOSSummaryReleaseRule(const FunctionDecl *FD) {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
AF.getEmptyMap(),
|
||||
/*ReceiverEff=*/DoNothing,
|
||||
/*DefaultEff=*/DoNothing,
|
||||
/*ThisEff=*/DecRef);
|
||||
/*ReceiverEff=*/ArgEffect(DoNothing),
|
||||
/*DefaultEff=*/ArgEffect(DoNothing),
|
||||
/*ThisEff=*/ArgEffect(DecRef, ObjKind::OS));
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getOSSummaryFreeRule(const FunctionDecl *FD) {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
AF.getEmptyMap(),
|
||||
/*ReceiverEff=*/DoNothing,
|
||||
/*DefaultEff=*/DoNothing,
|
||||
/*ThisEff=*/Dealloc);
|
||||
/*ReceiverEff=*/ArgEffect(DoNothing),
|
||||
/*DefaultEff=*/ArgEffect(DoNothing),
|
||||
/*ThisEff=*/ArgEffect(Dealloc, ObjKind::OS));
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
|
@ -722,7 +725,7 @@ const RetainSummary *
|
|||
RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
|
||||
return getPersistentSummary(RetEffect::MakeNotOwned(ObjKind::CF),
|
||||
ArgEffects(AF.getEmptyMap()),
|
||||
DoNothing, DoNothing);
|
||||
ArgEffect(DoNothing), ArgEffect(DoNothing));
|
||||
}
|
||||
|
||||
|
||||
|
@ -775,19 +778,24 @@ bool RetainSummaryManager::applyFunctionParamAnnotationEffect(
|
|||
const ParmVarDecl *pd, unsigned parm_idx, const FunctionDecl *FD,
|
||||
RetainSummaryTemplate &Template) {
|
||||
if (hasEnabledAttr<NSConsumedAttr>(pd)) {
|
||||
Template->addArg(AF, parm_idx, DecRefMsg);
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRefMsg, ObjKind::ObjC));
|
||||
return true;
|
||||
} else if (hasEnabledAttr<CFConsumedAttr>(pd) ||
|
||||
hasEnabledAttr<OSConsumedAttr>(pd) ||
|
||||
hasRCAnnotation(pd, "rc_ownership_consumed")) {
|
||||
Template->addArg(AF, parm_idx, DecRef);
|
||||
} else if (hasEnabledAttr<CFConsumedAttr>(pd)) {
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::CF));
|
||||
return true;
|
||||
} else if (hasEnabledAttr<OSConsumedAttr>(pd)) {
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::OS));
|
||||
return true;
|
||||
} else if (hasRCAnnotation(pd, "rc_ownership_consumed")) {
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::Generalized));
|
||||
return true;
|
||||
} else if (hasEnabledAttr<CFReturnsRetainedAttr>(pd) ||
|
||||
hasRCAnnotation(pd, "rc_ownership_returns_retained")) {
|
||||
QualType PointeeTy = pd->getType()->getPointeeType();
|
||||
if (!PointeeTy.isNull()) {
|
||||
if (coreFoundation::isCFObjectRef(PointeeTy)) {
|
||||
Template->addArg(AF, parm_idx, RetainedOutParameter);
|
||||
Template->addArg(AF, parm_idx, ArgEffect(RetainedOutParameter,
|
||||
ObjKind::CF));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -795,7 +803,8 @@ bool RetainSummaryManager::applyFunctionParamAnnotationEffect(
|
|||
QualType PointeeTy = pd->getType()->getPointeeType();
|
||||
if (!PointeeTy.isNull()) {
|
||||
if (coreFoundation::isCFObjectRef(PointeeTy)) {
|
||||
Template->addArg(AF, parm_idx, UnretainedOutParameter);
|
||||
Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter,
|
||||
ObjKind::CF));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -834,7 +843,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
Template->setRetEffect(*RetE);
|
||||
|
||||
if (hasEnabledAttr<OSConsumesThisAttr>(FD))
|
||||
Template->setThisEffect(DecRef);
|
||||
Template->setThisEffect(ArgEffect(DecRef, ObjKind::OS));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -848,7 +857,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
|
||||
// Effects on the receiver.
|
||||
if (MD->hasAttr<NSConsumesSelfAttr>())
|
||||
Template->setReceiverEffect(DecRefMsg);
|
||||
Template->setReceiverEffect(ArgEffect(DecRefMsg, ObjKind::ObjC));
|
||||
|
||||
// Effects on the parameters.
|
||||
unsigned parm_idx = 0;
|
||||
|
@ -856,19 +865,23 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
pi != pe; ++pi, ++parm_idx) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
if (pd->hasAttr<NSConsumedAttr>()) {
|
||||
Template->addArg(AF, parm_idx, DecRefMsg);
|
||||
} else if (pd->hasAttr<CFConsumedAttr>() || pd->hasAttr<OSConsumedAttr>()) {
|
||||
Template->addArg(AF, parm_idx, DecRef);
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRefMsg, ObjKind::ObjC));
|
||||
} else if (pd->hasAttr<CFConsumedAttr>()) {
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::CF));
|
||||
} else if (pd->hasAttr<OSConsumedAttr>()) {
|
||||
Template->addArg(AF, parm_idx, ArgEffect(DecRef, ObjKind::OS));
|
||||
} else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
|
||||
QualType PointeeTy = pd->getType()->getPointeeType();
|
||||
if (!PointeeTy.isNull())
|
||||
if (coreFoundation::isCFObjectRef(PointeeTy))
|
||||
Template->addArg(AF, parm_idx, RetainedOutParameter);
|
||||
Template->addArg(AF, parm_idx,
|
||||
ArgEffect(RetainedOutParameter, ObjKind::CF));
|
||||
} else if (pd->hasAttr<CFReturnsNotRetainedAttr>()) {
|
||||
QualType PointeeTy = pd->getType()->getPointeeType();
|
||||
if (!PointeeTy.isNull())
|
||||
if (coreFoundation::isCFObjectRef(PointeeTy))
|
||||
Template->addArg(AF, parm_idx, UnretainedOutParameter);
|
||||
Template->addArg(AF, parm_idx, ArgEffect(UnretainedOutParameter,
|
||||
ObjKind::CF));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -881,7 +894,7 @@ const RetainSummary *
|
|||
RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
||||
Selector S, QualType RetTy) {
|
||||
// Any special effects?
|
||||
ArgEffect ReceiverEff = DoNothing;
|
||||
ArgEffect ReceiverEff = ArgEffect(DoNothing, ObjKind::ObjC);
|
||||
RetEffect ResultEff = RetEffect::MakeNoRet();
|
||||
|
||||
// Check the method family, and apply any default annotations.
|
||||
|
@ -918,7 +931,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
break;
|
||||
case OMF_init:
|
||||
ResultEff = ObjCInitRetE;
|
||||
ReceiverEff = DecRefMsg;
|
||||
ReceiverEff = ArgEffect(DecRefMsg, ObjKind::ObjC);
|
||||
break;
|
||||
case OMF_alloc:
|
||||
case OMF_new:
|
||||
|
@ -930,16 +943,16 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
ResultEff = RetEffect::MakeOwned(ObjKind::CF);
|
||||
break;
|
||||
case OMF_autorelease:
|
||||
ReceiverEff = Autorelease;
|
||||
ReceiverEff = ArgEffect(Autorelease, ObjKind::ObjC);
|
||||
break;
|
||||
case OMF_retain:
|
||||
ReceiverEff = IncRefMsg;
|
||||
ReceiverEff = ArgEffect(IncRefMsg, ObjKind::ObjC);
|
||||
break;
|
||||
case OMF_release:
|
||||
ReceiverEff = DecRefMsg;
|
||||
ReceiverEff = ArgEffect(DecRefMsg, ObjKind::ObjC);
|
||||
break;
|
||||
case OMF_dealloc:
|
||||
ReceiverEff = Dealloc;
|
||||
ReceiverEff = ArgEffect(Dealloc, ObjKind::ObjC);
|
||||
break;
|
||||
case OMF_self:
|
||||
// -self is handled specially by the ExprEngine to propagate the receiver.
|
||||
|
@ -961,17 +974,17 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
if (ResultEff == ObjCInitRetE)
|
||||
ResultEff = RetEffect::MakeNoRetHard();
|
||||
else
|
||||
ReceiverEff = StopTrackingHard;
|
||||
ReceiverEff = ArgEffect(StopTrackingHard, ObjKind::ObjC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ReceiverEff == DoNothing &&
|
||||
if (ReceiverEff.getKind() == DoNothing &&
|
||||
ResultEff.getKind() == RetEffect::NoRet)
|
||||
return getDefaultSummary();
|
||||
|
||||
return getPersistentSummary(ResultEff, ArgEffects(AF.getEmptyMap()),
|
||||
ReceiverEff, MayEscape);
|
||||
ArgEffect(ReceiverEff), ArgEffect(MayEscape));
|
||||
}
|
||||
|
||||
const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
|
||||
|
@ -1037,11 +1050,11 @@ void RetainSummaryManager::InitializeClassMethodSummaries() {
|
|||
ScratchArgs));
|
||||
|
||||
// Create the [NSAutoreleasePool addObject:] summary.
|
||||
ScratchArgs = AF.add(ScratchArgs, 0, Autorelease);
|
||||
ScratchArgs = AF.add(ScratchArgs, 0, ArgEffect(Autorelease));
|
||||
addClassMethSummary("NSAutoreleasePool", "addObject",
|
||||
getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
ScratchArgs,
|
||||
DoNothing, Autorelease));
|
||||
getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
|
||||
ArgEffect(DoNothing),
|
||||
ArgEffect(Autorelease)));
|
||||
}
|
||||
|
||||
void RetainSummaryManager::InitializeMethodSummaries() {
|
||||
|
@ -1051,7 +1064,7 @@ void RetainSummaryManager::InitializeMethodSummaries() {
|
|||
// receiver.
|
||||
const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE,
|
||||
ScratchArgs,
|
||||
DecRefMsg);
|
||||
ArgEffect(DecRefMsg));
|
||||
addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
|
||||
|
||||
// awakeAfterUsingCoder: behaves basically like an 'init' method. It
|
||||
|
@ -1067,19 +1080,20 @@ void RetainSummaryManager::InitializeMethodSummaries() {
|
|||
|
||||
// Create the "retain" selector.
|
||||
RetEffect NoRet = RetEffect::MakeNoRet();
|
||||
const RetainSummary *Summ = getPersistentSummary(NoRet, ScratchArgs, IncRefMsg);
|
||||
const RetainSummary *Summ =
|
||||
getPersistentSummary(NoRet, ScratchArgs, ArgEffect(IncRefMsg));
|
||||
addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
|
||||
|
||||
// Create the "release" selector.
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, DecRefMsg);
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(DecRefMsg));
|
||||
addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
|
||||
|
||||
// Create the -dealloc summary.
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, Dealloc);
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Dealloc));
|
||||
addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
|
||||
|
||||
// Create the "autorelease" selector.
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, Autorelease);
|
||||
Summ = getPersistentSummary(NoRet, ScratchArgs, ArgEffect(Autorelease));
|
||||
addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
|
||||
|
||||
// For NSWindow, allocated objects are (initially) self-owned.
|
||||
|
@ -1088,8 +1102,9 @@ void RetainSummaryManager::InitializeMethodSummaries() {
|
|||
// Thus, we need to track an NSWindow's display status.
|
||||
// This is tracked in <rdar://problem/6062711>.
|
||||
// See also http://llvm.org/bugs/show_bug.cgi?id=3714.
|
||||
const RetainSummary *NoTrackYet = getPersistentSummary(
|
||||
RetEffect::MakeNoRet(), ScratchArgs, StopTracking, StopTracking);
|
||||
const RetainSummary *NoTrackYet =
|
||||
getPersistentSummary(RetEffect::MakeNoRet(), ScratchArgs,
|
||||
ArgEffect(StopTracking), ArgEffect(StopTracking));
|
||||
|
||||
addClassMethSummary("NSWindow", "alloc", NoTrackYet);
|
||||
|
||||
|
@ -1130,8 +1145,7 @@ CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
|
|||
/*TrackNSAndCFObjects=*/true,
|
||||
/*TrackOSObjects=*/false);
|
||||
const RetainSummary *S = M.getMethodSummary(MD);
|
||||
CallEffects CE(S->getRetEffect());
|
||||
CE.Receiver = S->getReceiverEffect();
|
||||
CallEffects CE(S->getRetEffect(), S->getReceiverEffect());
|
||||
unsigned N = MD->param_size();
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
CE.Args.push_back(S->getArg(i));
|
||||
|
|
Loading…
Reference in New Issue