[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:
George Karpenkov 2019-01-10 18:13:59 +00:00
parent 7e3016dec4
commit 585a210e5f
6 changed files with 179 additions and 140 deletions

View File

@ -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();

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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,

View File

@ -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.

View File

@ -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));