[analyzer] Add some convenience accessors to CallEvent, and use them.

These are CallEvent-equivalents of helpers already accessible in
CheckerContext, as part of making it easier for new checkers to be written
using CallEvent rather than raw CallExprs.

llvm-svn: 167338
This commit is contained in:
Jordan Rose 2012-11-02 23:49:29 +00:00
parent 0da6747901
commit 829c383114
7 changed files with 81 additions and 15 deletions

View File

@ -249,6 +249,12 @@ public:
/// \brief Returns the result type, adjusted for references.
QualType getResultType() const;
/// \brief Returns the return value of the call.
///
/// This should only be called if the CallEvent was created using a state in
/// which the return value has already been bound to the origin expression.
SVal getReturnValue() const;
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
@ -261,6 +267,38 @@ public:
return hasNonZeroCallbackArg();
}
/// \brief Returns true if the callee is an externally-visible function in the
/// top-level namespace, such as \c malloc.
///
/// You can use this call to determine that a particular function really is
/// a library function and not, say, a C++ member function with the same name.
///
/// If a name is provided, the function must additionally match the given
/// name.
///
/// Note that this deliberately excludes C++ library functions in the \c std
/// namespace, but will include C library functions accessed through the
/// \c std namespace. This also does not check if the function is declared
/// as 'extern "C"', or if it uses C++ name mangling.
// FIXME: Add a helper for checking namespaces.
// FIXME: Move this down to AnyFunctionCall once checkers have more
// precise callbacks.
bool isGlobalCFunction(StringRef SpecificName = StringRef()) const;
/// \brief Returns the name of the callee, if its name is a simple identifier.
///
/// Note that this will fail for Objective-C methods, blocks, and C++
/// overloaded operators. The former is named by a Selector rather than a
/// simple identifier, and the latter two do not have names.
// FIXME: Move this down to AnyFunctionCall once checkers have more
// precise callbacks.
const IdentifierInfo *getCalleeIdentifier() const {
const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDecl());
if (!ND)
return 0;
return ND->getIdentifier();
}
/// \brief Returns an appropriate ProgramPoint for this call.
ProgramPoint getProgramPoint(bool IsPreVisit = false,
const ProgramPointTag *Tag = 0) const;

View File

@ -212,9 +212,18 @@ public:
return getCalleeName(FunDecl);
}
/// \brief Returns true if the given function is the specified built-in or
/// system library C function.
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name);
/// \brief Returns true if the callee is an externally-visible function in the
/// top-level namespace, such as \c malloc.
///
/// If a name is provided, the function must additionally match the given
/// name.
///
/// Note that this deliberately excludes C++ library functions in the \c std
/// namespace, but will include C library functions accessed through the
/// \c std namespace. This also does not check if the function is declared
/// as 'extern "C"', or if it uses C++ name mangling.
static bool isCLibraryFunction(const FunctionDecl *FD,
StringRef Name = StringRef());
/// \brief Depending on wither the location corresponds to a macro, return
/// either the macro name or the token spelling.

View File

@ -105,8 +105,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
// Get the returned value if it's a region.
SVal Result = C.getSVal(Call.getOriginExpr());
const MemRegion *RetReg = Result.getAsRegion();
const MemRegion *RetReg = Call.getReturnValue().getAsRegion();
if (!RetReg)
return;

View File

@ -291,13 +291,12 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
// returns 'self'. So assign the flags, which were set on 'self' to the
// return value.
// EX: self = performMoreInitialization(self)
const Expr *CallExpr = CE.getOriginExpr();
if (CallExpr)
addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()),
prevFlags, C);
addSelfFlag(state, CE.getReturnValue(), prevFlags, C);
return;
}
}
C.addTransition(state);
}
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,

View File

@ -2783,8 +2783,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
// Consult the summary for the return value.
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::NoRetHard) {
SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
C.getLocationContext()).getAsSymbol();
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (Sym)
state = removeRefBinding(state, Sym);
}
@ -2863,8 +2862,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::OwnedAllocatedSymbol:
case RetEffect::OwnedSymbol: {
SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
C.getLocationContext()).getAsSymbol();
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
@ -2883,7 +2881,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (!Sym)
break;
assert(Ex);

View File

@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallSet.h"
@ -99,6 +100,14 @@ bool CallEvent::hasNonZeroCallbackArg() const {
return false;
}
bool CallEvent::isGlobalCFunction(StringRef FunctionName) const {
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
if (!FD)
return false;
return CheckerContext::isCLibraryFunction(FD, FunctionName);
}
/// \brief Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {
@ -223,6 +232,13 @@ SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
return ArgE->getSourceRange();
}
SVal CallEvent::getReturnValue() const {
const Expr *E = getOriginExpr();
if (!E)
return UndefinedVal();
return getSVal(E);
}
void CallEvent::dump() const {
dump(llvm::errs());
}

View File

@ -43,6 +43,8 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
// Using a string compare is slow, we might want to switch on BuiltinID here.
unsigned BId = FD->getBuiltinID();
if (BId != 0) {
if (Name.empty())
return true;
StringRef BName = FD->getASTContext().BuiltinInfo.GetName(BId);
if (BName.find(Name) != StringRef::npos)
return true;
@ -64,9 +66,14 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
return false;
// If this function is not externally visible, it is not a C library function.
if (FD->getLinkage() != ExternalLinkage)
// Note that we make an exception for inline functions, which may be
// declared in header files without external linkage.
if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage)
return false;
if (Name.empty())
return true;
StringRef FName = II->getName();
if (FName.equals(Name))
return true;