[analyzer] [ARCMT] [NFC] Unify entry point into RetainSummaryManager

Just use one single entry point, since we have AnyCall utility now.

Differential Revision: https://reviews.llvm.org/D57346

llvm-svn: 352532
This commit is contained in:
George Karpenkov 2019-01-29 19:29:33 +00:00
parent 38bc347ff5
commit 2e46667853
4 changed files with 49 additions and 98 deletions

View File

@ -203,40 +203,6 @@ public:
} }
}; };
/// Encapsulates the retain count semantics on the arguments, return value,
/// and receiver (if any) of a function/method call.
///
/// Note that construction of these objects is not highly efficient. That
/// is okay for clients where creating these objects isn't really a bottleneck.
/// The purpose of the API is to provide something simple. The actual
/// static analyzer checker that implements retain/release typestate
/// tracking uses something more efficient.
class CallEffects {
llvm::SmallVector<ArgEffect, 10> Args;
RetEffect Ret;
ArgEffect Receiver;
CallEffects(const RetEffect &R,
ArgEffect Receiver = ArgEffect(DoNothing, ObjKind::AnyObj))
: Ret(R), Receiver(Receiver) {}
public:
/// Returns the argument effects for a call.
ArrayRef<ArgEffect> getArgs() const { return Args; }
/// Returns the effects on the receiver.
ArgEffect getReceiver() const { return Receiver; }
/// Returns the effect on the return value.
RetEffect getReturnValue() const { return Ret; }
/// Return the CallEfect for a given Objective-C method.
static CallEffects getEffect(const ObjCMethodDecl *MD);
/// Return the CallEfect for a given C/C++ function.
static CallEffects getEffect(const FunctionDecl *FD);
};
/// A key identifying a summary. /// A key identifying a summary.
class ObjCSummaryKey { class ObjCSummaryKey {
IdentifierInfo* II; IdentifierInfo* II;
@ -690,9 +656,13 @@ public:
bool isTrustedReferenceCountImplementation(const FunctionDecl *FD); bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
const RetainSummary *getSummary(AnyCall C, const RetainSummary *getSummary(AnyCall C,
bool HasNonZeroCallbackArg, bool HasNonZeroCallbackArg=false,
bool IsReceiverUnconsumedSelf, bool IsReceiverUnconsumedSelf=false,
QualType ReceiverType=QualType()); QualType ReceiverType={});
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
private:
/// getMethodSummary - This version of getMethodSummary is used to query /// getMethodSummary - This version of getMethodSummary is used to query
/// the summary for the current method being analyzed. /// the summary for the current method being analyzed.
@ -700,9 +670,6 @@ public:
const RetainSummary *getFunctionSummary(const FunctionDecl *FD); const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
private:
const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID, const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD, const ObjCMethodDecl *MD,
QualType RetTy, QualType RetTy,

View File

@ -64,9 +64,11 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
ObjCInstanceTypeFamily OIT_Family = OIT_None); ObjCInstanceTypeFamily OIT_Family = OIT_None);
void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl); void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, void AddCFAnnotations(ASTContext &Ctx,
const RetainSummary *RS,
const FunctionDecl *FuncDecl, bool ResultAnnotated); const FunctionDecl *FuncDecl, bool ResultAnnotated);
void AddCFAnnotations(ASTContext &Ctx, const CallEffects &CE, void AddCFAnnotations(ASTContext &Ctx,
const RetainSummary *RS,
const ObjCMethodDecl *MethodDecl, bool ResultAnnotated); const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
void AnnotateImplicitBridging(ASTContext &Ctx); void AnnotateImplicitBridging(ASTContext &Ctx);
@ -84,6 +86,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc); bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
std::unique_ptr<RetainSummaryManager> Summaries;
public: public:
std::string MigrateDir; std::string MigrateDir;
unsigned ASTMigrateActions; unsigned ASTMigrateActions;
@ -102,6 +106,14 @@ public:
llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
llvm::StringSet<> WhiteListFilenames; llvm::StringSet<> WhiteListFilenames;
RetainSummaryManager &getSummaryManager(ASTContext &Ctx) {
if (!Summaries)
Summaries.reset(new RetainSummaryManager(Ctx,
/*TrackNSCFObjects=*/true,
/*TrackOSObjects=*/false));
return *Summaries;
}
ObjCMigrateASTConsumer(StringRef migrateDir, ObjCMigrateASTConsumer(StringRef migrateDir,
unsigned astMigrateActions, unsigned astMigrateActions,
FileRemapper &remapper, FileRemapper &remapper,
@ -1452,12 +1464,12 @@ void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *De
} }
void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
const CallEffects &CE, const RetainSummary *RS,
const FunctionDecl *FuncDecl, const FunctionDecl *FuncDecl,
bool ResultAnnotated) { bool ResultAnnotated) {
// Annotate function. // Annotate function.
if (!ResultAnnotated) { if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue(); RetEffect Ret = RS->getRetEffect();
const char *AnnotationString = nullptr; const char *AnnotationString = nullptr;
if (Ret.getObjKind() == ObjKind::CF) { if (Ret.getObjKind() == ObjKind::CF) {
if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
@ -1477,12 +1489,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit); Editor->commit(commit);
} }
} }
ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0; unsigned i = 0;
for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i]; ArgEffect AE = RS->getArg(i);
if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF && if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF &&
!pd->hasAttr<CFConsumedAttr>() && !pd->hasAttr<CFConsumedAttr>() &&
NSAPIObj->isMacroDefined("CF_CONSUMED")) { NSAPIObj->isMacroDefined("CF_CONSUMED")) {
@ -1506,7 +1517,8 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
if (FuncDecl->hasBody()) if (FuncDecl->hasBody())
return CF_BRIDGING_NONE; return CF_BRIDGING_NONE;
CallEffects CE = CallEffects::getEffect(FuncDecl); const RetainSummary *RS =
getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl));
bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() || bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() || FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
FuncDecl->hasAttr<NSReturnsRetainedAttr>() || FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
@ -1519,7 +1531,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
bool ReturnCFAudited = false; bool ReturnCFAudited = false;
if (!FuncIsReturnAnnotated) { if (!FuncIsReturnAnnotated) {
RetEffect Ret = CE.getReturnValue(); RetEffect Ret = RS->getRetEffect();
if (Ret.getObjKind() == ObjKind::CF && if (Ret.getObjKind() == ObjKind::CF &&
(Ret.isOwned() || Ret.notOwned())) (Ret.isOwned() || Ret.notOwned()))
ReturnCFAudited = true; ReturnCFAudited = true;
@ -1528,14 +1540,12 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
} }
// At this point result type is audited for potential inclusion. // At this point result type is audited for potential inclusion.
// Now, how about argument types.
ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0; unsigned i = 0;
bool ArgCFAudited = false; bool ArgCFAudited = false;
for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(), for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) { pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i]; ArgEffect AE = RS->getArg(i);
if ((AE.getKind() == DecRef /*CFConsumed annotated*/ || if ((AE.getKind() == DecRef /*CFConsumed annotated*/ ||
AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) { AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) {
if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>())
@ -1545,7 +1555,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
} else { } else {
QualType AT = pd->getType(); QualType AT = pd->getType();
if (!AuditedType(AT)) { if (!AuditedType(AT)) {
AddCFAnnotations(Ctx, CE, FuncDecl, FuncIsReturnAnnotated); AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
return CF_BRIDGING_NONE; return CF_BRIDGING_NONE;
} }
} }
@ -1567,12 +1577,12 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
} }
void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
const CallEffects &CE, const RetainSummary *RS,
const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodDecl,
bool ResultAnnotated) { bool ResultAnnotated) {
// Annotate function. // Annotate function.
if (!ResultAnnotated) { if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue(); RetEffect Ret = RS->getRetEffect();
const char *AnnotationString = nullptr; const char *AnnotationString = nullptr;
if (Ret.getObjKind() == ObjKind::CF) { if (Ret.getObjKind() == ObjKind::CF) {
if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
@ -1604,12 +1614,11 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit); Editor->commit(commit);
} }
} }
ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0; unsigned i = 0;
for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i]; ArgEffect AE = RS->getArg(i);
if (AE.getKind() == DecRef if (AE.getKind() == DecRef
&& AE.getObjKind() == ObjKind::CF && AE.getObjKind() == ObjKind::CF
&& !pd->hasAttr<CFConsumedAttr>() && && !pd->hasAttr<CFConsumedAttr>() &&
@ -1627,7 +1636,9 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
if (MethodDecl->hasBody() || MethodDecl->isImplicit()) if (MethodDecl->hasBody() || MethodDecl->isImplicit())
return; return;
CallEffects CE = CallEffects::getEffect(MethodDecl); const RetainSummary *RS =
getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl));
bool MethodIsReturnAnnotated = bool MethodIsReturnAnnotated =
(MethodDecl->hasAttr<CFReturnsRetainedAttr>() || (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() || MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
@ -1635,7 +1646,7 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() || MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>()); MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
if (CE.getReceiver().getKind() == DecRef && if (RS->getReceiverEffect().getKind() == DecRef &&
!MethodDecl->hasAttr<NSConsumesSelfAttr>() && !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
MethodDecl->getMethodFamily() != OMF_init && MethodDecl->getMethodFamily() != OMF_init &&
MethodDecl->getMethodFamily() != OMF_release && MethodDecl->getMethodFamily() != OMF_release &&
@ -1651,27 +1662,25 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
return; return;
if (!MethodIsReturnAnnotated) { if (!MethodIsReturnAnnotated) {
RetEffect Ret = CE.getReturnValue(); RetEffect Ret = RS->getRetEffect();
if ((Ret.getObjKind() == ObjKind::CF || if ((Ret.getObjKind() == ObjKind::CF ||
Ret.getObjKind() == ObjKind::ObjC) && Ret.getObjKind() == ObjKind::ObjC) &&
(Ret.isOwned() || Ret.notOwned())) { (Ret.isOwned() || Ret.notOwned())) {
AddCFAnnotations(Ctx, CE, MethodDecl, false); AddCFAnnotations(Ctx, RS, MethodDecl, false);
return; return;
} else if (!AuditedType(MethodDecl->getReturnType())) } else if (!AuditedType(MethodDecl->getReturnType()))
return; return;
} }
// At this point result type is either annotated or audited. // At this point result type is either annotated or audited.
// Now, how about argument types.
ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0; unsigned i = 0;
for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(), for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) { pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i]; ArgEffect AE = RS->getArg(i);
if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) || if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) ||
AE.getKind() == IncRef || !AuditedType(pd->getType())) { AE.getKind() == IncRef || !AuditedType(pd->getType())) {
AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated); AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
return; return;
} }
} }

