diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-07-02 19:27:35 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-07-02 19:27:35 +0000 |
commit | 740d490593e0de8732a697c9f77b90ddd463863b (patch) | |
tree | 1c4003bd0e0d2be292345e6ac90af5628e1734c0 /include/clang | |
parent | 7518b3784ed2176aad8dcabe0685c6e02c5f1043 (diff) |
[analyzer] Add a new abstraction over all types of calls: CallEvent
This is intended to replace CallOrObjCMessage, and is eventually intended to be
used for anything that cares more about /what/ is being called than /how/ it's
being called. For example, inlining destructors should be the same as inlining
blocks, and checking __attribute__((nonnull)) should apply to the allocator
calls generated by operator new.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159554 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang')
7 files changed, 367 insertions, 15 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 76d8c15f75..fb224ef158 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -266,7 +266,7 @@ class RegionChanges { const StoreManager::InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> Explicits, ArrayRef<const MemRegion *> Regions, - const CallOrObjCMessage *Call) { + const CallEvent *Call) { return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated, Explicits, Regions, Call); } diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index b9d6a32918..3202fbe6b8 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -294,7 +294,7 @@ public: const StoreManager::InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallOrObjCMessage *Call); + const CallEvent *Call); /// \brief Run checkers for handling assumptions on symbolic values. ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, @@ -373,7 +373,7 @@ public: const StoreManager::InvalidatedSymbols *symbols, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallOrObjCMessage *Call)> + const CallEvent *Call)> CheckRegionChangesFunc; typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h new file mode 100644 index 0000000000..45b5fc70a2 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h @@ -0,0 +1,356 @@ +//===- Calls.h - Wrapper for all function and method calls --------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file defines CallEvent and its subclasses, which represent path- +/// sensitive instances of different kinds of function and method calls +/// (C, C++, and Objective-C). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL +#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL + +#include "clang/Basic/SourceManager.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" + +namespace clang { +namespace ento { + +enum CallEventKind { + CE_Function, + CE_CXXMember, + CE_Block, + CE_BEG_SIMPLE_CALLS = CE_Function, + CE_END_SIMPLE_CALLS = CE_Block, + CE_CXXConstructor, + CE_BEG_FUNCTION_CALLS = CE_Function, + CE_END_FUNCTION_CALLS = CE_CXXConstructor, + CE_ObjCMessage +}; + +/// \brief Represents an abstract call to a function or method along a +/// particular path. +class CallEvent { +public: + typedef CallEventKind Kind; + +protected: + ProgramStateRef State; + const LocationContext *LCtx; + const Kind K; + + 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); + } + + 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 {} + + typedef const ParmVarDecl * const *param_iterator; + virtual param_iterator param_begin() const = 0; + virtual param_iterator param_end() const = 0; + + virtual QualType getDeclaredResultType() const { return QualType(); } + +public: + /// \brief Returns the declaration of the function or method that will be + /// called. May be null. + virtual const Decl *getDecl() const = 0; + + /// \brief Returns the expression whose value will be the result of this call. + /// May be null. + virtual const Expr *getOriginExpr() const = 0; + + /// \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; + + /// \brief Returns true if the callee is known to be from a system header. + bool isInSystemHeader() const { + const Decl *D = getDecl(); + if (!D) + return false; + + SourceLocation Loc = D->getLocation(); + if (Loc.isValid()) { + const SourceManager &SM = + State->getStateManager().getContext().getSourceManager(); + return SM.isInSystemHeader(D->getLocation()); + } + + // Special case for implicitly-declared global operator new/delete. + // These should be considered system functions. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal(); + + return false; + } + + /// \brief Returns the kind of call this is. + Kind getKind() const { return K; } + + /// \brief Returns the value of a given argument at the time of the call. + virtual 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; + } + + /// \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; + + /// \brief Returns the result type, adjusted for references. + QualType getResultType() const; + + /// \brief Returns true if any of the arguments appear to represent callbacks. + bool hasNonZeroCallbackArg() const; + + /// \brief Returns a new state with all argument regions invalidated. + /// + /// This accepts an alternate state in case some processing has already + /// occurred. + ProgramStateRef invalidateRegions(unsigned BlockCount, + ProgramStateRef Orig = 0) const; + + // Iterator access to parameter types. +private: + typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun; + +public: + typedef llvm::mapped_iterator<param_iterator, get_type_fun> + param_type_iterator; + + param_type_iterator param_type_begin() const { + return llvm::map_iterator(param_begin(), + get_type_fun(&ParmVarDecl::getType)); + } + param_type_iterator param_type_end() const { + return llvm::map_iterator(param_end(), get_type_fun(&ParmVarDecl::getType)); + } + + 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 { +protected: + AnyFunctionCall(ProgramStateRef St, const LocationContext *LCtx, Kind K) + : CallEvent(St, LCtx, K) {} + + param_iterator param_begin() const; + param_iterator param_end() const; + + QualType getDeclaredResultType() const; + +public: + virtual const FunctionDecl *getDecl() const = 0; + + 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, + const LocationContext *LCtx, Kind K) + : AnyFunctionCall(St, LCtx, K), CE(ce) { + } + +public: + const CallExpr *getOriginExpr() const { return CE; } + + const FunctionDecl *getDecl() const; + + unsigned getNumArgs() const { return CE->getNumArgs(); } + + const Expr *getArgExpr(unsigned Index) const { + return CE->getArg(Index); + } + + static bool classof(const CallEvent *CA) { + return CA->getKind() >= CE_BEG_SIMPLE_CALLS && + CA->getKind() <= CE_END_SIMPLE_CALLS; + } +}; + +/// \brief Represents a C function or static C++ member function call. +/// +/// Example: \c fun() +class FunctionCall : public SimpleCall { +public: + FunctionCall(const CallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : SimpleCall(CE, St, LCtx, CE_Function) {} + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_Function; + } +}; + +/// \brief Represents a non-static C++ member function call. +/// +/// Example: \c obj.fun() +class CXXMemberCall : public SimpleCall { +protected: + void addExtraInvalidatedRegions(RegionList &Regions) const; + +public: + CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : SimpleCall(CE, St, LCtx, CE_CXXMember) {} + + const CXXMemberCallExpr *getOriginExpr() const { + return cast<CXXMemberCallExpr>(SimpleCall::getOriginExpr()); + } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXMember; + } +}; + +/// \brief Represents a call to a block. +/// +/// Example: \c ^{ /* ... */ }() +class BlockCall : public SimpleCall { +protected: + void addExtraInvalidatedRegions(RegionList &Regions) const; + + param_iterator param_begin() const; + param_iterator param_end() const; + + QualType getDeclaredResultType() const; + +public: + BlockCall(const CallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx) + : SimpleCall(CE, St, LCtx, CE_Block) { + assert(isa<BlockDataRegion>(getSVal(CE->getCallee()).getAsRegion())); + } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_Block; + } + +private: + const BlockDataRegion *getBlockRegion() const; +}; + +/// \brief Represents a call to a C++ constructor. +/// +/// Example: \c T(1) +class CXXConstructorCall : public AnyFunctionCall { + const CXXConstructExpr *CE; + const MemRegion *Target; + +protected: + void addExtraInvalidatedRegions(RegionList &Regions) const; + +public: + 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, + ProgramStateRef St, const LocationContext *LCtx) + : AnyFunctionCall(St, LCtx, CE_CXXConstructor), CE(ce), Target(target) {} + + const CXXConstructExpr *getOriginExpr() const { return CE; } + + const CXXConstructorDecl *getDecl() const { + return CE->getConstructor(); + } + + unsigned getNumArgs() const { return CE->getNumArgs(); } + + const Expr *getArgExpr(unsigned Index) const { + return CE->getArg(Index); + } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXConstructor; + } +}; + +/// \brief Represents any expression that causes an Objective-C message send. +// +// This class is mostly passthrough to ObjCMessage, because /that/ class is the +// adapter for the different kinds of Objective-C messages in the system. The +// difference here is that like other CallActions this refers to a specific +// (path-sensitive) message send, while ObjCMessage is simply a wrapper for the +// various (path-insensitive) expressions that are implemented using messages. +class ObjCMessageInvocation : public CallEvent { + ObjCMessage Msg; + +protected: + void addExtraInvalidatedRegions(RegionList &Regions) const; + + param_iterator param_begin() const; + param_iterator param_end() const; + + QualType getDeclaredResultType() const; + +public: + ObjCMessageInvocation(const ObjCMessage &msg, ProgramStateRef St, + const LocationContext *LCtx) + : CallEvent(St, LCtx, CE_ObjCMessage), Msg(msg) {} + + Selector getSelector() const { return Msg.getSelector(); } + bool isInstanceMessage() const { return Msg.isInstanceMessage(); } + const ObjCMethodDecl *getDecl() const { return Msg.getMethodDecl(); } + unsigned getNumArgs() const { return Msg.getNumArgs(); } + const Expr *getArgExpr(unsigned Index) const { return Msg.getArgExpr(Index); } + + // FIXME: for emitting warnings and such this may not be the best idea. + const Expr *getOriginExpr() const { return Msg.getMessageExpr(); } + + SVal getReceiverSVal() const; + + SourceRange getReceiverSourceRange() const { + return Msg.getReceiverSourceRange(); + } + + const ObjCInterfaceDecl *getReceiverInterface() const { + return Msg.getReceiverInterface(); + } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_ObjCMessage; + } +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 0cccd41d3c..46fb70deae 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -41,7 +41,7 @@ class ObjCForCollectionStmt; namespace ento { class AnalysisManager; -class CallOrObjCMessage; +class CallEvent; class ObjCMessage; class ExprEngine : public SubEngine { @@ -240,7 +240,7 @@ public: const StoreManager::InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallOrObjCMessage *Call); + const CallEvent *Call); /// printState - Called by ProgramStateManager to print checker-specific data. void printState(raw_ostream &Out, ProgramStateRef State, @@ -437,10 +437,6 @@ protected: ExplodedNode *Pred, ProgramStateRef state, bool GenSink); - ProgramStateRef invalidateArguments(ProgramStateRef State, - const CallOrObjCMessage &Call, - const LocationContext *LC); - ProgramStateRef MarkBranch(ProgramStateRef state, const Stmt *Terminator, const LocationContext *LCtx, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 44190c6709..3dd2775aa4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -35,7 +35,7 @@ class ASTContext; namespace ento { -class CallOrObjCMessage; +class CallEvent; typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&, SubEngine&); @@ -219,7 +219,7 @@ public: const Expr *E, unsigned BlockCount, const LocationContext *LCtx, StoreManager::InvalidatedSymbols *IS = 0, - const CallOrObjCMessage *Call = 0) const; + const CallEvent *Call = 0) const; /// enterStackFrame - Returns the state for entry to the given stack frame, /// preserving the current state. @@ -381,7 +381,7 @@ private: const Expr *E, unsigned BlockCount, const LocationContext *LCtx, StoreManager::InvalidatedSymbols &IS, - const CallOrObjCMessage *Call) const; + const CallEvent *Call) const; }; //===----------------------------------------------------------------------===// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index b8a745168e..35097aca6c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -29,7 +29,7 @@ class StackFrameContext; namespace ento { -class CallOrObjCMessage; +class CallEvent; class ProgramState; class ProgramStateManager; class SubRegionMap; @@ -194,7 +194,7 @@ public: const Expr *E, unsigned Count, const LocationContext *LCtx, InvalidatedSymbols &IS, - const CallOrObjCMessage *Call, + const CallEvent *Call, InvalidatedRegions *Invalidated) = 0; /// enterStackFrame - Let the StoreManager to do something when execution diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index baf57d4906..68b81f19a4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -105,7 +105,7 @@ public: const StoreManager::InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, - const CallOrObjCMessage *Call) = 0; + const CallEvent *Call) = 0; inline ProgramStateRef |