summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-10 22:07:57 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-10 22:07:57 +0000
commitd1d54aa1314fc4a6f7b001261079456df677c88b (patch)
treebeff7831c2d3ea0e5aecb5fcf88d51e5963205cd /clang/lib/StaticAnalyzer
parentfbe6dba15a02fdf30fdbdce40ea15b6452867bce (diff)
downloadbcm5719-llvm-d1d54aa1314fc4a6f7b001261079456df677c88b.tar.gz
bcm5719-llvm-d1d54aa1314fc4a6f7b001261079456df677c88b.zip
[analyzer] Use CallEvent for building inlined stack frames.
In order to accomplish this, we now build the callee's stack frame as part of the CallEnter node, rather than the subsequent BlockEdge node. This should not have any effect on perceived behavior or diagnostics. This makes it safe to re-enable inlining of member overloaded operators. llvm-svn: 160022
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Core/Calls.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp20
-rw-r--r--clang/lib/StaticAnalyzer/Core/ProgramState.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp88
-rw-r--r--clang/lib/StaticAnalyzer/Core/Store.cpp35
5 files changed, 96 insertions, 129 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/Calls.cpp b/clang/lib/StaticAnalyzer/Core/Calls.cpp
index 8ea1336bb7b..ced1154da75 100644
--- a/clang/lib/StaticAnalyzer/Core/Calls.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Calls.cpp
@@ -219,20 +219,22 @@ bool CallEvent::mayBeInlined(const Stmt *S) {
}
-CallEvent::param_iterator AnyFunctionCall::param_begin() const {
- const FunctionDecl *D = getDecl();
+CallEvent::param_iterator
+AnyFunctionCall::param_begin(bool UseDefinitionParams) const {
+ const Decl *D = UseDefinitionParams ? getDefinition() : getDecl();
if (!D)
return 0;
- return D->param_begin();
+ return cast<FunctionDecl>(D)->param_begin();
}
-CallEvent::param_iterator AnyFunctionCall::param_end() const {
- const FunctionDecl *D = getDecl();
+CallEvent::param_iterator
+AnyFunctionCall::param_end(bool UseDefinitionParams) const {
+ const Decl *D = UseDefinitionParams ? getDefinition() : getDecl();
if (!D)
return 0;
- return D->param_end();
+ return cast<FunctionDecl>(D)->param_end();
}
QualType AnyFunctionCall::getDeclaredResultType() const {
@@ -309,23 +311,31 @@ const FunctionDecl *SimpleCall::getDecl() const {
}
-void CXXMemberCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+SVal CXXMemberCall::getCXXThisVal() const {
const Expr *Base = getOriginExpr()->getImplicitObjectArgument();
// FIXME: Will eventually need to cope with member pointers. This is
// a limitation in getImplicitObjectArgument().
if (!Base)
- return;
-
- if (const MemRegion *R = getSVal(Base).getAsRegion())
+ return UnknownVal();
+
+ return getSVal(Base);
+}
+
+void CXXMemberCall::addExtraInvalidatedRegions(RegionList &Regions) const {
+ if (const MemRegion *R = getCXXThisVal().getAsRegion())
Regions.push_back(R);
}
+SVal CXXMemberOperatorCall::getCXXThisVal() const {
+ const Expr *Base = getOriginExpr()->getArg(0);
+ return getSVal(Base);
+}
+
void
CXXMemberOperatorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
- const Expr *Base = getOriginExpr()->getArg(0);
- if (const MemRegion *R = getSVal(Base).getAsRegion())
+ if (const MemRegion *R = getCXXThisVal().getAsRegion())
Regions.push_back(R);
}
@@ -337,14 +347,22 @@ const BlockDataRegion *BlockCall::getBlockRegion() const {
return dyn_cast_or_null<BlockDataRegion>(DataReg);
}
-CallEvent::param_iterator BlockCall::param_begin() const {
+CallEvent::param_iterator
+BlockCall::param_begin(bool UseDefinitionParams) const {
+ // Blocks don't have distinct declarations and definitions.
+ (void)UseDefinitionParams;
+
const BlockDecl *D = getBlockDecl();
if (!D)
return 0;
return D->param_begin();
}
-CallEvent::param_iterator BlockCall::param_end() const {
+CallEvent::param_iterator
+BlockCall::param_end(bool UseDefinitionParams) const {
+ // Blocks don't have distinct declarations and definitions.
+ (void)UseDefinitionParams;
+
const BlockDecl *D = getBlockDecl();
if (!D)
return 0;
@@ -366,32 +384,46 @@ QualType BlockCall::getDeclaredResultType() const {
}
+SVal CXXConstructorCall::getCXXThisVal() const {
+ if (Target)
+ return loc::MemRegionVal(Target);
+ return UnknownVal();
+}
+
void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
if (Target)
Regions.push_back(Target);
}
+SVal CXXDestructorCall::getCXXThisVal() const {
+ if (Target)
+ return loc::MemRegionVal(Target);
+ return UnknownVal();
+}
+
void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const {
if (Target)
Regions.push_back(Target);
}
-CallEvent::param_iterator ObjCMethodCall::param_begin() const {
- const ObjCMethodDecl *D = getDecl();
+CallEvent::param_iterator
+ObjCMethodCall::param_begin(bool UseDefinitionParams) const {
+ const Decl *D = UseDefinitionParams ? getDefinition() : getDecl();
if (!D)
return 0;
- return D->param_begin();
+ return cast<ObjCMethodDecl>(D)->param_begin();
}
-CallEvent::param_iterator ObjCMethodCall::param_end() const {
- const ObjCMethodDecl *D = getDecl();
+CallEvent::param_iterator
+ObjCMethodCall::param_end(bool UseDefinitionParams) const {
+ const Decl *D = UseDefinitionParams ? getDefinition() : getDecl();
if (!D)
return 0;
- return D->param_end();
+ return cast<ObjCMethodDecl>(D)->param_end();
}
void
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 92497dbb1e3..2b47bc064da 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -55,11 +55,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Construct an edge representing the starting location in the callee.
BlockEdge Loc(Entry, Succ, calleeCtx);
- // Construct a new state which contains the mapping from actual to
- // formal arguments.
- const LocationContext *callerCtx = Pred->getLocationContext();
- ProgramStateRef state = Pred->getState()->enterStackFrame(callerCtx,
- calleeCtx);
+ ProgramStateRef state = Pred->getState();
// Construct a new node and add it to the worklist.
bool isNew;
@@ -287,14 +283,9 @@ bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
switch (Call.getKind()) {
case CE_Function:
case CE_CXXMember:
+ case CE_CXXMemberOperator:
// These are always at least possible to inline.
break;
- case CE_CXXMemberOperator:
- // FIXME: This should be possible to inline, but
- // RegionStore::enterStackFrame isn't smart enough to handle the first
- // argument being 'this'. The correct solution is to use CallEvent in
- // enterStackFrame as well.
- return false;
case CE_CXXConstructor:
case CE_CXXDestructor:
// Do not inline constructors until we can really model destructors.
@@ -337,8 +328,13 @@ bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
currentStmtIdx);
CallEnter Loc(CallE, CalleeSFC, Pred->getLocationContext());
+
+ // Construct a new state which contains the mapping from actual to
+ // formal arguments.
+ ProgramStateRef State = Pred->getState()->enterStackFrame(Call, CalleeSFC);
+
bool isNew;
- if (ExplodedNode *N = G.getNode(Loc, Pred->getState(), false, &isNew)) {
+ if (ExplodedNode *N = G.getNode(Loc, State, false, &isNew)) {
N->addPredecessor(Pred, G);
if (isNew)
Engine.getWorkList()->enqueue(N);
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index d7668dec1a9..529be0a845f 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -203,11 +203,11 @@ ProgramStateRef ProgramState::unbindLoc(Loc LV) const {
}
ProgramStateRef
-ProgramState::enterStackFrame(const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx) const {
- const StoreRef &new_store =
- getStateManager().StoreMgr->enterStackFrame(this, callerCtx, calleeCtx);
- return makeWithStore(new_store);
+ProgramState::enterStackFrame(const CallEvent &Call,
+ const StackFrameContext *CalleeCtx) const {
+ const StoreRef &NewStore =
+ getStateManager().StoreMgr->enterStackFrame(getStore(), Call, CalleeCtx);
+ return makeWithStore(NewStore);
}
SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const {
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index fa26c132039..c084bd2ad0d 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -389,16 +389,6 @@ public: // Part of public interface to class.
/// It returns a new Store with these values removed.
StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
-
- StoreRef enterStackFrame(ProgramStateRef state,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx);
-
- StoreRef enterStackFrame(ProgramStateRef state,
- const FunctionDecl *FD,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx);
-
//===------------------------------------------------------------------===//
// Region "extents".
@@ -2066,84 +2056,6 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
return StoreRef(B.getRootWithoutRetain(), *this);
}
-StoreRef RegionStoreManager::enterStackFrame(ProgramStateRef state,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx)
-{
- const Decl *D = calleeCtx->getDecl();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return enterStackFrame(state, FD, callerCtx, calleeCtx);
-
- // FIXME: when we handle more cases, this will need to be expanded.
-
- const BlockDecl *BD = cast<BlockDecl>(D);
- BlockDecl::param_const_iterator PI = BD->param_begin(),
- PE = BD->param_end();
- StoreRef store = StoreRef(state->getStore(), *this);
- const CallExpr *CE = cast<CallExpr>(calleeCtx->getCallSite());
- CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
- for (; AI != AE && PI != PE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI, callerCtx);
- store = Bind(store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
- ArgVal);
- }
-
- return store;
-}
-
-StoreRef RegionStoreManager::enterStackFrame(ProgramStateRef state,
- const FunctionDecl *FD,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx)
-{
- FunctionDecl::param_const_iterator PI = FD->param_begin(),
- PE = FD->param_end();
- StoreRef store = StoreRef(state->getStore(), *this);
-
- if (CallExpr const *CE = dyn_cast<CallExpr>(calleeCtx->getCallSite())) {
- CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
-
- // Copy the arg expression value to the arg variables. We check that
- // PI != PE because the actual number of arguments may be different than
- // the function declaration.
- for (; AI != AE && PI != PE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI, callerCtx);
- store = Bind(store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
- ArgVal);
- }
-
- // For C++ method calls, also include the 'this' pointer.
- if (const CXXMemberCallExpr *CME = dyn_cast<CXXMemberCallExpr>(CE)) {
- loc::MemRegionVal This =
- svalBuilder.getCXXThis(cast<CXXMethodDecl>(CME->getCalleeDecl()),
- calleeCtx);
- SVal CalledObj = state->getSVal(CME->getImplicitObjectArgument(),
- callerCtx);
- store = Bind(store.getStore(), This, CalledObj);
- }
- }
- else if (const CXXConstructExpr *CE =
- dyn_cast<CXXConstructExpr>(calleeCtx->getCallSite())) {
- CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(),
- AE = CE->arg_end();
-
- // Copy the arg expression value to the arg variables.
- for (; AI != AE; ++AI, ++PI) {
- SVal ArgVal = state->getSVal(*AI, callerCtx);
- store = Bind(store.getStore(),
- svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
- ArgVal);
- }
- }
- else {
- assert(isa<CXXDestructorDecl>(calleeCtx->getDecl()));
- }
-
- return store;
-}
-
//===----------------------------------------------------------------------===//
// Utility methods.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 11748ae54db..d5c88e8ad81 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -23,10 +24,36 @@ StoreManager::StoreManager(ProgramStateManager &stateMgr)
: svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr),
MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {}
-StoreRef StoreManager::enterStackFrame(ProgramStateRef state,
- const LocationContext *callerCtx,
- const StackFrameContext *calleeCtx) {
- return StoreRef(state->getStore(), *this);
+StoreRef StoreManager::enterStackFrame(Store OldStore,
+ const CallEvent &Call,
+ const StackFrameContext *LCtx) {
+ StoreRef Store = StoreRef(OldStore, *this);
+
+ unsigned Idx = 0;
+ for (CallEvent::param_iterator I = Call.param_begin(/*UseDefinition=*/true),
+ E = Call.param_end(/*UseDefinition=*/true);
+ I != E; ++I, ++Idx) {
+ const ParmVarDecl *Decl = *I;
+ assert(Decl && "Formal parameter has no decl?");
+
+ SVal ArgVal = Call.getArgSVal(Idx);
+ if (!ArgVal.isUnknown()) {
+ Store = Bind(Store.getStore(),
+ svalBuilder.makeLoc(MRMgr.getVarRegion(Decl, LCtx)),
+ ArgVal);
+ }
+ }
+
+ // FIXME: We will eventually want to generalize this to handle other non-
+ // parameter arguments besides 'this' (such as 'self' for ObjC methods).
+ SVal ThisVal = Call.getCXXThisVal();
+ if (!ThisVal.isUndef()) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(Call.getDecl());
+ loc::MemRegionVal ThisRegion = svalBuilder.getCXXThis(MD, LCtx);
+ Store = Bind(Store.getStore(), ThisRegion, ThisVal);
+ }
+
+ return Store;
}
const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
OpenPOWER on IntegriCloud