aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CallEvent.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-30 23:39:47 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-30 23:39:47 +0000
commit57c033621dacd8720ac9ff65a09025f14f70e22f (patch)
treef5ddbd4787a29c32786be7b60c4b5130759734d5 /lib/StaticAnalyzer/Core/CallEvent.cpp
parentd64effc4e31044c05d6e4400150edb26e914983a (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.cpp57
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);
+}
+