diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-07-10 22:07:57 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-07-10 22:07:57 +0000 |
commit | e54cfc7b9990acffd0a8a4ba381717b4bb9f3011 (patch) | |
tree | 2b1073b5acf22805d099103511a4746f23c79901 /lib | |
parent | 852aa0d2c5d2d1faf2d77b5aa3c0848068a342c5 (diff) |
[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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160022 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/StaticAnalyzer/Core/Calls.cpp | 72 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 20 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ProgramState.cpp | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 88 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/Store.cpp | 35 |
5 files changed, 96 insertions, 129 deletions
diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp index 8ea1336bb7..ced1154da7 100644 --- a/lib/StaticAnalyzer/Core/Calls.cpp +++ b/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/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 92497dbb1e..2b47bc064d 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/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/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index d7668dec1a..529be0a845 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/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/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index fa26c13203..c084bd2ad0 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/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/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 11748ae54d..d5c88e8ad8 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/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, |