diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-07-30 23:39:47 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-07-30 23:39:47 +0000 |
commit | 57c033621dacd8720ac9ff65a09025f14f70e22f (patch) | |
tree | f5ddbd4787a29c32786be7b60c4b5130759734d5 /lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | d64effc4e31044c05d6e4400150edb26e914983a (diff) |
[analyzer] Perform post-call checks for all inlined calls.
Previously, we were only checking the origin expressions of inlined calls.
Checkers using the generic postCall and older postObjCMessage callbacks were
ignored. Now that we have CallEventManager, it is much easier to create
a CallEvent generically when exiting an inlined function, which we can then
use for post-call checks.
No test case because we don't (yet) have any checkers that depend on this
behavior (which is why it hadn't been fixed before now).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161005 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 6a5d0f0fa9..ad5a104aa0 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -641,3 +641,60 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State, // something we can't reason about. return create<FunctionCall>(CE, State, LCtx); } + + +CallEventRef<> +CallEventManager::getCaller(const StackFrameContext *CalleeCtx, + ProgramStateRef State) { + const LocationContext *ParentCtx = CalleeCtx->getParent(); + const LocationContext *CallerCtx = ParentCtx->getCurrentStackFrame(); + assert(CallerCtx && "This should not be used for top-level stack frames"); + + const Stmt *CallSite = CalleeCtx->getCallSite(); + + if (CallSite) { + if (const CallExpr *CE = dyn_cast<CallExpr>(CallSite)) + return getSimpleCall(CE, State, CallerCtx); + + switch (CallSite->getStmtClass()) { + case Stmt::CXXConstructExprClass: { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl()); + Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx); + SVal ThisVal = State->getSVal(ThisPtr); + + return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite), + ThisVal.getAsRegion(), State, CallerCtx); + } + case Stmt::CXXNewExprClass: + return getCXXAllocatorCall(cast<CXXNewExpr>(CallSite), State, CallerCtx); + case Stmt::ObjCMessageExprClass: + return getObjCMethodCall(cast<ObjCMessageExpr>(CallSite), + State, CallerCtx); + default: + llvm_unreachable("This is not an inlineable statement."); + } + } + + // Fall back to the CFG. The only thing we haven't handled yet is + // destructors, though this could change in the future. + const CFGBlock *B = CalleeCtx->getCallSiteBlock(); + CFGElement E = (*B)[CalleeCtx->getIndex()]; + assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs"); + assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet"); + + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl()); + Loc ThisPtr = SVB.getCXXThis(Dtor, CalleeCtx); + SVal ThisVal = State->getSVal(ThisPtr); + + const Stmt *Trigger; + if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E)) + Trigger = AutoDtor->getTriggerStmt(); + else + Trigger = Dtor->getBody(); + + return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(), + State, CallerCtx); +} + |