Added boilerplate transfer function support for CallExprs.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47298 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Analysis/GRExprEngine.cpp b/Analysis/GRExprEngine.cpp
index 09ffcd4..4ea7819 100644
--- a/Analysis/GRExprEngine.cpp
+++ b/Analysis/GRExprEngine.cpp
@@ -259,7 +259,7 @@
do {
nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1));
- NonLValue Res = EvalBinaryOp(ValMgr, BinaryOperator::EQ, CondV, CaseVal);
+ NonLValue Res = EvalBinaryOp(BinaryOperator::EQ, CondV, CaseVal);
// Now "assume" that the case matches.
bool isFeasible = false;
@@ -407,12 +407,51 @@
Nodify(Dst, D, Pred, SetValue(St, D, GetValue(St, D)));
}
+void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred,
+ CallExpr::arg_iterator I, CallExpr::arg_iterator E,
+ NodeSet& Dst) {
+
+ if (I != E) {
+ NodeSet DstTmp;
+ Visit(*I, Pred, DstTmp);
+ ++I;
+
+ for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI)
+ VisitCall(CE, *DI, I, E, Dst);
+
+ return;
+ }
+
+ // If we reach here we have processed all of the arguments. Evaluate
+ // the callee expression.
+ NodeSet DstTmp;
+ Visit(CE->getCallee(), Pred, DstTmp);
+
+ // Finally, evaluate the function call.
+ for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) {
+ StateTy St = (*DI)->getState();
+ LValue L = GetLValue(St, CE->getCallee());
+
+ // Check for uninitialized control-flow.
+ if (isa<UninitializedVal>(L)) {
+ NodeTy* N = Builder->generateNode(CE, St, *DI);
+ N->markAsSink();
+ UninitBranches.insert(N);
+ continue;
+ }
+
+ // Note: EvalCall must handle the case where the callee is "UnknownVal."
+ Nodify(Dst, CE, *DI, EvalCall(CE, (*DI)->getState()));
+ }
+}
+
void GRExprEngine::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) {
QualType T = CastE->getType();
// Check for redundant casts.
- if (E->getType() == T) {
+ if (E->getType() == T ||
+ (T->isPointerType() && E->getType()->isFunctionType())) {
Dst.Add(Pred);
return;
}
@@ -515,7 +554,7 @@
BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
: BinaryOperator::Sub;
- RValue Result = EvalBinaryOp(ValMgr, Op, R1, GetRValueConstant(1U, U));
+ RValue Result = EvalBinaryOp(Op, R1, GetRValueConstant(1U, U));
if (U->isPostfix())
Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result));
@@ -553,14 +592,14 @@
const LValue& L1 = cast<LValue>(V1);
lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
Nodify(Dst, U, N1,
- SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ,
+ SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ,
L1, V2)));
}
else {
const NonLValue& R1 = cast<NonLValue>(V1);
nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth());
Nodify(Dst, U, N1,
- SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ,
+ SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ,
R1, V2)));
}
@@ -705,7 +744,7 @@
continue;
}
- Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(ValMgr, Op, V1, V2)));
+ Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(Op, V1, V2)));
continue;
}
@@ -742,14 +781,14 @@
if (B->getType()->isPointerType()) { // Perform pointer arithmetic.
const NonLValue& R2 = cast<NonLValue>(V2);
- Result = EvalBinaryOp(ValMgr, Op, L1, R2);
+ Result = EvalBinaryOp(Op, L1, R2);
}
else if (isa<LValue>(V2)) {
const LValue& L2 = cast<LValue>(V2);
if (B->getRHS()->getType()->isPointerType()) {
// LValue comparison.
- Result = EvalBinaryOp(ValMgr, Op, L1, L2);
+ Result = EvalBinaryOp(Op, L1, L2);
}
else {
QualType T1 = B->getLHS()->getType();
@@ -757,7 +796,7 @@
// An operation between two variables of a non-lvalue type.
Result =
- EvalBinaryOp(ValMgr, Op,
+ EvalBinaryOp(Op,
cast<NonLValue>(GetValue(N1->getState(), L1, &T1)),
cast<NonLValue>(GetValue(N2->getState(), L2, &T2)));
}
@@ -767,7 +806,7 @@
const NonLValue& R1 = cast<NonLValue>(GetValue(N1->getState(),
L1, &T));
const NonLValue& R2 = cast<NonLValue>(V2);
- Result = EvalBinaryOp(ValMgr, Op, R1, R2);
+ Result = EvalBinaryOp(Op, R1, R2);
}
Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result));
@@ -821,6 +860,12 @@
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
break;
}
+
+ case Stmt::CallExprClass: {
+ CallExpr* C = cast<CallExpr>(S);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ break;
+ }
case Stmt::CastExprClass: {
CastExpr* C = cast<CastExpr>(S);
diff --git a/Analysis/RValues.cpp b/Analysis/RValues.cpp
index c8a4dfa..0fc03dd 100644
--- a/Analysis/RValues.cpp
+++ b/Analysis/RValues.cpp
@@ -342,7 +342,12 @@
case lval::DeclValKind:
Out << '&'
- << cast<lval::DeclVal>(this)->getDecl()->getIdentifier()->getName();
+ << cast<lval::DeclVal>(this)->getDecl()->getIdentifier()->getName();
+ break;
+
+ case lval::FuncValKind:
+ Out << "function "
+ << cast<lval::FuncVal>(this)->getDecl()->getIdentifier()->getName();
break;
default:
diff --git a/Analysis/ValueState.cpp b/Analysis/ValueState.cpp
index 32be0c6..0f29def 100644
--- a/Analysis/ValueState.cpp
+++ b/Analysis/ValueState.cpp
@@ -220,6 +220,8 @@
// a better way, since APInts are fairly lightweight.
return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal()));
}
+ else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
+ return lval::FuncVal(FD);
assert (false &&
"ValueDecl support for this ValueDecl not implemented.");
@@ -248,7 +250,10 @@
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr* C = cast<ImplicitCastExpr>(E);
- if (C->getType() == C->getSubExpr()->getType()) {
+ QualType CT = C->getType();
+ QualType ST = C->getSubExpr()->getType();
+
+ if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
E = C->getSubExpr();
continue;
}
@@ -257,7 +262,10 @@
case Stmt::CastExprClass: {
CastExpr* C = cast<CastExpr>(E);
- if (C->getType() == C->getSubExpr()->getType()) {
+ QualType CT = C->getType();
+ QualType ST = C->getSubExpr()->getType();
+
+ if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) {
E = C->getSubExpr();
continue;
}
@@ -297,8 +305,14 @@
while (ParenExpr* P = dyn_cast<ParenExpr>(E))
E = P->getSubExpr();
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
- return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
+ if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
+ ValueDecl* VD = DR->getDecl();
+
+ if (FunctionDecl* FD = dyn_cast<FunctionDecl>(VD))
+ return lval::FuncVal(FD);
+ else
+ return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
+ }
if (UnaryOperator* U = dyn_cast<UnaryOperator>(E))
if (U->getOpcode() == UnaryOperator::Deref)