#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/PointerIntPair.h"
namespace clang {
class ProgramPoint;
CE_END_OBJC_CALLS = CE_ObjCPropertyAccess
};
+
/// \brief Represents an abstract call to a function or method along a
/// particular path.
class CallEvent {
public:
typedef CallEventKind Kind;
+private:
+ // PointerIntPair doesn't respect IntrusiveRefCntPtr, so we have to manually
+ // retain and release the state.
+ llvm::PointerIntPair<const ProgramState *, 2> State;
+ llvm::PointerIntPair<const LocationContext *, 2> LCtx;
+ llvm::PointerUnion<const Expr *, const Decl *> Origin;
+
protected:
- ProgramStateRef State;
- const LocationContext *LCtx;
- const Kind K;
+ // This is user data for subclasses.
+ const void *Data;
+ SourceLocation Location;
+
+ CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx,
+ Kind k)
+ : State(state.getPtr(), (k & 0x3)),
+ LCtx(lctx, ((k >> 2) & 0x3)),
+ Origin(E) {
+ IntrusiveRefCntPtrInfo<const ProgramState>::retain(getState());
+ assert(k == getKind() && "More kinds than bits in the PointerIntPairs.");
+ }
+
+ CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx,
+ Kind k)
+ : State(state.getPtr(), (k & 0x3)),
+ LCtx(lctx, ((k >> 2) & 0x3)),
+ Origin(D) {
+ IntrusiveRefCntPtrInfo<const ProgramState>::retain(getState());
+ assert(k == getKind() && "More kinds than bits in the PointerIntPairs.");
+ }
+
+ const ProgramState *getState() const {
+ return State.getPointer();
+ }
+
+ const LocationContext *getLocationContext() const {
+ return LCtx.getPointer();
+ }
+
+ ~CallEvent() {
+ IntrusiveRefCntPtrInfo<const ProgramState>::release(getState());
+ }
- CallEvent(ProgramStateRef state, const LocationContext *lctx, Kind k)
- : State(state), LCtx(lctx), K(k) {}
- virtual ~CallEvent() {}
/// \brief Get the value of arbitrary expressions at this point in the path.
SVal getSVal(const Stmt *S) const {
- return State->getSVal(S, LCtx);
+ return getState()->getSVal(S, getLocationContext());
}
typedef SmallVectorImpl<const MemRegion *> RegionList;
/// \brief Used to specify non-argument regions that will be invalidated as a
/// result of this call.
- virtual void addExtraInvalidatedRegions(RegionList &Regions) const {}
+ void addExtraInvalidatedRegions(RegionList &Regions) const;
- virtual QualType getDeclaredResultType() const { return QualType(); }
+ QualType getDeclaredResultType() const;
public:
+ /// \brief Returns the kind of call this is.
+ Kind getKind() const {
+ return static_cast<Kind>((State.getInt()) | (LCtx.getInt() << 2));
+ }
+
/// \brief Returns the declaration of the function or method that will be
/// called. May be null.
- virtual const Decl *getDecl() const = 0;
+ const Decl *getDecl() const;
/// \brief Returns the definition of the function or method that will be
/// called. May be null.
/// definition that is actually invoked at runtime. Note that if we have
/// sufficient type information to devirtualize a dynamic method call,
/// we will (and \p IsDynamicDispatch will be set to \c false).
- virtual const Decl *getDefinition(bool &IsDynamicDispatch) const {
- IsDynamicDispatch = false;
- return getDecl();
- }
+ const Decl *getDefinition(bool &IsDynamicDispatch) const;
/// \brief Returns the expression whose value will be the result of this call.
/// May be null.
- virtual const Expr *getOriginExpr() const = 0;
+ const Expr *getOriginExpr() const {
+ return Origin.dyn_cast<const Expr *>();
+ }
/// \brief Returns the number of arguments (explicit and implicit).
///
/// Note that this may be greater than the number of parameters in the
/// callee's declaration, and that it may include arguments not written in
/// the source.
- virtual unsigned getNumArgs() const = 0;
+ unsigned getNumArgs() const;
/// \brief Returns true if the callee is known to be from a system header.
bool isInSystemHeader() const {
SourceLocation Loc = D->getLocation();
if (Loc.isValid()) {
const SourceManager &SM =
- State->getStateManager().getContext().getSourceManager();
+ getState()->getStateManager().getContext().getSourceManager();
return SM.isInSystemHeader(D->getLocation());
}
return false;
}
- /// \brief Returns the kind of call this is.
- Kind getKind() const { return K; }
-
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
- virtual SourceRange getSourceRange() const = 0;
+ SourceRange getSourceRange() const;
/// \brief Returns the value of a given argument at the time of the call.
- virtual SVal getArgSVal(unsigned Index) const;
+ SVal getArgSVal(unsigned Index) const;
/// \brief Returns the expression associated with a given argument.
/// May be null if this expression does not appear in the source.
- virtual const Expr *getArgExpr(unsigned Index) const {
- return 0;
- }
+ const Expr *getArgExpr(unsigned Index) const;
/// \brief Returns the source range for errors associated with this argument.
/// May be invalid if the argument is not written in the source.
// FIXME: Is it better to return an invalid range or the range of the origin
// expression?
- virtual SourceRange getArgSourceRange(unsigned Index) const;
+ SourceRange getArgSourceRange(unsigned Index) const;
/// \brief Returns the result type, adjusted for references.
QualType getResultType() const;
/// \brief Returns the value of the implicit 'this' object, or UndefinedVal if
/// this is not a C++ member function call.
- virtual SVal getCXXThisVal() const { return UndefinedVal(); }
+ SVal getCXXThisVal() const;
/// \brief Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
// NOTE: The exact semantics of this are still being defined!
// We don't really want a list of hardcoded exceptions in the long run,
// but we don't want duplicated lists of known APIs in the short term either.
- virtual bool argumentsMayEscape() const {
- return hasNonZeroCallbackArg();
- }
+ bool argumentsMayEscape() const;
/// \brief Returns an appropriate ProgramPoint for this call.
ProgramPoint getProgramPoint(bool IsPreVisit = false,
/// If the call has no accessible declaration (or definition, if
/// \p UseDefinitionParams is set), \c param_begin() will be equal to
/// \c param_end().
- virtual param_iterator param_begin(bool UseDefinitionParams = false) const = 0;
+ param_iterator param_begin(bool UseDefinitionParams = false) const;
/// \sa param_begin()
- virtual param_iterator param_end(bool UseDefinitionParams = false) const = 0;
+ param_iterator param_end(bool UseDefinitionParams = false) const;
typedef llvm::mapped_iterator<param_iterator, get_type_fun>
param_type_iterator;
}
// For debugging purposes only
- virtual void dump(raw_ostream &Out) const;
+ void dump(raw_ostream &Out) const;
LLVM_ATTRIBUTE_USED void dump() const { dump(llvm::errs()); }
static bool classof(const CallEvent *) { return true; }
};
+
/// \brief Represents a call to any sort of function that might have a
/// FunctionDecl.
class AnyFunctionCall : public CallEvent {
+ friend class CallEvent;
+
protected:
- AnyFunctionCall(ProgramStateRef St, const LocationContext *LCtx, Kind K)
- : CallEvent(St, LCtx, K) {}
+ AnyFunctionCall(const Expr *E, ProgramStateRef St,
+ const LocationContext *LCtx, Kind K)
+ : CallEvent(E, St, LCtx, K) {}
+ AnyFunctionCall(const Decl *D, ProgramStateRef St,
+ const LocationContext *LCtx, Kind K)
+ : CallEvent(D, St, LCtx, K) {}
- param_iterator param_begin(bool UseDefinitionParams = false) const;
- param_iterator param_end(bool UseDefinitionParams = false) const;
+ // Most function calls have no extra invalidated regions.
+ void addExtraInvalidatedRegions(RegionList &Regions) const {}
QualType getDeclaredResultType() const;
public:
- virtual const FunctionDecl *getDecl() const = 0;
+ // This function is overridden by subclasses, but they must return
+ // a FunctionDecl.
+ const FunctionDecl *getDecl() const {
+ return cast_or_null<FunctionDecl>(CallEvent::getDecl());
+ }
const Decl *getDefinition(bool &IsDynamicDispatch) const {
IsDynamicDispatch = false;
bool argumentsMayEscape() const;
+ SVal getArgSVal(unsigned Index) const;
+ SourceRange getArgSourceRange(unsigned Index) const;
+
+ param_iterator param_begin(bool UseDefinitionParams = false) const;
+ param_iterator param_end(bool UseDefinitionParams = false) const;
+
static bool classof(const CallEvent *CA) {
return CA->getKind() >= CE_BEG_FUNCTION_CALLS &&
CA->getKind() <= CE_END_FUNCTION_CALLS;
/// \brief Represents a call to a written as a CallExpr.
class SimpleCall : public AnyFunctionCall {
- const CallExpr *CE;
-
protected:
- SimpleCall(const CallExpr *ce, ProgramStateRef St,
+ SimpleCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx, Kind K)
- : AnyFunctionCall(St, LCtx, K), CE(ce) {
+ : AnyFunctionCall(CE, St, LCtx, K) {
}
public:
- const CallExpr *getOriginExpr() const { return CE; }
+ const CallExpr *getOriginExpr() const {
+ return cast<CallExpr>(AnyFunctionCall::getOriginExpr());
+ }
const FunctionDecl *getDecl() const;
- unsigned getNumArgs() const { return CE->getNumArgs(); }
- SourceRange getSourceRange() const { return CE->getSourceRange(); }
+ unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
+ SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
const Expr *getArgExpr(unsigned Index) const {
- return CE->getArg(Index);
+ return getOriginExpr()->getArg(Index);
}
static bool classof(const CallEvent *CA) {
const LocationContext *LCtx)
: SimpleCall(CE, St, LCtx, CE_Function) {}
+ SVal getCXXThisVal() const { return UndefinedVal(); }
+
static bool classof(const CallEvent *CA) {
return CA->getKind() == CE_Function;
}
/// \brief Represents a non-static C++ member function call, no matter how
/// it is written.
class CXXInstanceCall : public SimpleCall {
+ friend class CallEvent;
+
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
: SimpleCall(CE, St, LCtx, K) {}
public:
- SVal getCXXThisVal() const = 0;
-
const Decl *getDefinition(bool &IsDynamicDispatch) const;
static bool classof(const CallEvent *CA) {
///
/// Example: <tt>^{ /* ... */ }()</tt>
class BlockCall : public SimpleCall {
+ friend class CallEvent;
+
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
- param_iterator param_begin(bool UseDefinitionParams = false) const;
- param_iterator param_end(bool UseDefinitionParams = false) const;
-
QualType getDeclaredResultType() const;
public:
return getBlockDecl();
}
+ param_iterator param_begin(bool UseDefinitionParams = false) const;
+ param_iterator param_end(bool UseDefinitionParams = false) const;
+
+ SVal getCXXThisVal() const { return UndefinedVal(); }
+
static bool classof(const CallEvent *CA) {
return CA->getKind() == CE_Block;
}
///
/// Example: \c T(1)
class CXXConstructorCall : public AnyFunctionCall {
- const CXXConstructExpr *CE;
- const MemRegion *Target;
+ friend class CallEvent;
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
public:
- CXXConstructorCall(const CXXConstructExpr *ce, ProgramStateRef St,
+ /// Represents a constructor call to a new or unknown region.
+ CXXConstructorCall(const CXXConstructExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(0) {}
- CXXConstructorCall(const CXXConstructExpr *ce, const MemRegion *target,
+ : AnyFunctionCall(CE, St, LCtx, CE_CXXConstructor) {
+ Data = 0;
+ }
+
+ /// Represents a constructor call on an existing object region.
+ CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
ProgramStateRef St, const LocationContext *LCtx)
- : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(target) {}
+ : AnyFunctionCall(CE, St, LCtx, CE_CXXConstructor) {
+ Data = target;
+ }
- const CXXConstructExpr *getOriginExpr() const { return CE; }
- SourceRange getSourceRange() const { return CE->getSourceRange(); }
+ const CXXConstructExpr *getOriginExpr() const {
+ return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
const CXXConstructorDecl *getDecl() const {
- return CE->getConstructor();
+ return getOriginExpr()->getConstructor();
}
- unsigned getNumArgs() const { return CE->getNumArgs(); }
+ unsigned getNumArgs() const { return getOriginExpr()->getNumArgs(); }
const Expr *getArgExpr(unsigned Index) const {
- return CE->getArg(Index);
+ return getOriginExpr()->getArg(Index);
}
SVal getCXXThisVal() const;
/// This can occur at the end of a scope (for automatic objects), at the end
/// of a full-expression (for temporaries), or as part of a delete.
class CXXDestructorCall : public AnyFunctionCall {
- const CXXDestructorDecl *DD;
- const MemRegion *Target;
- SourceLocation Loc;
+ friend class CallEvent;
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
public:
- CXXDestructorCall(const CXXDestructorDecl *dd, const Stmt *Trigger,
- const MemRegion *target, ProgramStateRef St,
+ /// Creates an implicit destructor.
+ ///
+ /// \param DD The destructor that will be called.
+ /// \param Trigger The statement whose completion causes this destructor call.
+ /// \param Target The object region to be destructed.
+ /// \param St The path-sensitive state at this point in the program.
+ /// \param LCtx The location context at this point in the program.
+ CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+ const MemRegion *Target, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(St, LCtx, CE_CXXDestructor), DD(dd), Target(target),
- Loc(Trigger->getLocEnd()) {}
-
- const Expr *getOriginExpr() const { return 0; }
- SourceRange getSourceRange() const { return Loc; }
+ : AnyFunctionCall(DD, St, LCtx, CE_CXXDestructor) {
+ Data = Target;
+ Location = Trigger->getLocEnd();
+ }
- const CXXDestructorDecl *getDecl() const { return DD; }
+ SourceRange getSourceRange() const { return Location; }
unsigned getNumArgs() const { return 0; }
SVal getCXXThisVal() const;
///
/// This is a call to "operator new".
class CXXAllocatorCall : public AnyFunctionCall {
- const CXXNewExpr *E;
-
public:
- CXXAllocatorCall(const CXXNewExpr *e, ProgramStateRef St,
+ CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(St, LCtx, CE_CXXAllocator), E(e) {}
+ : AnyFunctionCall(E, St, LCtx, CE_CXXAllocator) {}
- const CXXNewExpr *getOriginExpr() const { return E; }
- SourceRange getSourceRange() const { return E->getSourceRange(); }
+ const CXXNewExpr *getOriginExpr() const {
+ return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
+ }
+
+ // FIXME: This isn't exactly the range of the allocator...
+ SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
const FunctionDecl *getDecl() const {
- return E->getOperatorNew();
+ return getOriginExpr()->getOperatorNew();
}
- unsigned getNumArgs() const { return E->getNumPlacementArgs() + 1; }
+ unsigned getNumArgs() const {
+ return getOriginExpr()->getNumPlacementArgs() + 1;
+ }
const Expr *getArgExpr(unsigned Index) const {
// The first argument of an allocator call is the size of the allocation.
if (Index == 0)
return 0;
- return E->getPlacementArg(Index - 1);
+ return getOriginExpr()->getPlacementArg(Index - 1);
}
+ SVal getCXXThisVal() const { return UndefinedVal(); }
+
static bool classof(const CallEvent *CE) {
return CE->getKind() == CE_CXXAllocator;
}
/// \brief Represents any expression that calls an Objective-C method.
class ObjCMethodCall : public CallEvent {
- const ObjCMessageExpr *Msg;
+ friend class CallEvent;
protected:
- ObjCMethodCall(const ObjCMessageExpr *msg, ProgramStateRef St,
+ ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
const LocationContext *LCtx, Kind K)
- : CallEvent(St, LCtx, K), Msg(msg) {}
+ : CallEvent(Msg, St, LCtx, K) {}
void addExtraInvalidatedRegions(RegionList &Regions) const;
- param_iterator param_begin(bool UseDefinitionParams = false) const;
- param_iterator param_end(bool UseDefinitionParams = false) const;
-
QualType getDeclaredResultType() const;
public:
- Selector getSelector() const { return Msg->getSelector(); }
- bool isInstanceMessage() const { return Msg->isInstanceMessage(); }
- ObjCMethodFamily getMethodFamily() const { return Msg->getMethodFamily(); }
+ const ObjCMessageExpr *getOriginExpr() const {
+ return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
+ }
- const ObjCMethodDecl *getDecl() const { return Msg->getMethodDecl(); }
- SourceRange getSourceRange() const { return Msg->getSourceRange(); }
- unsigned getNumArgs() const { return Msg->getNumArgs(); }
- const Expr *getArgExpr(unsigned Index) const {
- return Msg->getArg(Index);
+ Selector getSelector() const {
+ return getOriginExpr()->getSelector();
+ }
+ bool isInstanceMessage() const {
+ return getOriginExpr()->isInstanceMessage();
+ }
+ ObjCMethodFamily getMethodFamily() const {
+ return getOriginExpr()->getMethodFamily();
}
- const ObjCMessageExpr *getOriginExpr() const { return Msg; }
+ const ObjCMethodDecl *getDecl() const {
+ return getOriginExpr()->getMethodDecl();
+ }
+
+ SourceRange getSourceRange() const {
+ return getOriginExpr()->getSourceRange();
+ }
+ unsigned getNumArgs() const {
+ return getOriginExpr()->getNumArgs();
+ }
+ const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index);
+ }
/// \brief Returns the value of the receiver at the time of this call.
SVal getReceiverSVal() const;
/// Returns NULL otherwise.
/// \sa ObjCMessageExpr::getInstanceReceiver()
const Expr *getInstanceReceiverExpr() const {
- return Msg->getInstanceReceiver();
+ return getOriginExpr()->getInstanceReceiver();
}
/// \brief Get the interface for the receiver.
/// This works whether this is an instance message or a class message.
/// However, it currently just uses the static type of the receiver.
const ObjCInterfaceDecl *getReceiverInterface() const {
- return Msg->getReceiverInterface();
+ return getOriginExpr()->getReceiverInterface();
}
SourceRange getReceiverSourceRange() const {
- return Msg->getReceiverRange();
+ return getOriginExpr()->getReceiverRange();
}
const Decl *getDefinition(bool &IsDynamicDispatch) const {
return 0;
}
+ SVal getCXXThisVal() const { return UndefinedVal(); }
+
+ bool argumentsMayEscape() const {
+ return hasNonZeroCallbackArg();
+ }
+
+ SVal getArgSVal(unsigned Index) const { return getSVal(getArgExpr(Index)); }
+ SourceRange getArgSourceRange(unsigned Index) const {
+ return getArgExpr(Index)->getSourceRange();
+ }
+
+
+ param_iterator param_begin(bool UseDefinitionParams = false) const;
+ param_iterator param_end(bool UseDefinitionParams = false) const;
+
static bool classof(const CallEvent *CA) {
return CA->getKind() >= CE_BEG_OBJC_CALLS &&
CA->getKind() <= CE_END_OBJC_CALLS;
///
/// Example: obj.prop += 1;
class ObjCPropertyAccess : public ObjCMethodCall {
- const ObjCPropertyRefExpr *PropE;
- SourceRange EntireRange;
-
public:
- ObjCPropertyAccess(const ObjCPropertyRefExpr *pe, SourceRange range,
+ ObjCPropertyAccess(const ObjCPropertyRefExpr *PE, SourceRange range,
const ObjCMessageExpr *Msg, const ProgramStateRef St,
const LocationContext *LCtx)
- : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess), PropE(pe),
- EntireRange(range)
- {}
+ : ObjCMethodCall(Msg, St, LCtx, CE_ObjCPropertyAccess) {
+ Data = PE;
+ }
/// \brief Returns true if this property access is calling the setter method.
bool isSetter() const {
return getNumArgs() > 0;
}
- SourceRange getSourceRange() const {
- return EntireRange;
- }
+ SourceRange getSourceRange() const;
/// \brief Return the property reference part of this access.
///
/// In the expression "obj.prop += 1", the property reference expression is
/// "obj.prop".
const ObjCPropertyRefExpr *getPropertyExpr() const {
- return PropE;
+ return static_cast<const ObjCPropertyRefExpr *>(Data);
}
static bool classof(const CallEvent *CA) {
}
};
+
+// FIXME: Use a .def or .td file for this.
+#define DISPATCH(fn) \
+ switch (getKind()) { \
+ case CE_Function: \
+ return cast<FunctionCall>(this)->fn(); \
+ case CE_CXXMember: \
+ return cast<CXXMemberCall>(this)->fn(); \
+ case CE_CXXMemberOperator: \
+ return cast<CXXMemberOperatorCall>(this)->fn(); \
+ case CE_Block: \
+ return cast<BlockCall>(this)->fn(); \
+ case CE_CXXConstructor: \
+ return cast<CXXConstructorCall>(this)->fn(); \
+ case CE_CXXDestructor: \
+ return cast<CXXDestructorCall>(this)->fn(); \
+ case CE_CXXAllocator: \
+ return cast<CXXAllocatorCall>(this)->fn(); \
+ case CE_ObjCMessage: \
+ return cast<ObjCMessageSend>(this)->fn(); \
+ case CE_ObjCPropertyAccess: \
+ return cast<ObjCPropertyAccess>(this)->fn(); \
+ }
+
+#define DISPATCH_ARG(fn, arg) \
+ switch (getKind()) { \
+ case CE_Function: \
+ return cast<FunctionCall>(this)->fn(arg); \
+ case CE_CXXMember: \
+ return cast<CXXMemberCall>(this)->fn(arg); \
+ case CE_CXXMemberOperator: \
+ return cast<CXXMemberOperatorCall>(this)->fn(arg); \
+ case CE_Block: \
+ return cast<BlockCall>(this)->fn(arg); \
+ case CE_CXXConstructor: \
+ return cast<CXXConstructorCall>(this)->fn(arg); \
+ case CE_CXXDestructor: \
+ return cast<CXXDestructorCall>(this)->fn(arg); \
+ case CE_CXXAllocator: \
+ return cast<CXXAllocatorCall>(this)->fn(arg); \
+ case CE_ObjCMessage: \
+ return cast<ObjCMessageSend>(this)->fn(arg); \
+ case CE_ObjCPropertyAccess: \
+ return cast<ObjCPropertyAccess>(this)->fn(arg); \
+ }
+
+inline void CallEvent::addExtraInvalidatedRegions(RegionList &Regions) const {
+ DISPATCH_ARG(addExtraInvalidatedRegions, Regions);
+}
+
+inline QualType CallEvent::getDeclaredResultType() const {
+ DISPATCH(getDeclaredResultType);
+}
+
+inline const Decl *CallEvent::getDecl() const {
+ if (const Decl *D = Origin.dyn_cast<const Decl *>())
+ return D;
+ DISPATCH(getDecl);
+}
+
+inline const Decl *CallEvent::getDefinition(bool &IsDynamicDispatch) const {
+ DISPATCH_ARG(getDefinition, IsDynamicDispatch);
+}
+
+inline unsigned CallEvent::getNumArgs() const {
+ DISPATCH(getNumArgs);
+}
+
+inline SourceRange CallEvent::getSourceRange() const {
+ DISPATCH(getSourceRange);
+}
+
+inline SVal CallEvent::getArgSVal(unsigned Index) const {
+ DISPATCH_ARG(getArgSVal, Index);
+}
+
+inline const Expr *CallEvent::getArgExpr(unsigned Index) const {
+ DISPATCH_ARG(getArgExpr, Index);
+}
+
+inline SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
+ DISPATCH_ARG(getArgSourceRange, Index);
+}
+
+inline SVal CallEvent::getCXXThisVal() const {
+ DISPATCH(getCXXThisVal);
+}
+
+
+inline bool CallEvent::argumentsMayEscape() const {
+ DISPATCH(argumentsMayEscape);
+}
+
+inline CallEvent::param_iterator
+CallEvent::param_begin(bool UseDefinitionParams) const {
+ DISPATCH_ARG(param_begin, UseDefinitionParams);
+}
+
+inline CallEvent::param_iterator
+CallEvent::param_end(bool UseDefinitionParams) const {
+ DISPATCH_ARG(param_end, UseDefinitionParams);
+}
+
+#undef DISPATCH
+#undef DISPATCH_ARG
+
} // end namespace ento
} // end namespace clang
#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
-SVal CallEvent::getArgSVal(unsigned Index) const {
- const Expr *ArgE = getArgExpr(Index);
- if (!ArgE)
- return UnknownVal();
- return getSVal(ArgE);
-}
-
-SourceRange CallEvent::getArgSourceRange(unsigned Index) const {
- const Expr *ArgE = getArgExpr(Index);
- if (!ArgE)
- return SourceRange();
- return ArgE->getSourceRange();
-}
-
QualType CallEvent::getResultType() const {
QualType ResultTy = getDeclaredResultType();
ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig) const {
- ProgramStateRef Result = (Orig ? Orig : State);
+ ProgramStateRef Result = (Orig ? Orig : getState());
SmallVector<const MemRegion *, 8> RegionsToInvalidate;
addExtraInvalidatedRegions(RegionsToInvalidate);
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
// global variables.
return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
- BlockCount, LCtx, /*Symbols=*/0, this);
+ BlockCount, getLocationContext(),
+ /*Symbols=*/0, this);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
const ProgramPointTag *Tag) const {
if (const Expr *E = getOriginExpr()) {
if (IsPreVisit)
- return PreStmt(E, LCtx, Tag);
- return PostStmt(E, LCtx, Tag);
+ return PreStmt(E, getLocationContext(), Tag);
+ return PostStmt(E, getLocationContext(), Tag);
}
const Decl *D = getDecl();
SourceLocation Loc = getSourceRange().getBegin();
if (IsPreVisit)
- return PreImplicitCall(D, Loc, LCtx, Tag);
- return PostImplicitCall(D, Loc, LCtx, Tag);
+ return PreImplicitCall(D, Loc, getLocationContext(), Tag);
+ return PostImplicitCall(D, Loc, getLocationContext(), Tag);
}
}
bool AnyFunctionCall::argumentsMayEscape() const {
- if (CallEvent::argumentsMayEscape())
+ if (hasNonZeroCallbackArg())
return true;
const FunctionDecl *D = getDecl();
return false;
}
+SVal AnyFunctionCall::getArgSVal(unsigned Index) const {
+ const Expr *ArgE = getArgExpr(Index);
+ if (!ArgE)
+ return UnknownVal();
+ return getSVal(ArgE);
+}
+
+SourceRange AnyFunctionCall::getArgSourceRange(unsigned Index) const {
+ const Expr *ArgE = getArgExpr(Index);
+ if (!ArgE)
+ return SourceRange();
+ return ArgE->getSourceRange();
+}
+
const FunctionDecl *SimpleCall::getDecl() const {
- const FunctionDecl *D = CE->getDirectCallee();
+ const FunctionDecl *D = getOriginExpr()->getDirectCallee();
if (D)
return D;
- return getSVal(CE->getCallee()).getAsFunctionDecl();
+ return getSVal(getOriginExpr()->getCallee()).getAsFunctionDecl();
}
void CallEvent::dump(raw_ostream &Out) const {
- ASTContext &Ctx = State->getStateManager().getContext();
+ ASTContext &Ctx = getState()->getStateManager().getContext();
if (const Expr *E = getOriginExpr()) {
E->printPretty(Out, Ctx, 0, Ctx.getLangOpts());
Out << "\n";
if (!RD)
return 0;
- RD = RD->getDefinition();
- if (!RD)
- return 0;
-
const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD);
const FunctionDecl *Definition;
if (!Result->hasBody(Definition))
SVal CXXConstructorCall::getCXXThisVal() const {
- if (Target)
- return loc::MemRegionVal(Target);
+ if (Data)
+ return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
return UnknownVal();
}
void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
- if (Target)
- Regions.push_back(Target);
+ if (Data)
+ Regions.push_back(static_cast<const MemRegion *>(Data));
}
SVal CXXDestructorCall::getCXXThisVal() const {
- if (Target)
- return loc::MemRegionVal(Target);
+ if (Data)
+ return loc::MemRegionVal(static_cast<const MemRegion *>(Data));
return UnknownVal();
}
void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
- if (Target)
- Regions.push_back(Target);
+ if (Data)
+ Regions.push_back(static_cast<const MemRegion *>(Data));
}
const Decl *CXXDestructorCall::getDefinition(bool &IsDynamicDispatch) const {
if (!isInstanceMessage())
return UnknownVal();
- const Expr *Base = Msg->getInstanceReceiver();
- if (Base)
+ if (const Expr *Base = getInstanceReceiverExpr())
return getSVal(Base);
// An instance message with no expression means we are sending to super.
// In this case the object reference is the same as 'self'.
+ const LocationContext *LCtx = getLocationContext();
const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
- return State->getSVal(State->getRegion(SelfDecl, LCtx));
+ return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx));
+}
+
+SourceRange ObjCPropertyAccess::getSourceRange() const {
+ const ParentMap &PM = getLocationContext()->getParentMap();
+ const ObjCMessageExpr *ME = getOriginExpr();
+ const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(PM.getParent(ME));
+ return PO->getSourceRange();
}