[analyzer] Port RetainSummaryManager to the new AnyCall interface, decouple ARCMT from the analyzer

rdar://19694750

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

llvm-svn: 352149
This commit is contained in:
George Karpenkov 2019-01-25 01:24:04 +00:00
parent 7faa1de17d
commit 6fdd2bd503
9 changed files with 127 additions and 112 deletions

View File

@ -12,25 +12,21 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYZER_CORE_RETAINSUMMARYMANAGER
#define LLVM_CLANG_ANALYZER_CORE_RETAINSUMMARYMANAGER
#ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H
#define LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/AnyCall.h"
#include "clang/Analysis/SelectorExtras.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/STLExtras.h"
//===----------------------------------------------------------------------===//
// Adapters for FoldingSet.
//===----------------------------------------------------------------------===//
using namespace clang;
using namespace ento;
namespace clang {
namespace ento {
@ -262,9 +258,13 @@ public:
} // end namespace ento
} // end namespace clang
using namespace ento;
namespace llvm {
//===----------------------------------------------------------------------===//
// Adapters for FoldingSet.
//===----------------------------------------------------------------------===//
template <> struct FoldingSetTrait<ArgEffect> {
static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
ID.AddInteger((unsigned) X.getKind());
@ -653,18 +653,14 @@ class RetainSummaryManager {
RetainSummaryTemplate &Template);
public:
RetainSummaryManager(ASTContext &ctx,
bool usesARC,
bool trackObjCAndCFObjects,
RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects,
bool trackOSObjects)
: Ctx(ctx),
ARCEnabled(usesARC),
: Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount),
TrackObjCAndCFObjects(trackObjCAndCFObjects),
TrackOSObjects(trackOSObjects),
AF(BPAlloc),
ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC)
TrackOSObjects(trackOSObjects), AF(BPAlloc),
ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
: RetEffect::MakeOwned(ObjKind::ObjC)),
ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(ObjKind::ObjC)
ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
: RetEffect::MakeOwnedWhenTrackedReceiver()) {
InitializeClassMethodSummaries();
InitializeMethodSummaries();
@ -693,43 +689,29 @@ public:
bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
const RetainSummary *getSummary(const CallEvent &Call,
const RetainSummary *getSummary(AnyCall C,
bool HasNonZeroCallbackArg,
bool IsReceiverUnconsumedSelf,
QualType ReceiverType=QualType());
/// getMethodSummary - This version of getMethodSummary is used to query
/// the summary for the current method being analyzed.
const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD);
const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
private:
const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
QualType RetTy,
ObjCMethodSummariesTy &CachedSummaries);
const RetainSummary *
getInstanceMethodSummary(const ObjCMethodCall &M,
QualType ReceiverType);
getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType);
const RetainSummary *getClassMethodSummary(const ObjCMethodCall &M) {
assert(!M.isInstanceMessage());
const ObjCInterfaceDecl *Class = M.getReceiverInterface();
return getMethodSummary(M.getSelector(), Class, M.getDecl(),
M.getResultType(), ObjCClassMethodSummaries);
}
/// getMethodSummary - This version of getMethodSummary is used to query
/// the summary for the current method being analyzed.
const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
const ObjCInterfaceDecl *ID = MD->getClassInterface();
Selector S = MD->getSelector();
QualType ResultTy = MD->getReturnType();
ObjCMethodSummariesTy *CachedSummaries;
if (MD->isInstanceMethod())
CachedSummaries = &ObjCMethodSummaries;
else
CachedSummaries = &ObjCClassMethodSummaries;
return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
}
const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME);
const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy);
@ -744,13 +726,10 @@ public:
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD);
void updateSummaryForCall(const RetainSummary *&Summ,
const CallEvent &Call);
bool isARCEnabled() const { return ARCEnabled; }
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
AnyCall C,
bool HasNonZeroCallbackArg,
bool IsReceiverUnconsumedSelf);
/// Determine whether a declaration {@code D} of correspondent type (return
/// type for functions/methods) {@code QT} has any of the given attributes,

View File

@ -34,6 +34,4 @@ add_clang_library(clangARCMigrate
clangRewrite
clangSema
clangSerialization
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
)

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Transforms.h"
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/ARCMigrate/ARCMT.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/AST/ASTConsumer.h"
@ -26,7 +27,6 @@
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Path.h"

View File

