blob: d1e25a5a664366c6e05b97553386197e1b60567e [file] [log] [blame]
//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a meta-engine for path-sensitive dataflow analysis that
// is built on GREngine, but provides the boilerplate to execute transfer
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
namespace clang {
class BugType;
class PathDiagnosticClient;
class Diagnostic;
class BugReporterData;
class GRExprEngine {
public:
typedef GRState StateTy;
typedef ExplodedGraph<StateTy> GraphTy;
typedef GraphTy::NodeTy NodeTy;
// Builders.
typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
typedef GREndPathNodeBuilder<StateTy> EndPathNodeBuilder;
typedef ExplodedNodeSet<StateTy> NodeSet;
protected:
GRCoreEngine<GRExprEngine> CoreEngine;
/// G - the simulation graph.
GraphTy& G;
/// Liveness - live-variables information the ValueDecl* and block-level
/// Expr* in the CFG. Used to prune out dead state.
LiveVariables& Liveness;
/// DeadSymbols - A scratch set used to record the set of symbols that
/// were just marked dead by a call to GRStateManager::RemoveDeadBindings.
GRStateManager::DeadSymbolsTy DeadSymbols;
/// Builder - The current GRStmtNodeBuilder which is used when building the
/// nodes for a given statement.
StmtNodeBuilder* Builder;
/// StateMgr - Object that manages the data for all created states.
GRStateManager StateMgr;
/// BugTypes - Objects used for reporting bugs.
typedef std::vector<BugType*> BugTypeSet;
BugTypeSet BugTypes;
/// SymMgr - Object that manages the symbol information.
SymbolManager& SymMgr;
/// EntryNode - The immediate predecessor node.
NodeTy* EntryNode;
/// CleanedState - The state for EntryNode "cleaned" of all dead
/// variables and symbols (as determined by a liveness analysis).
const GRState* CleanedState;
/// CurrentStmt - The current block-level statement.
Stmt* CurrentStmt;
// Obj-C Class Identifiers.
IdentifierInfo* NSExceptionII;
// Obj-C Selectors.
Selector* NSExceptionInstanceRaiseSelectors;
Selector RaiseSel;
llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
public:
typedef llvm::SmallPtrSet<NodeTy*,2> UndefBranchesTy;
typedef llvm::SmallPtrSet<NodeTy*,2> UndefStoresTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadDerefTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadCallsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> UndefReceiversTy;
typedef llvm::DenseMap<NodeTy*, Expr*> UndefArgsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> BadDividesTy;
typedef llvm::SmallPtrSet<NodeTy*,2> NoReturnCallsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> UndefResultsTy;
typedef llvm::SmallPtrSet<NodeTy*,2> RetsStackAddrTy;
protected:
/// RetsStackAddr - Nodes in the ExplodedGraph that result from returning
/// the address of a stack variable.
RetsStackAddrTy RetsStackAddr;
/// UndefBranches - Nodes in the ExplodedGraph that result from
/// taking a branch based on an undefined value.
UndefBranchesTy UndefBranches;
/// UndefStores - Sinks in the ExplodedGraph that result from
/// making a store to an undefined lvalue.
UndefStoresTy UndefStores;
/// NoReturnCalls - Sinks in the ExplodedGraph that result from
// calling a function with the attribute "noreturn".
NoReturnCallsTy NoReturnCalls;
/// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
/// taking a dereference on a symbolic pointer that MAY be NULL.
BadDerefTy ImplicitNullDeref;
/// ExplicitNullDeref - Nodes in the ExplodedGraph that result from
/// taking a dereference on a symbolic pointer that MUST be NULL.
BadDerefTy ExplicitNullDeref;
/// UnitDeref - Nodes in the ExplodedGraph that result from
/// taking a dereference on an undefined value.
BadDerefTy UndefDeref;
/// ImplicitBadDivides - Nodes in the ExplodedGraph that result from
/// evaluating a divide or modulo operation where the denominator
/// MAY be zero.
BadDividesTy ImplicitBadDivides;
/// ExplicitBadDivides - Nodes in the ExplodedGraph that result from
/// evaluating a divide or modulo operation where the denominator
/// MUST be zero or undefined.
BadDividesTy ExplicitBadDivides;
/// UndefResults - Nodes in the ExplodedGraph where the operands are defined
/// by the result is not. Excludes divide-by-zero errors.
UndefResultsTy UndefResults;
/// BadCalls - Nodes in the ExplodedGraph resulting from calls to function
/// pointers that are NULL (or other constants) or Undefined.
BadCallsTy BadCalls;
/// UndefReceiver - Nodes in the ExplodedGraph resulting from message
/// ObjC message expressions where the receiver is undefined (uninitialized).
UndefReceiversTy UndefReceivers;
/// UndefArg - Nodes in the ExplodedGraph resulting from calls to functions
/// where a pass-by-value argument has an undefined value.
UndefArgsTy UndefArgs;
/// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from
/// message expressions where a pass-by-value argument has an undefined
/// value.
UndefArgsTy MsgExprUndefArgs;
public:
GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, LiveVariables& L);
~GRExprEngine();
void ExecuteWorkList(unsigned Steps = 150000) {
CoreEngine.ExecuteWorkList(Steps);
}
/// getContext - Return the ASTContext associated with this analysis.
ASTContext& getContext() const { return G.getContext(); }
/// getCFG - Returns the CFG associated with this analysis.
CFG& getCFG() { return G.getCFG(); }
GRTransferFuncs& getTF() { return *StateMgr.TF; }
/// setTransferFunctions
void setTransferFunctions(GRTransferFuncs* tf);
void setTransferFunctions(GRTransferFuncs& tf) {
setTransferFunctions(&tf);
}
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
void ViewGraph(bool trim = false);
void ViewGraph(NodeTy** Beg, NodeTy** End);
/// getLiveness - Returned computed live-variables information for the
/// analyzed function.
const LiveVariables& getLiveness() const { return Liveness; }
LiveVariables& getLiveness() { return Liveness; }
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
const GRState* getInitialState();
GraphTy& getGraph() { return G; }
const GraphTy& getGraph() const { return G; }
typedef BugTypeSet::iterator bug_type_iterator;
typedef BugTypeSet::const_iterator const_bug_type_iterator;
bug_type_iterator bug_types_begin() { return BugTypes.begin(); }
bug_type_iterator bug_types_end() { return BugTypes.end(); }
const_bug_type_iterator bug_types_begin() const { return BugTypes.begin(); }
const_bug_type_iterator bug_types_end() const { return BugTypes.end(); }
/// Register - Register a BugType with the analyzer engine. A registered
/// BugType object will have its 'EmitWarnings' method called when the
/// the analyzer finishes analyzing a method or function.
void Register(BugType* B) {
BugTypes.push_back(B);
}
void RegisterInternalChecks();
void EmitWarnings(BugReporterData& BRData);
bool isRetStackAddr(const NodeTy* N) const {
return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
}
bool isUndefControlFlow(const NodeTy* N) const {
return N->isSink() && UndefBranches.count(const_cast<NodeTy*>(N)) != 0;
}
bool isUndefStore(const NodeTy* N) const {
return N->isSink() && UndefStores.count(const_cast<NodeTy*>(N)) != 0;
}
bool isImplicitNullDeref(const NodeTy* N) const {
return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
}
bool isExplicitNullDeref(const NodeTy* N) const {
return N->isSink() && ExplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
}
bool isUndefDeref(const NodeTy* N) const {
return N->isSink() && UndefDeref.count(const_cast<NodeTy*>(N)) != 0;
}
bool isImplicitBadDivide(const NodeTy* N) const {
return N->isSink() && ImplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
}
bool isExplicitBadDivide(const NodeTy* N) const {
return N->isSink() && ExplicitBadDivides.count(const_cast<NodeTy*>(N)) != 0;
}
bool isNoReturnCall(const NodeTy* N) const {
return N->isSink() && NoReturnCalls.count(const_cast<NodeTy*>(N)) != 0;
}
bool isUndefResult(const NodeTy* N) const {
return N->isSink() && UndefResults.count(const_cast<NodeTy*>(N)) != 0;
}
bool isBadCall(const NodeTy* N) const {
return N->isSink() && BadCalls.count(const_cast<NodeTy*>(N)) != 0;
}
bool isUndefArg(const NodeTy* N) const {
return N->isSink() &&
(UndefArgs.find(const_cast<NodeTy*>(N)) != UndefArgs.end() ||
MsgExprUndefArgs.find(const_cast<NodeTy*>(N)) != MsgExprUndefArgs.end());
}
bool isUndefReceiver(const NodeTy* N) const {
return N->isSink() && UndefReceivers.count(const_cast<NodeTy*>(N)) != 0;
}
typedef RetsStackAddrTy::iterator ret_stackaddr_iterator;
ret_stackaddr_iterator ret_stackaddr_begin() { return RetsStackAddr.begin(); }
ret_stackaddr_iterator ret_stackaddr_end() { return RetsStackAddr.end(); }
typedef UndefBranchesTy::iterator undef_branch_iterator;
undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); }
undef_branch_iterator undef_branches_end() { return UndefBranches.end(); }
typedef BadDerefTy::iterator null_deref_iterator;
null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); }
null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); }
null_deref_iterator implicit_null_derefs_begin() {
return ImplicitNullDeref.begin();
}
null_deref_iterator implicit_null_derefs_end() {
return ImplicitNullDeref.end();
}
typedef BadDerefTy::iterator undef_deref_iterator;
undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); }
undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); }
typedef BadDividesTy::iterator bad_divide_iterator;
bad_divide_iterator explicit_bad_divides_begin() {
return ExplicitBadDivides.begin();
}
bad_divide_iterator explicit_bad_divides_end() {
return ExplicitBadDivides.end();
}
bad_divide_iterator implicit_bad_divides_begin() {
return ImplicitBadDivides.begin();
}
bad_divide_iterator implicit_bad_divides_end() {
return ImplicitBadDivides.end();
}
typedef UndefResultsTy::iterator undef_result_iterator;
undef_result_iterator undef_results_begin() { return UndefResults.begin(); }
undef_result_iterator undef_results_end() { return UndefResults.end(); }
typedef BadCallsTy::iterator bad_calls_iterator;
bad_calls_iterator bad_calls_begin() { return BadCalls.begin(); }
bad_calls_iterator bad_calls_end() { return BadCalls.end(); }
typedef UndefArgsTy::iterator undef_arg_iterator;
undef_arg_iterator undef_arg_begin() { return UndefArgs.begin(); }
undef_arg_iterator undef_arg_end() { return UndefArgs.end(); }
undef_arg_iterator msg_expr_undef_arg_begin() {
return MsgExprUndefArgs.begin();
}
undef_arg_iterator msg_expr_undef_arg_end() {
return MsgExprUndefArgs.end();
}
typedef UndefReceiversTy::iterator undef_receivers_iterator;
undef_receivers_iterator undef_receivers_begin() {
return UndefReceivers.begin();
}
undef_receivers_iterator undef_receivers_end() {
return UndefReceivers.end();
}
void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
/// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
void ProcessStmt(Stmt* S, StmtNodeBuilder& builder);
/// ProcessBlockEntrance - Called by GRCoreEngine when start processing
/// a CFGBlock. This method returns true if the analysis should continue
/// exploring the given path, and false otherwise.
bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
GRBlockCounter BC);
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void ProcessBranch(Expr* Condition, Stmt* Term, BranchNodeBuilder& builder);
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void ProcessSwitch(SwitchNodeBuilder& builder);
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
/// nodes when the control reaches the end of a function.
void ProcessEndPath(EndPathNodeBuilder& builder) {
getTF().EvalEndPath(*this, builder);
}
GRStateManager& getStateManager() { return StateMgr; }
const GRStateManager& getStateManger() const { return StateMgr; }
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
const BasicValueFactory& getBasicVals() const {
return StateMgr.getBasicVals();
}
SymbolManager& getSymbolManager() { return SymMgr; }
const SymbolManager& getSymbolManager() const { return SymMgr; }
protected:
const GRState* GetState(NodeTy* N) {
return N == EntryNode ? CleanedState : N->getState();
}
public:
const GRState* SetRVal(const GRState* St, Expr* Ex, RVal V) {
return StateMgr.SetRVal(St, Ex, V);
}
const GRState* SetRVal(const GRState* St, const Expr* Ex, RVal V) {
return SetRVal(St, const_cast<Expr*>(Ex), V);
}
LVal getLVal(VarDecl* V) {
return getStateManager().getLVal(V);
}
protected:
const GRState* SetBlkExprRVal(const GRState* St, Expr* Ex, RVal V) {
return StateMgr.SetRVal(St, Ex, V, true, false);
}
const GRState* SetRVal(const GRState* St, LVal LV, RVal V) {
return StateMgr.SetRVal(St, LV, V);
}
RVal GetRVal(const GRState* St, Expr* Ex) {
return StateMgr.GetRVal(St, Ex);
}
RVal GetRVal(const GRState* St, const Expr* Ex) {
return GetRVal(St, const_cast<Expr*>(Ex));
}
RVal GetBlkExprRVal(const GRState* St, Expr* Ex) {
return StateMgr.GetBlkExprRVal(St, Ex);
}
RVal GetRVal(const GRState* St, LVal LV, QualType T = QualType()) {
return StateMgr.GetRVal(St, LV, T);
}
// Get the lvalue of an expression.
// FIXME: Remove this method, and used specialized versions of GetLValue
// in GRStateManager.
RVal GetLValue(const GRState* St, const Expr* Ex) {
return StateMgr.GetLValue(St, Ex);
}
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
return NonLVal::MakeVal(getBasicVals(), X, Ex->getType());
}
/// Assume - Create new state by assuming that a given expression
/// is true or false.
const GRState* Assume(const GRState* St, RVal Cond, bool Assumption,
bool& isFeasible) {
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
}
const GRState* Assume(const GRState* St, LVal Cond, bool Assumption,
bool& isFeasible) {
return StateMgr.Assume(St, Cond, Assumption, isFeasible);
}
NodeTy* MakeNode(NodeSet& Dst, Stmt* S, NodeTy* Pred, const GRState* St,
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) {
assert (Builder && "GRStmtNodeBuilder not present.");
return Builder->MakeNode(Dst, S, Pred, St, K);
}
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
/// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is
/// a DeclRefExpr, it evaluates to the MemRegionVal which represents its
/// storage location. Note that not all kinds of expressions has lvalue.
void VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
/// VisitArraySubscriptExpr - Transfer function for array accesses.
void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, NodeTy* Pred,
NodeSet& Dst, bool asLValue);
/// VisitAsmStmt - Transfer function logic for inline asm.
void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst);
void VisitAsmStmtHelperOutputs(AsmStmt* A,
AsmStmt::outputs_iterator I,
AsmStmt::outputs_iterator E,
NodeTy* Pred, NodeSet& Dst);
void VisitAsmStmtHelperInputs(AsmStmt* A,
AsmStmt::inputs_iterator I,
AsmStmt::inputs_iterator E,
NodeTy* Pred, NodeSet& Dst);
/// VisitBinaryOperator - Transfer function logic for binary operators.
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
/// VisitCall - Transfer function for function calls.
void VisitCall(CallExpr* CE, NodeTy* Pred,
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
NodeSet& Dst);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
bool asLValue);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
/// VisitMemberExpr - Transfer function for member expressions.
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst,bool asLValue);
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
bool asLValue);
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
ObjCMessageExpr::arg_iterator I,
ObjCMessageExpr::arg_iterator E,
NodeTy* Pred, NodeSet& Dst);
void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred,
NodeSet& Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst);
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
NodeSet& Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
bool asLValue);
bool CheckDivideZero(Expr* Ex, const GRState* St, NodeTy* Pred,
RVal Denom);
RVal EvalCast(RVal X, QualType CastT) {
if (X.isUnknownOrUndef())
return X;
if (isa<LVal>(X))
return getTF().EvalCast(*this, cast<LVal>(X), CastT);
else
return getTF().EvalCast(*this, cast<NonLVal>(X), CastT);
}
RVal EvalMinus(UnaryOperator* U, RVal X) {
return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLVal>(X)) : X;
}
RVal EvalComplement(RVal X) {
return X.isValid() ? getTF().EvalComplement(*this, cast<NonLVal>(X)) : X;
}
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, NonLVal R) {
return R.isValid() ? getTF().DetermEvalBinOpNN(getStateManager(), Op, L, R)
: R;
}
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, RVal R) {
return R.isValid() ? getTF().DetermEvalBinOpNN(getStateManager(), Op, L,
cast<NonLVal>(R)) : R;
}
void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex,
BinaryOperator::Opcode Op, NonLVal L, NonLVal R,
ExplodedNode<GRState>* Pred);
void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex,
BinaryOperator::Opcode Op, NonLVal L, NonLVal R);
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
if (L.isUndef() || R.isUndef())
return UndefinedVal();
if (L.isUnknown() || R.isUnknown())
return UnknownVal();
if (isa<LVal>(L)) {
if (isa<LVal>(R))
return getTF().EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
else
return getTF().EvalBinOp(*this, Op, cast<LVal>(L), cast<NonLVal>(R));
}
if (isa<LVal>(R)) {
// Support pointer arithmetic where the increment/decrement operand
// is on the left and the pointer on the right.
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
// Commute the operands.
return getTF().EvalBinOp(*this, Op, cast<LVal>(R),
cast<NonLVal>(L));
}
else
return getTF().DetermEvalBinOpNN(getStateManager(), Op, cast<NonLVal>(L),
cast<NonLVal>(R));
}
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal L, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred);
}
void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
}
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, const GRState* St,
RVal TargetLV, RVal Val);
void EvalStore(NodeSet& Dst, Expr* E, Expr* StoreE, NodeTy* Pred,
const GRState* St, RVal TargetLV, RVal Val);
// FIXME: The "CheckOnly" option exists only because Array and Field
// loads aren't fully implemented. Eventually this option will go away.
void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
const GRState* St, RVal location, bool CheckOnly = false);
const GRState* EvalLocation(Expr* Ex, NodeTy* Pred,
const GRState* St, RVal location,
bool isLoad = false);
void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
const GRState* MarkBranch(const GRState* St, Stmt* Terminator, bool branchTaken);
};
} // end clang namespace
#endif