summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-12-18 20:13:39 +0000
committerTed Kremenek <kremenek@apple.com>2009-12-18 20:13:39 +0000
commit53287518f69b8f06f82a6cdbd13e4e3a13b58186 (patch)
treeed4668c21c79b378704b7fdea3675cad5764fd7f
parent5231eaa5f58c49860d5446d5269685cd9c063ccb (diff)
downloadclang-53287518f69b8f06f82a6cdbd13e4e3a13b58186.tar.gz
Enhance GRExprEngine::VisitCallExpr() to be used in an lvalue context. Uncovered a new failing test case along the way, but we're making progress on handling C++ references in the analyzer.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91710 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h2
-rw-r--r--lib/Analysis/GRExprEngine.cpp57
-rw-r--r--test/Analysis/misc-ps-region-store.cpp8
3 files changed, 60 insertions, 7 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index 6c422edff9..21031a488e 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -265,7 +265,7 @@ protected:
/// VisitCall - Transfer function for function calls.
void VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
- ExplodedNodeSet& Dst);
+ ExplodedNodeSet& Dst, bool asLValue);
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 9b00d1e64a..4295e9a1ae 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -46,6 +46,23 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
return Ctx.Selectors.getSelector(0, &II);
}
+static bool CalleeReturnsReference(const CallExpr *CE) {
+ const Expr *Callee = CE->getCallee();
+ QualType T = Callee->getType();
+
+
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
+ T = FT->getResultType();
+ }
+ else {
+ const BlockPointerType *BT = T->getAs<BlockPointerType>();
+ T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
+ }
+
+ return T->isReferenceType();
+}
+
//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
//===----------------------------------------------------------------------===//
@@ -228,7 +245,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
}
-
+
void *tag = I->first;
Checker *checker = I->second;
@@ -593,7 +610,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass: {
CallExpr* C = cast<CallExpr>(S);
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false);
break;
}
@@ -745,6 +762,14 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true);
return;
+ case Stmt::CallExprClass:
+ case Stmt::CXXOperatorCallExprClass: {
+ CallExpr* C = cast<CallExpr>(Ex);
+ assert(CalleeReturnsReference(C));
+ VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
+ break;
+ }
+
case Stmt::CompoundLiteralExprClass:
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true);
return;
@@ -1563,7 +1588,7 @@ public:
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
- ExplodedNodeSet& Dst) {
+ ExplodedNodeSet& Dst, bool asLValue) {
// Determine the type of function we're calling (if available).
const FunctionProtoType *Proto = NULL;
@@ -1577,7 +1602,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
WorkList.push_back(CallExprWLItem(AI, Pred));
ExplodedNodeSet ArgsEvaluated;
-
+
while (!WorkList.empty()) {
CallExprWLItem Item = WorkList.back();
WorkList.pop_back();
@@ -1623,6 +1648,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
// Finally, evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet DstTmp3;
+
for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
DI != DE; ++DI) {
@@ -1664,7 +1690,28 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
- CheckerVisit(CE, Dst, DstTmp3, false);
+
+ if (!(!asLValue && CalleeReturnsReference(CE))) {
+ CheckerVisit(CE, Dst, DstTmp3, false);
+ return;
+ }
+
+ // Handle the case where the called function returns a reference but
+ // we expect an rvalue. For such cases, convert the reference to
+ // an rvalue.
+ // FIXME: This conversion doesn't actually happen unless the result
+ // of CallExpr is consumed by another expression.
+ ExplodedNodeSet DstTmp4;
+ CheckerVisit(CE, DstTmp4, DstTmp3, false);
+ QualType LoadTy = CE->getType();
+
+ static int *ConvertToRvalueTag = 0;
+ for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end();
+ NI!=NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ EvalLoad(Dst, CE, *NI, state, state->getSVal(CE),
+ &ConvertToRvalueTag, LoadTy);
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index c1e03bb0d9..838ac39d5c 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -2,8 +2,14 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
// XFAIL: *
-// This test case currently crashes because of an assertion failure.
+// Test basic handling of references.
char &test1_aux();
char *test1() {
return &test1_aux();
}
+
+// This test currently crasehs because test1_aux() evaluates to a 'char' instead of a char& in CFRefCount.cpp.
+char test1_as_rvalue() {
+ return test1_aux();
+}
+