[analyzer] Start moving the path-sensitive checkers to CheckerV2.
-Migrate ObjCSelfInitChecker to CheckerV2. In the process remove the 'preCallSelfFlags' field
from the checker class and use GRState for storing that info.
-Get ExprEngine to start delegating checker running to CheckerManager.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126229 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index ab8d564..c072d19 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -92,12 +92,13 @@
}
if (CO->empty()) {
- // If there are no checkers, return early without doing any
- // more work.
- Dst.insert(Src);
+ // If there are no checkers, just delegate to the checker manager.
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, Src, S, *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
unsigned checkersEvaluated = 0;
@@ -108,7 +109,7 @@
break;
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -144,6 +145,9 @@
// Don't autotransition. The CheckerContext objects should do this
// automatically.
+
+ getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback,
+ Dst, CheckersV1Dst, S, *this);
}
void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
@@ -152,10 +156,12 @@
bool isPrevisit) {
if (Checkers.empty()) {
- Dst.insert(Src);
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg,
+ *this);
return;
}
+ ExplodedNodeSet CheckersV1Dst;
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
@@ -163,7 +169,7 @@
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -181,8 +187,8 @@
PrevSet = CurrSet;
}
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
+ getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst,
+ msg, *this);
}
void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
@@ -1923,20 +1929,28 @@
const GRState* state, SVal location,
const void *tag, bool isLoad) {
// Early checks for performance reason.
- if (location.isUnknown() || Checkers.empty()) {
+ if (location.isUnknown()) {
Dst.Add(Pred);
return;
}
- ExplodedNodeSet Src, Tmp;
+ ExplodedNodeSet Src;
Src.Add(Pred);
+ if (Checkers.empty()) {
+ getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S,
+ state, *this);
+ return;
+ }
+
+ ExplodedNodeSet CheckersV1Dst;
+ ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = 0;
if (I+1 == E)
- CurrSet = &Dst;
+ CurrSet = &CheckersV1Dst;
else {
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
@@ -1957,6 +1971,9 @@
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
+
+ getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location,
+ isLoad, S, state, *this);
}
bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 4f247ea..5f32bb8 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -47,8 +47,9 @@
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/CheckerV2.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
@@ -63,45 +64,23 @@
static bool isSelfVar(SVal location, CheckerContext &C);
namespace {
-enum SelfFlagEnum {
- /// \brief No flag set.
- SelfFlag_None = 0x0,
- /// \brief Value came from 'self'.
- SelfFlag_Self = 0x1,
- /// \brief Value came from the result of an initializer (e.g. [super init]).
- SelfFlag_InitRes = 0x2
-};
-}
-
-namespace {
-class ObjCSelfInitChecker : public CheckerVisitor<ObjCSelfInitChecker> {
- /// \brief A call receiving a reference to 'self' invalidates the object that
- /// 'self' contains. This field keeps the "self flags" assigned to the 'self'
- /// object before the call and assign them to the new object that 'self'
- /// points to after the call.
- SelfFlagEnum preCallSelfFlags;
-
+class ObjCSelfInitChecker : public CheckerV2<
+ check::PostObjCMessage,
+ check::PostStmt<ObjCIvarRefExpr>,
+ check::PreStmt<ReturnStmt>,
+ check::PreStmt<CallExpr>,
+ check::PostStmt<CallExpr>,
+ check::Location > {
public:
- static void *getTag() { static int tag = 0; return &tag; }
- void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
- void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE);
- virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location,
- bool isLoad);
+ void checkPostObjCMessage(ObjCMessage msg, CheckerContext &C) const;
+ void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
+ void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+ void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkLocation(SVal location, bool isLoad, CheckerContext &C) const;
};
} // end anonymous namespace
-static void RegisterObjCSelfInitChecker(ExprEngine &Eng) {
- if (Eng.getContext().getLangOptions().ObjC1)
- Eng.registerCheck(new ObjCSelfInitChecker());
-}
-
-void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
- mgr.addCheckerRegisterFunction(RegisterObjCSelfInitChecker);
-}
-
namespace {
class InitSelfBug : public BugType {
@@ -113,22 +92,40 @@
} // end anonymous namespace
+namespace {
+enum SelfFlagEnum {
+ /// \brief No flag set.
+ SelfFlag_None = 0x0,
+ /// \brief Value came from 'self'.
+ SelfFlag_Self = 0x1,
+ /// \brief Value came from the result of an initializer (e.g. [super init]).
+ SelfFlag_InitRes = 0x2
+};
+}
+
typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag;
namespace { struct CalledInit {}; }
+namespace { struct PreCallSelfFlags {}; }
namespace clang {
namespace ento {
template<>
struct GRStateTrait<SelfFlag> : public GRStatePartialTrait<SelfFlag> {
- static void* GDMIndex() {
- static int index = 0;
- return &index;
- }
+ static void* GDMIndex() { static int index = 0; return &index; }
};
template <>
struct GRStateTrait<CalledInit> : public GRStatePartialTrait<bool> {
static void *GDMIndex() { static int index = 0; return &index; }
};
+
+ /// \brief A call receiving a reference to 'self' invalidates the object that
+ /// 'self' contains. This keeps the "self flags" assigned to the 'self'
+ /// object before the call so we can assign them to the new object that 'self'
+ /// points to after the call.
+ template <>
+ struct GRStateTrait<PreCallSelfFlags> : public GRStatePartialTrait<unsigned> {
+ static void *GDMIndex() { static int index = 0; return &index; }
+ };
}
}
@@ -188,8 +185,8 @@
C.EmitReport(report);
}
-void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
- ObjCMessage msg) {
+void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
+ CheckerContext &C) const {
// When encountering a message that does initialization (init rule),
// tag the return value so that we know later on that if self has this value
// then it is properly initialized.
@@ -219,8 +216,8 @@
// fails.
}
-void ObjCSelfInitChecker::PostVisitObjCIvarRefExpr(CheckerContext &C,
- const ObjCIvarRefExpr *E) {
+void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -231,8 +228,8 @@
"'[(super or self) init...]'");
}
-void ObjCSelfInitChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *S) {
+void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
+ CheckerContext &C) const {
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisContext()->getDecl())))
@@ -259,40 +256,46 @@
// Until we can use inter-procedural analysis, in such a call, transfer the
// SelfFlags to the result of the call.
-void ObjCSelfInitChecker::PreVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- preCallSelfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- preCallSelfFlags = getSelfFlags(argV, C);
+ unsigned selfFlags = getSelfFlags(argV, C);
+ C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
}
}
}
-void ObjCSelfInitChecker::PostVisitGenericCall(CheckerContext &C,
- const CallExpr *CE) {
+void ObjCSelfInitChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
const GRState *state = C.getState();
for (CallExpr::const_arg_iterator
I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) {
SVal argV = state->getSVal(*I);
if (isSelfVar(argV, C)) {
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
- addSelfFlag(state, state->getSVal(CE), preCallSelfFlags, C);
+ SelfFlagEnum prevFlags = (SelfFlagEnum)state->get<PreCallSelfFlags>();
+ state = state->remove<PreCallSelfFlags>();
+ addSelfFlag(state, state->getSVal(CE), prevFlags, C);
return;
}
}
}
-void ObjCSelfInitChecker::visitLocation(CheckerContext &C, const Stmt *S,
- SVal location, bool isLoad) {
+void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
+ CheckerContext &C) const {
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
const GRState *state = C.getState();
@@ -354,3 +357,11 @@
static bool isInitMessage(const ObjCMessage &msg) {
return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
}
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerObjCSelfInitChecker(CheckerManager &mgr) {
+ mgr.registerChecker<ObjCSelfInitChecker>();
+}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 1989b82..92e97e1 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -13,11 +13,17 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/DeclBase.h"
using namespace clang;
using namespace ento;
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for AST traversing..
+//===----------------------------------------------------------------------===//
+
void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
assert(D);
@@ -33,39 +39,162 @@
for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
DeclCheckerInfo &info = DeclCheckers[i];
if (info.IsForDeclFn(D))
- checkers->push_back(std::make_pair(info.Checker, info.CheckFn));
+ checkers->push_back(info.CheckFn);
}
}
assert(checkers);
for (CachedDeclCheckers::iterator
- I = checkers->begin(), E = checkers->end(); I != E; ++I) {
- CheckerRef checker = I->first;
- CheckDeclFunc fn = I->second;
- fn(checker, D, mgr, BR);
- }
+ I = checkers->begin(), E = checkers->end(); I != E; ++I)
+ (*I)(D, mgr, BR);
}
void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
assert(D && D->hasBody());
- for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) {
- CheckerRef checker = BodyCheckers[i].first;
- CheckDeclFunc fn = BodyCheckers[i].second;
- fn(checker, D, mgr, BR);
+ for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i)
+ BodyCheckers[i](D, mgr, BR);
+}
+
+//===----------------------------------------------------------------------===//
+// Functions for running checkers for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+template <typename CHECK_CTX>
+static void runPathSensitiveCheckers(CHECK_CTX checkCtx,
+ ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src) {
+
+ if (checkCtx.Checkers.empty()) {
+ Dst.insert(Src);
+ return;
+ }
+
+ ExplodedNodeSet Tmp;
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (typename CHECK_CTX::CheckersTy::const_iterator
+ I= checkCtx.Checkers.begin(), E= checkCtx.Checkers.end(); I!=E; ++I) {
+ ExplodedNodeSet *CurrSet = 0;
+ if (I+1 == E)
+ CurrSet = &Dst;
+ else {
+ CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+ CurrSet->clear();
+ }
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checkCtx.runChecker(*I, *CurrSet, *NI);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
}
}
-void CheckerManager::_registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
- HandlesDeclFunc isForDeclFn) {
- DeclCheckerInfo info = { checker, checkfn, isForDeclFn };
- DeclCheckers.push_back(info);
+namespace {
+ struct CheckStmtContext {
+ typedef llvm::SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
+ bool IsPreVisit;
+ const CheckersTy &Checkers;
+ const Stmt *S;
+ ExprEngine &Eng;
+
+ CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
+ const Stmt *s, ExprEngine &eng)
+ : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckStmtFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ // FIXME: Remove respondsToCallback from CheckerContext;
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0, S);
+ checkFn(S, C);
+ }
+ };
}
-void CheckerManager::_registerForBody(CheckerRef checker,
- CheckDeclFunc checkfn) {
- BodyCheckers.push_back(std::make_pair(checker, checkfn));
+/// \brief Run checkers for visiting Stmts.
+void CheckerManager::runCheckersForStmt(bool isPreVisit,
+ ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ const Stmt *S,
+ ExprEngine &Eng) {
+ CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
+ S, Eng);
+ runPathSensitiveCheckers(C, Dst, Src);
+}
+
+namespace {
+ struct CheckObjCMessageContext {
+ typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
+ bool IsPreVisit;
+ const CheckersTy &Checkers;
+ const ObjCMessage &Msg;
+ ExprEngine &Eng;
+
+ CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
+ const ObjCMessage &msg, ExprEngine &eng)
+ : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsPreVisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0,
+ Msg.getOriginExpr());
+ checkFn(Msg, C);
+ }
+ };
+}
+
+/// \brief Run checkers for visiting obj-c messages.
+void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
+ ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ const ObjCMessage &msg,
+ ExprEngine &Eng) {
+ CheckObjCMessageContext C(isPreVisit, PostObjCMessageCheckers, msg, Eng);
+ runPathSensitiveCheckers(C, Dst, Src);
+}
+
+namespace {
+ struct CheckLocationContext {
+ typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
+ const CheckersTy &Checkers;
+ SVal Loc;
+ bool IsLoad;
+ const Stmt *S;
+ const GRState *State;
+ ExprEngine &Eng;
+
+ CheckLocationContext(const CheckersTy &checkers,
+ SVal loc, bool isLoad, const Stmt *s,
+ const GRState *state, ExprEngine &eng)
+ : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s),
+ State(state), Eng(eng) { }
+
+ void runChecker(CheckerManager::CheckLocationFunc checkFn,
+ ExplodedNodeSet &Dst, ExplodedNode *Pred) {
+ CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker,
+ IsLoad ? ProgramPoint::PreLoadKind :
+ ProgramPoint::PreStoreKind, 0, S, State);
+ checkFn(Loc, IsLoad, C);
+ }
+ };
+}
+
+/// \brief Run checkers for load/store of a location.
+void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
+ ExplodedNodeSet &Src,
+ SVal location, bool isLoad,
+ const Stmt *S,
+ const GRState *state,
+ ExprEngine &Eng) {
+ CheckLocationContext C(LocationCheckers, location, isLoad, S, state, Eng);
+ runPathSensitiveCheckers(C, Dst, Src);
}
void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
@@ -73,12 +202,76 @@
Funcs[i](eng);
}
-CheckerManager::~CheckerManager() {
- for (unsigned i = 0, e = Checkers.size(); i != e; ++i) {
- CheckerRef checker = Checkers[i].first;
- Dtor dtor = Checkers[i].second;
- dtor(checker);
+//===----------------------------------------------------------------------===//
+// Internal registration functions for AST traversing.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
+ HandlesDeclFunc isForDeclFn) {
+ DeclCheckerInfo info = { checkfn, isForDeclFn };
+ DeclCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
+ BodyCheckers.push_back(checkfn);
+}
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
+ HandlesStmtFunc isForStmtFn) {
+ StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
+ StmtCheckers.push_back(info);
+}
+void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
+ HandlesStmtFunc isForStmtFn) {
+ StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
+ StmtCheckers.push_back(info);
+}
+
+void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
+ PreObjCMessageCheckers.push_back(checkfn);
+}
+void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
+ PostObjCMessageCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
+ LocationCheckers.push_back(checkfn);
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation details.
+//===----------------------------------------------------------------------===//
+
+CheckerManager::CachedStmtCheckers *
+CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
+ assert(S);
+
+ CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
+ CachedStmtCheckers *checkers = 0;
+ CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
+ if (CCI != CachedStmtCheckersMap.end()) {
+ checkers = &(CCI->second);
+ } else {
+ // Find the checkers that should run for this Stmt and cache them.
+ checkers = &CachedStmtCheckersMap[key];
+ for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
+ StmtCheckerInfo &info = StmtCheckers[i];
+ if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
+ checkers->push_back(info.CheckFn);
+ }
}
+
+ assert(checkers);
+ return checkers;
+}
+
+CheckerManager::~CheckerManager() {
+ for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
+ CheckerDtors[i]();
}
// Anchor for the vtable.