@ -21,6 +21,7 @@ add_clang_library(clangAnalysis
PostOrderCFGView.cpp
ProgramPoint.cpp
ReachableCode.cpp
RetainSummaryManager.cpp
ThreadSafety.cpp
ThreadSafetyCommon.cpp
ThreadSafetyLogical.cpp

View File

@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@ -558,8 +558,11 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
}
void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
const CallEvent &Call) {
if (Call.hasNonZeroCallbackArg()) {
AnyCall C,
bool HasNonZeroCallbackArg,
bool IsReceiverUnconsumedSelf) {
if (HasNonZeroCallbackArg) {
ArgEffect RecEffect =
getStopTrackingHardEquivalent(S->getReceiverEffect());
ArgEffect DefEffect =
@ -580,8 +583,8 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
// Special cases where the callback argument CANNOT free the return value.
// This can generally only happen if we know that the callback will only be
// called when the return value is already being deallocated.
if (const SimpleFunctionCall *FC = dyn_cast<SimpleFunctionCall>(&Call)) {
if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
if (C.getKind() == AnyCall::Function) {
if (const IdentifierInfo *Name = C.getIdentifier()) {
// When the CGBitmapContext is deallocated, the callback here will free
// the associated data buffer.
// The callback in dispatch_data_create frees the buffer, but not
@ -607,50 +610,42 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
// Note, we don't want to just stop tracking the value since we want the
// RetainCount checker to report leaks and use-after-free if SelfInit checker
// is turned off.
if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) {
if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) {
// Check if the message is not consumed, we know it will not be used in
// an assignment, ex: "self = [super init]".
const Expr *ME = MC->getOriginExpr();
const LocationContext *LCtx = MC->getLocationContext();
ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap();
if (!PM.isConsumedExpr(ME)) {
if (IsReceiverUnconsumedSelf) {
RetainSummaryTemplate ModifiableSummaryTemplate(S, *this);
ModifiableSummaryTemplate->setReceiverEffect(ArgEffect(DoNothing));
ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet());
}
}
}
}
const RetainSummary *
RetainSummaryManager::getSummary(const CallEvent &Call,
RetainSummaryManager::getSummary(AnyCall C,
bool HasNonZeroCallbackArg,
bool IsReceiverUnconsumedSelf,
QualType ReceiverType) {
const RetainSummary *Summ;
switch (Call.getKind()) {
case CE_Function:
case CE_CXXMember:
case CE_CXXMemberOperator:
case CE_CXXConstructor:
case CE_CXXAllocator:
Summ = getFunctionSummary(cast_or_null<FunctionDecl>(Call.getDecl()));
switch (C.getKind()) {
case AnyCall::Function:
case AnyCall::Constructor:
case AnyCall::Allocator:
case AnyCall::Deallocator:
Summ = getFunctionSummary(cast_or_null<FunctionDecl>(C.getDecl()));
break;
case CE_Block:
case CE_CXXDestructor:
case AnyCall::Block:
case AnyCall::Destructor:
// FIXME: These calls are currently unsupported.
return getPersistentStopSummary();
case CE_ObjCMessage: {
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
if (Msg.isInstanceMessage())
Summ = getInstanceMethodSummary(Msg, ReceiverType);
case AnyCall::ObjCMethod: {
const auto *ME = cast<ObjCMessageExpr>(C.getExpr());
if (ME->isInstanceMessage())
Summ = getInstanceMethodSummary(ME, ReceiverType);
else
Summ = getClassMethodSummary(Msg);
Summ = getClassMethodSummary(ME);
break;
}
}
updateSummaryForCall(Summ, Call);
updateSummaryForCall(Summ, C, HasNonZeroCallbackArg,
IsReceiverUnconsumedSelf);
assert(Summ && "Unknown call type?");
return Summ;
@ -1067,8 +1062,17 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
ArgEffect(ReceiverEff), ArgEffect(MayEscape));
}
const RetainSummary *
RetainSummaryManager::getClassMethodSummary(const ObjCMessageExpr *ME) {
assert(!ME->isInstanceMessage());
const ObjCInterfaceDecl *Class = ME->getReceiverInterface();
return getMethodSummary(ME->getSelector(), Class, ME->getMethodDecl(),
ME->getType(), ObjCClassMethodSummaries);
}
const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
const ObjCMethodCall &Msg,
const ObjCMessageExpr *ME,
QualType ReceiverType) {
const ObjCInterfaceDecl *ReceiverClass = nullptr;
@ -1080,18 +1084,18 @@ const RetainSummary *RetainSummaryManager::getInstanceMethodSummary(
// If we don't know what kind of object this is, fall back to its static type.
if (!ReceiverClass)
ReceiverClass = Msg.getReceiverInterface();
ReceiverClass = ME->getReceiverInterface();
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
// id x = [NSObject class];
// [x performSelector:... withObject:... afterDelay:...];
Selector S = Msg.getSelector();
const ObjCMethodDecl *Method = Msg.getDecl();
Selector S = ME->getSelector();
const ObjCMethodDecl *Method = ME->getMethodDecl();
if (!Method && ReceiverClass)
Method = ReceiverClass->getInstanceMethod(S);
return getMethodSummary(S, ReceiverClass, Method, Msg.getResultType(),
return getMethodSummary(S, ReceiverClass, Method, ME->getType(),
ObjCMethodSummaries);
}
@ -1220,10 +1224,24 @@ void RetainSummaryManager::InitializeMethodSummaries() {
addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize", "info");
}
const RetainSummary *
RetainSummaryManager::getMethodSummary(const ObjCMethodDecl *MD) {
const ObjCInterfaceDecl *ID = MD->getClassInterface();
Selector S = MD->getSelector();
QualType ResultTy = MD->getReturnType();
ObjCMethodSummariesTy *CachedSummaries;
if (MD->isInstanceMethod())
CachedSummaries = &ObjCMethodSummaries;
else
CachedSummaries = &ObjCClassMethodSummaries;
return getMethodSummary(S, ID, MD, ResultTy, *CachedSummaries);
}
CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
ASTContext &Ctx = MD->getASTContext();
LangOptions L = Ctx.getLangOpts();
RetainSummaryManager M(Ctx, L.ObjCAutoRefCount,
RetainSummaryManager M(Ctx,
/*TrackNSAndCFObjects=*/true,
/*TrackOSObjects=*/false);
const RetainSummary *S = M.getMethodSummary(MD);
@ -1237,8 +1255,7 @@ CallEffects CallEffects::getEffect(const ObjCMethodDecl *MD) {
CallEffects CallEffects::getEffect(const FunctionDecl *FD) {
ASTContext &Ctx = FD->getASTContext();
LangOptions L = Ctx.getLangOpts();
RetainSummaryManager M(Ctx, L.ObjCAutoRefCount,
RetainSummaryManager M(Ctx,
/*TrackNSAndCFObjects=*/true,
/*TrackOSObjects=*/false);
const RetainSummary *S = M.getFunctionSummary(FD);

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "RetainCountChecker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
using namespace clang;
using namespace ento;
@ -326,6 +327,31 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
C.addTransition(State);
}
static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
// Check if the message is not consumed, we know it will not be used in
// an assignment, ex: "self = [super init]".
return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
!Call.getLocationContext()
->getAnalysisDeclContext()
->getParentMap()
.isConsumedExpr(Call.getOriginExpr());
}
return false;
}
const static RetainSummary *getSummary(RetainSummaryManager &Summaries,
const CallEvent &Call,
QualType ReceiverType) {
const Expr *CE = Call.getOriginExpr();
AnyCall C =
CE ? *AnyCall::forExpr(CE)
: AnyCall::forDestructorCall(cast<CXXDestructorDecl>(Call.getDecl()));
return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
isReceiverUnconsumedSelf(Call), ReceiverType);
}
void RetainCountChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
RetainSummaryManager &Summaries = getSummaryManager(C);
@ -341,7 +367,7 @@ void RetainCountChecker::checkPostCall(const CallEvent &Call,
}
}
const RetainSummary *Summ = Summaries.getSummary(Call, ReceiverType);
const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
if (C.wasInlined) {
processSummaryOfInlined(*Summ, Call, C);

View File

@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/SelectorExtras.h"
@ -32,7 +33,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
@ -275,15 +275,9 @@ public:
RetainCountChecker() {};
RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
// FIXME: We don't support ARC being turned on and off during one analysis.
// (nor, for that matter, do we support changing ASTContexts)
bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount;
if (!Summaries) {
Summaries.reset(new RetainSummaryManager(
Ctx, ARCEnabled, TrackObjCAndCFObjects, TrackOSObjects));
} else {
assert(Summaries->isARCEnabled() == ARCEnabled);
}
if (!Summaries)
Summaries.reset(
new RetainSummaryManager(Ctx, TrackObjCAndCFObjects, TrackOSObjects));
return *Summaries;
}

View File

@ -14,10 +14,11 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
namespace clang {
namespace ento {

View File

@ -43,7 +43,6 @@ add_clang_library(clangStaticAnalyzerCore
RangeConstraintManager.cpp
RangedConstraintManager.cpp
RegionStore.cpp
RetainSummaryManager.cpp
SarifDiagnostics.cpp
SimpleConstraintManager.cpp
SimpleSValBuilder.cpp