[analyzer] Refactor checkers to use helper function for getting callee Decl and name.

We are getting name of the called function or it's declaration in a few checkers. Refactor them to use the helper function in the CheckerContext. 

llvm-svn: 145576
This commit is contained in:
Anna Zaks 2011-12-01 05:57:37 +00:00
parent 24fc93a940
commit c6aa531a8f
14 changed files with 52 additions and 111 deletions

View File

@ -142,6 +142,9 @@ public:
Eng.getBugReporter().EmitReport(R);
}
/// \brief Get the declaration of the called function (path-sensitive).
const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
/// \brief Get the name of the called function (path-sensitive).
StringRef getCalleeName(const CallExpr *CE) const;

View File

@ -249,11 +249,8 @@ static const char* GetCFNumberTypeStr(uint64_t i) {
void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
const Expr *Callee = CE->getCallee();
const ProgramState *state = C.getState();
SVal CallV = state->getSVal(Callee);
const FunctionDecl *FD = CallV.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@ -363,11 +360,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
if (CE->getNumArgs() != 1)
return;
// Get the function declaration of the callee.
const ProgramState *state = C.getState();
SVal X = state->getSVal(CE->getCallee());
const FunctionDecl *FD = X.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;

View File

@ -30,12 +30,9 @@ public:
}
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
CheckerContext &C) const{
CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;

View File

@ -1664,20 +1664,9 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
//===----------------------------------------------------------------------===//
bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
if (!FD)
StringRef Name = C.getCalleeName(CE);
if (Name.empty())
return false;
// Get the name of the callee. If it's a builtin, strip off the prefix.
IdentifierInfo *II = FD->getIdentifier();
if (!II) // if no identifier, not a simple C function
return false;
StringRef Name = II->getName();
if (Name.startswith("__builtin_"))
Name = Name.substr(10);

View File

@ -62,10 +62,7 @@ private:
} // end anonymous namespace
bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;
@ -125,10 +122,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
// Check the jail state before any function call except chroot and chdir().
void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@ -143,7 +137,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
return;
// If jail state is ROOT_CHANGED, generate BugReport.
void *const* k = state->FindGDM(ChrootChecker::getTag());
void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
if (k)
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.addTransition()) {

View File

@ -281,18 +281,12 @@ void MacOSKeychainAPIChecker::
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *State = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = State->getSVal(Callee);
unsigned idx = InvalidIdx;
const ProgramState *State = C.getState();
const FunctionDecl *funDecl = L.getAsFunctionDecl();
if (!funDecl)
StringRef funName = C.getCalleeName(CE);
if (funName.empty())
return;
IdentifierInfo *funI = funDecl->getIdentifier();
if (!funI)
return;
StringRef funName = funI->getName();
// If it is a call to an allocator function, it could be a double allocation.
idx = getTrackedFunctionIndex(funName, true);

View File

@ -37,11 +37,11 @@ public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
const IdentifierInfo *FI) const;
StringRef FName) const;
typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
const CallExpr *,
const IdentifierInfo *) const;
StringRef FName) const;
};
} //end anonymous namespace
@ -50,7 +50,7 @@ public:
//===----------------------------------------------------------------------===//
void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
const IdentifierInfo *FI) const {
StringRef FName) const {
if (CE->getNumArgs() < 1)
return;
@ -71,7 +71,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
llvm::SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << FI->getName() << "' uses";
os << "Call to '" << FName << "' uses";
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
os << " the local variable '" << VR->getDecl()->getName() << '\'';
else
@ -92,27 +92,18 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const {
// FIXME: This sort of logic is common to several checkers, including
// UnixAPIChecker, PthreadLockChecker, and CStringChecker. Should refactor.
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
if (!Fn)
return;
const IdentifierInfo *FI = Fn->getIdentifier();
if (!FI)
StringRef Name = C.getCalleeName(CE);
if (Name.empty())
return;
SubChecker SC =
llvm::StringSwitch<SubChecker>(FI->getName())
llvm::StringSwitch<SubChecker>(Name)
.Cases("dispatch_once", "dispatch_once_f",
&MacOSXAPIChecker::CheckDispatchOnce)
.Default(NULL);
if (SC)
(this->*SC)(C, CE, FI);
(this->*SC)(C, CE, Name);
}
//===----------------------------------------------------------------------===//

View File

@ -128,11 +128,7 @@ namespace ento {
}
bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;

View File

@ -35,24 +35,27 @@ private:
};
}
static StringRef getCalleeName(const ProgramState *State,
const CallExpr *CE) {
const Expr *Callee = CE->getCallee();
SVal L = State->getSVal(Callee);
const FunctionDecl *funDecl = L.getAsFunctionDecl();
if (!funDecl)
return StringRef();
IdentifierInfo *funI = funDecl->getIdentifier();
if (!funI)
return StringRef();
return funI->getName();
}
bool OSAtomicChecker::inlineCall(const CallExpr *CE,
ExprEngine &Eng,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) const {
const ProgramState *state = Pred->getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
if (!FD)
StringRef FName = getCalleeName(Pred->getState(), CE);
if (FName.empty())
return false;
const IdentifierInfo *II = FD->getIdentifier();
if (!II)
return false;
StringRef FName(II->getName());
// Check for compare and swap.
if (FName.startswith("OSAtomicCompareAndSwap") ||
FName.startswith("objc_atomicCompareAndSwap"))

View File

@ -57,18 +57,10 @@ template <> struct ProgramStateTrait<LockSet> :
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
if (!FD)
StringRef FName = C.getCalleeName(CE);
if (FName.empty())
return;
// Get the name of the callee.
IdentifierInfo *II = FD->getIdentifier();
if (!II) // if no identifier, not a simple C function
return;
StringRef FName = II->getName();
if (CE->getNumArgs() != 1)
return;

View File

@ -2990,10 +2990,7 @@ void RetainCountChecker::processNonLeakError(const ProgramState *St,
bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. We're only interested in simple C functions.
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;
@ -3015,7 +3012,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// See if it's one of the specific functions we know how to eval.
bool canEval = false;
QualType ResultTy = FD->getResultType();
QualType ResultTy = CE->getCallReturnType();
if (ResultTy->isObjCIdType()) {
// Handle: id NSMakeCollectable(CFTypeRef)
canEval = II->isStr("NSMakeCollectable");

View File

@ -115,10 +115,7 @@ namespace ento {
}
bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
SVal L = state->getSVal(Callee);
const FunctionDecl *FD = L.getAsFunctionDecl();
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return false;

View File

@ -224,21 +224,12 @@ void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
//===----------------------------------------------------------------------===//
void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Get the callee. All the functions we care about are C functions
// with simple identifiers.
const ProgramState *state = C.getState();
const Expr *Callee = CE->getCallee();
const FunctionDecl *Fn = state->getSVal(Callee).getAsFunctionDecl();
if (!Fn)
return;
const IdentifierInfo *FI = Fn->getIdentifier();
if (!FI)
StringRef FName = C.getCalleeName(CE);
if (FName.empty())
return;
SubChecker SC =
llvm::StringSwitch<SubChecker>(FI->getName())
llvm::StringSwitch<SubChecker>(FName)
.Case("open", &UnixAPIChecker::CheckOpen)
.Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)

View File

@ -16,12 +16,15 @@
using namespace clang;
using namespace ento;
StringRef CheckerContext::getCalleeName(const CallExpr *CE) const {
const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
const ProgramState *State = getState();
const Expr *Callee = CE->getCallee();
SVal L = State->getSVal(Callee);
return L.getAsFunctionDecl();
}
const FunctionDecl *funDecl = L.getAsFunctionDecl();
StringRef CheckerContext::getCalleeName(const CallExpr *CE) const {
const FunctionDecl *funDecl = getCalleeDecl(CE);
if (!funDecl)
return StringRef();
IdentifierInfo *funI = funDecl->getIdentifier();