diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h | 431 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/Calls.cpp | 83 |
2 files changed, 364 insertions, 150 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h index dc7e7344a4..596716b394 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h @@ -22,6 +22,7 @@ #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; @@ -49,38 +50,78 @@ enum CallEventKind { 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. @@ -91,21 +132,20 @@ public: /// 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 { @@ -116,7 +156,7 @@ public: SourceLocation Loc = D->getLocation(); if (Loc.isValid()) { const SourceManager &SM = - State->getStateManager().getContext().getSourceManager(); + getState()->getStateManager().getContext().getSourceManager(); return SM.isInSystemHeader(D->getLocation()); } @@ -128,34 +168,29 @@ public: 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; @@ -165,9 +200,7 @@ public: // 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, @@ -205,9 +238,9 @@ public: /// 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; @@ -227,26 +260,37 @@ public: } // 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; @@ -259,6 +303,12 @@ public: 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; @@ -267,24 +317,26 @@ public: /// \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) { @@ -302,6 +354,8 @@ public: 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; } @@ -310,6 +364,8 @@ public: /// \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; @@ -318,8 +374,6 @@ protected: : SimpleCall(CE, St, LCtx, K) {} public: - SVal getCXXThisVal() const = 0; - const Decl *getDefinition(bool &IsDynamicDispatch) const; static bool classof(const CallEvent *CA) { @@ -378,12 +432,11 @@ public: /// /// 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: @@ -412,6 +465,11 @@ 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; } @@ -421,31 +479,42 @@ public: /// /// 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; @@ -460,24 +529,28 @@ public: /// 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; @@ -492,29 +565,37 @@ public: /// /// 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; } @@ -522,33 +603,45 @@ public: /// \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; @@ -559,7 +652,7 @@ public: /// Returns NULL otherwise. /// \sa ObjCMessageExpr::getInstanceReceiver() const Expr *getInstanceReceiverExpr() const { - return Msg->getInstanceReceiver(); + return getOriginExpr()->getInstanceReceiver(); } /// \brief Get the interface for the receiver. @@ -567,11 +660,11 @@ public: /// 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 { @@ -586,6 +679,21 @@ public: 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; @@ -610,32 +718,27 @@ public: /// /// 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) { @@ -643,6 +746,112 @@ public: } }; + +// 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 diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp index 4ab6b45675..17627b3358 100644 --- a/lib/StaticAnalyzer/Core/Calls.cpp +++ b/lib/StaticAnalyzer/Core/Calls.cpp @@ -15,26 +15,13 @@ #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(); @@ -125,7 +112,7 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, 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); @@ -185,15 +172,16 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // 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(); @@ -201,8 +189,8 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, 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); } @@ -242,7 +230,7 @@ QualType AnyFunctionCall::getDeclaredResultType() const { } bool AnyFunctionCall::argumentsMayEscape() const { - if (CallEvent::argumentsMayEscape()) + if (hasNonZeroCallbackArg()) return true; const FunctionDecl *D = getDecl(); @@ -297,17 +285,31 @@ bool AnyFunctionCall::argumentsMayEscape() const { 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"; @@ -343,10 +345,6 @@ static const CXXMethodDecl *devirtualize(const CXXMethodDecl *MD, SVal ThisVal){ if (!RD) return 0; - RD = RD->getDefinition(); - if (!RD) - return 0; - const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD); const FunctionDecl *Definition; if (!Result->hasBody(Definition)) @@ -438,26 +436,26 @@ QualType BlockCall::getDeclaredResultType() const { 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 { @@ -520,14 +518,21 @@ SVal ObjCMethodCall::getReceiverSVal() 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(); } |