aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-03-30 17:41:19 +0000
committerTed Kremenek <kremenek@apple.com>2011-03-30 17:41:19 +0000
commitb277159055933e610bbc80262b600d3ad7e0595c (patch)
tree2c3f46daf5f1c71ba97933bb3f12a5b706571d3a /lib/StaticAnalyzer/Core/CXXExprEngine.cpp
parent61750f2bed7f5c0e440318841e3be385920b22f3 (diff)
Begin reworking static analyzer support for C++ method calls. The current logic was divorced
from how we process ordinary function calls, had a tremendous about of redundancy, and relied strictly on inlining behavior (which was incomplete) to provide semantics instead of falling back to the conservative analysis we use for C functions. This is a significant step into making C++ analyzer support more useful. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128557 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/CXXExprEngine.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp111
1 files changed, 28 insertions, 83 deletions
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index a71761dab8..b015d4f264 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -62,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
}
}
+void ExprEngine::evalCallee(const CallExpr *callExpr,
+ const ExplodedNodeSet &src,
+ ExplodedNodeSet &dest) {
+
+ const Expr *callee = 0;
+
+ switch (callExpr->getStmtClass()) {
+ case Stmt::CXXMemberCallExprClass: {
+ // Evaluate the implicit object argument that is the recipient of the
+ // call.
+ callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument();
+
+ // FIXME: handle member pointers.
+ if (!callee)
+ return;
+
+ break;
+ }
+ default: {
+ callee = callExpr->getCallee()->IgnoreParens();
+ break;
+ }
+ }
+
+ for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i)
+ Visit(callee, *i, dest);
+}
+
const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
const StackFrameContext *SFC) {
const Type *T = D->getTypeForDecl();
@@ -169,89 +197,6 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
Dst.Add(N);
}
-void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- ExplodedNodeSet argsEvaluated;
- evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated);
-
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllargsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = argsEvaluated.begin(),
- E = argsEvaluated.end(); I != E; ++I) {
- Visit(ObjArgExpr, *I, AllargsEvaluated);
- }
-
- // Now evaluate the call itself.
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
- evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst);
-}
-
-void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl());
- if (!MD) {
- // If the operator doesn't represent a method call treat as regular call.
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
- return;
- }
-
- // Determine the type of function we're calling (if available).
- const FunctionProtoType *Proto = NULL;
- QualType FnType = C->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
- Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
- // Evaluate arguments treating the first one (object method is called on)
- // as alvalue.
- ExplodedNodeSet argsEvaluated;
- evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true);
-
- // Now evaluate the call itself.
- evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst);
-}
-
-void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
- const Expr *ThisExpr, ExplodedNode *Pred,
- ExplodedNodeSet &Src, ExplodedNodeSet &Dst) {
- // Allow checkers to pre-visit the member call.
- ExplodedNodeSet PreVisitChecks;
- getCheckerManager().runCheckersForPreStmt(PreVisitChecks, Src, MCE, *this);
-
- if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) {
- // FIXME: conservative method call evaluation.
- getCheckerManager().runCheckersForPostStmt(Dst, PreVisitChecks, MCE, *this);
- return;
- }
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, SFC, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(),
- E = PreVisitChecks.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr));
- Dst.Add(Builder->generateNode(Loc, state, *I));
- }
-}
-
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
if (CNE->isArray()) {