View File

@ -635,11 +635,14 @@ RetainSummaryManager::getSummary(AnyCall C,
// FIXME: These calls are currently unsupported. // FIXME: These calls are currently unsupported.
return getPersistentStopSummary(); return getPersistentStopSummary();
case AnyCall::ObjCMethod: { case AnyCall::ObjCMethod: {
const auto *ME = cast<ObjCMessageExpr>(C.getExpr()); const auto *ME = cast_or_null<ObjCMessageExpr>(C.getExpr());
if (ME->isInstanceMessage()) if (!ME) {
return getMethodSummary(cast<ObjCMethodDecl>(C.getDecl()));
} else if (ME->isInstanceMessage()) {
Summ = getInstanceMethodSummary(ME, ReceiverType); Summ = getInstanceMethodSummary(ME, ReceiverType);
else } else {
Summ = getClassMethodSummary(ME); Summ = getClassMethodSummary(ME);
}
break; break;
} }
} }
@ -1238,31 +1241,3 @@ RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries); return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
} }
CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
ASTContext &Ctx = MD->getASTContext();
RetainSummaryManager M(Ctx,
/*TrackNSAndCFObjects=*/true,
/*TrackOSObjects=*/false);
const RetainSummary *S = M.getMethodSummary(MD);
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));
}
return CE;
}
CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
ASTContext &Ctx = FD->getASTContext();
RetainSummaryManager M(Ctx,
/*TrackNSAndCFObjects=*/true,
/*TrackOSObjects=*/false);
const RetainSummary *S = M.getFunctionSummary(FD);
CallEffects CE(S->getRetEffect());
unsigned N = FD->param_size();
for (unsigned i = 0; i < N; ++i) {
CE.Args.push_back(S->getArg(i));
}
return CE;
}

View File

@ -1031,11 +1031,11 @@ ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
// FIXME: What is the convention for blocks? Is there one? // FIXME: What is the convention for blocks? Is there one?
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
const RetainSummary *Summ = Summaries.getMethodSummary(MD); const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
RE = Summ->getRetEffect(); RE = Summ->getRetEffect();
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
if (!isa<CXXMethodDecl>(FD)) { if (!isa<CXXMethodDecl>(FD)) {
const RetainSummary *Summ = Summaries.getFunctionSummary(FD); const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
RE = Summ->getRetEffect(); RE = Summ->getRetEffect();
} }
} }
@ -1324,7 +1324,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
return; return;
ProgramStateRef state = Ctx.getState(); ProgramStateRef state = Ctx.getState();
const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD); const RetainSummary *FunctionSummary = SmrMgr.getSummary(AnyCall(FD));
ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects(); ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) { for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) {