kromanenkov updated this revision to Diff 77041.
kromanenkov added a comment.
According to dcoughlin suggestion PointerToMember SVal is now modeled as a
PointerUnion of DeclaratorDecl and bump pointer-allocated object stored
DeclaratorDecl and immutable linked list of CXXBaseSpecifiers.
https://reviews.llvm.org/D25475
Files:
include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
lib/StaticAnalyzer/Core/BasicValueFactory.cpp
lib/StaticAnalyzer/Core/ExprEngineC.cpp
lib/StaticAnalyzer/Core/SValBuilder.cpp
lib/StaticAnalyzer/Core/SVals.cpp
lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
test/Analysis/pointer-to-member.cpp
Index: test/Analysis/pointer-to-member.cpp
===================================================================
--- test/Analysis/pointer-to-member.cpp
+++ test/Analysis/pointer-to-member.cpp
@@ -35,8 +35,7 @@
clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}}
clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}}
- // FIXME: Should be TRUE.
- clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}}
}
namespace PR15742 {
@@ -62,21 +61,114 @@
}
}
-// ---------------
-// FALSE NEGATIVES
-// ---------------
-
bool testDereferencing() {
A obj;
obj.m_ptr = 0;
A::MemberPointer member = &A::m_ptr;
- // FIXME: Should be TRUE.
- clang_analyzer_eval(obj.*member == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}}
member = 0;
- // FIXME: Should emit a null dereference.
- return obj.*member; // no-warning
+ return obj.*member; // expected-warning{{}}
+}
+
+namespace testPointerToMemberFunction {
+ struct A {
+ virtual int foo() { return 1; }
+ int bar() { return 2; }
+ };
+
+ struct B : public A {
+ virtual int foo() { return 3; }
+ };
+
+ typedef int (A::*AFnPointer)();
+ typedef int (B::*BFnPointer)();
+
+ void testPointerToMemberCasts() {
+ AFnPointer AFP = &A::bar;
+ BFnPointer StaticCastedBase2Derived = static_cast<BFnPointer>(&A::bar),
+ CCastedBase2Derived = (BFnPointer) (&A::bar);
+ A a;
+ B b;
+
+ clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}}
+ }
+
+ void testPointerToMemberVirtualCall() {
+ A a;
+ B b;
+ A *APtr = &a;
+ AFnPointer AFP = &A::foo;
+
+ clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}}
+
+ APtr = &b;
+
+ clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}}
+ }
+} // end of testPointerToMemberFunction namespace
+
+namespace testPointerToMemberData {
+ struct A {
+ int i;
+ };
+
+ void testPointerToMemberData() {
+ int A::*AMdPointer = &A::i;
+ A a;
+
+ a.i = 42;
+ a.*AMdPointer += 1;
+
+ clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}}
+ }
+} // end of testPointerToMemberData namespace
+
+namespace testPointerToMemberMiscCasts {
+struct B {
+ int f;
+};
+
+struct D : public B {
+ int g;
+};
+
+void foo() {
+ D d;
+ d.f = 7;
+
+ int B::* pfb = &B::f;
+ int D::* pfd = pfb;
+ int v = d.*pfd;
+
+ clang_analyzer_eval(v == 7); // expected-warning{{TRUE}}
+}
+} // end of testPointerToMember namespace
+
+namespace testPointerToMemberMiscCasts2 {
+struct B {
+ int f;
+};
+struct L : public B { };
+struct R : public B { };
+struct D : public L, R { };
+
+void foo() {
+ D d;
+
+ int B::* pb = &B::f;
+ int L::* pl = pb;
+ int R::* pr = pb;
+
+ int D::* pdl = pl;
+ int D::* pdr = pr;
+
+ clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}}
+ clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}}
}
+} // end of testPointerToMemberMiscCasts2 namespace
Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -69,6 +69,9 @@
bool isLocType = Loc::isLocType(castTy);
+ if (val.getAs<nonloc::PointerToMember>())
+ return val;
+
if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) {
if (isLocType)
return LI->getLoc();
@@ -335,6 +338,21 @@
switch (lhs.getSubKind()) {
default:
return makeSymExprValNN(state, op, lhs, rhs, resultTy);
+ case nonloc::PointerToMemberKind: {
+ assert(rhs.getSubKind() == nonloc::PointerToMemberKind &&
+ "Both SVals should have pointer-to-member-type");
+ auto LPTM = lhs.castAs<nonloc::PointerToMember>(),
+ RPTM = rhs.castAs<nonloc::PointerToMember>();
+ auto LPTMD = LPTM.getPTMData(), RPTMD = RPTM.getPTMData();
+ switch (op) {
+ case BO_EQ:
+ return makeTruthVal(LPTMD == RPTMD, resultTy);
+ case BO_NE:
+ return makeTruthVal(LPTMD != RPTMD, resultTy);
+ default:
+ return UnknownVal();
+ }
+ }
case nonloc::LocAsIntegerKind: {
Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
switch (rhs.getSubKind()) {
@@ -857,6 +875,17 @@
SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
BinaryOperator::Opcode op,
Loc lhs, NonLoc rhs, QualType resultTy) {
+ if (op >= BO_PtrMemD && op <= BO_PtrMemI) {
+ if (auto PTMSV = rhs.getAs<nonloc::PointerToMember>()) {
+ if (PTMSV->isNullMemberPointer())
+ return UndefinedVal();
+ if (const FieldDecl *FD = PTMSV->getDeclAs<FieldDecl>())
+ return state->getLValue(FD, lhs);
+ }
+
+ return rhs;
+ }
+
assert(!BinaryOperator::isComparisonOp(op) &&
"arguments to comparison ops must be of the same type");
Index: lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -184,6 +184,12 @@
return isFeasible ? state : nullptr;
}
+ case nonloc::PointerToMemberKind: {
+ bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer();
+ bool IsFeasible = IsNull ? Assumption : !Assumption;
+ return IsFeasible ? state : nullptr;
+ }
+
case nonloc::LocAsIntegerKind:
return assume(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
Assumption);
Index: lib/StaticAnalyzer/Core/SVals.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SVals.cpp
+++ lib/StaticAnalyzer/Core/SVals.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/Support/raw_ostream.h"
+#include "clang/AST/DeclCXX.h"
using namespace clang;
using namespace ento;
using llvm::APSInt;
@@ -56,6 +57,10 @@
return FD;
}
+ if (auto X = getAs<nonloc::PointerToMember>()) {
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl()))
+ return MD;
+ }
return nullptr;
}
@@ -155,6 +160,20 @@
return static_cast<const LazyCompoundValData*>(Data)->getRegion();
}
+const DeclaratorDecl *nonloc::PointerToMember::getDecl() const {
+ const auto PTMD = this->getPTMData();
+ if (PTMD.isNull())
+ return nullptr;
+
+ const DeclaratorDecl *DD = nullptr;
+ if (PTMD.is<const DeclaratorDecl *>())
+ DD = PTMD.get<const DeclaratorDecl *>();
+ else
+ DD = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
+
+ return DD;
+}
+
//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//
@@ -167,6 +186,20 @@
return getValue()->end();
}
+nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
+ const PTMDataType PTMD = getPTMData();
+ if (PTMD.is<const DeclaratorDecl *>())
+ return nonloc::PointerToMember::iterator();
+ return PTMD.get<const PointerToMemberData *>()->begin();
+}
+
+nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
+ const PTMDataType PTMD = getPTMData();
+ if (PTMD.is<const DeclaratorDecl *>())
+ return nonloc::PointerToMember::iterator();
+ return PTMD.get<const PointerToMemberData *>()->end();
+}
+
//===----------------------------------------------------------------------===//
// Useful predicates.
//===----------------------------------------------------------------------===//
@@ -299,6 +332,26 @@
<< '}';
break;
}
+ case nonloc::PointerToMemberKind: {
+ os << "pointerToMember{";
+ const nonloc::PointerToMember &CastRes =
+ castAs<nonloc::PointerToMember>();
+ if (CastRes.getDecl())
+ os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
+ bool first = true;
+ for (const auto &I : CastRes) {
+ if (first) {
+ os << ' '; first = false;
+ }
+ else
+ os << ", ";
+
+ os << (*I).getType().getAsString();
+ }
+
+ os << '}';
+ break;
+ }
default:
assert (false && "Pretty-printed not implemented for this NonLoc.");
break;
Index: lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -214,6 +214,10 @@
return nonloc::SymbolVal(sym);
}
+DefinedSVal SValBuilder::getMemberPointer(const DeclaratorDecl* DD) {
+ return nonloc::PointerToMember(DD);
+}
+
DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
return loc::MemRegionVal(MemMgr.getFunctionCodeRegion(func));
}
@@ -291,6 +295,18 @@
case Stmt::CXXNullPtrLiteralExprClass:
return makeNull();
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UO = dyn_cast<UnaryOperator>(E);
+ if (const DeclRefExpr *DRE =
+ dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParenCasts())) {
+ if (const DeclaratorDecl *DD =
+ dyn_cast_or_null<DeclaratorDecl>(DRE->getDecl()))
+ if (isa<CXXMethodDecl>(DD) || isa<FieldDecl>(DD))
+ return getMemberPointer(DD);
+ }
+ return None;
+ }
+
case Stmt::ImplicitCastExprClass: {
const CastExpr *CE = cast<CastExpr>(E);
switch (CE->getCastKind()) {
Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -310,17 +311,32 @@
continue;
}
case CK_MemberPointerToBoolean:
- // FIXME: For now, member pointers are represented by void *.
- // FALLTHROUGH
+ case CK_PointerToBoolean: {
+ SVal V = state->getSVal(Ex, LCtx);
+ auto PTMSV = V.getAs<nonloc::PointerToMember>();
+ if (PTMSV)
+ V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy);
+ if (V.isUndef() || PTMSV) {
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ }
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
case CK_AddressSpaceConversion:
case CK_BooleanToSignedIntegral:
case CK_NullToPointer:
case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
+ case CK_PointerToIntegral: {
+ SVal V = state->getSVal(Ex, LCtx);
+ if (V.getAs<nonloc::PointerToMember>()) {
+ state = state->BindExpr(CastE, LCtx, UnknownVal());
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ }
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
@@ -435,17 +451,28 @@
continue;
}
case CK_NullToMemberPointer: {
- // FIXME: For now, member pointers are represented by void *.
- SVal V = svalBuilder.makeNull();
+ SVal V = svalBuilder.getMemberPointer(nullptr);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
}
+ case CK_DerivedToBaseMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_ReinterpretMemberPointer: {
+ SVal V = state->getSVal(CastE->getSubExpr(), LCtx);
+ if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
+ SVal CastedPTMSV = svalBuilder.makePointerToMember(
+ getBasicVals().accumCXXBase(
+ llvm::make_range<CastExpr::path_const_iterator>(
+ CastE->path_begin(), CastE->path_end()), *PTMSV));
+ state = state->BindExpr(CastE, LCtx, CastedPTMSV);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ // If getAs failed just fall through to default behaviour.
+ }
// Various C++ casts that are not handled yet.
case CK_ToUnion:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_ReinterpretMemberPointer:
case CK_VectorSplat: {
// Recover some path-sensitivty by conjuring a new value.
QualType resultType = CastE->getType();
@@ -868,7 +895,22 @@
assert(!U->isGLValue());
// FALL-THROUGH.
case UO_Deref:
- case UO_AddrOf:
+ case UO_AddrOf: {
+ // Process pointer-to-member address operation
+ const Expr *Ex = U->getSubExpr()->IgnoreParens();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex)) {
+ const ValueDecl *VD = DRE->getDecl();
+
+ if (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD)) {
+ ProgramStateRef State = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ SVal SV = svalBuilder.getMemberPointer(cast<DeclaratorDecl>(VD));
+ Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV));
+ break;
+ }
+ }
+ //Fall through in case of not pointer-to-member address operation
+ }
case UO_Extension: {
// FIXME: We can probably just have some magic in Environment::getSVal()
// that propagates values, instead of creating a new node here.
Index: lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===================================================================
--- lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -33,6 +33,13 @@
ID.AddPointer(region);
}
+void PointerToMemberData::Profile(
+ llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L) {
+ ID.AddPointer(D);
+ ID.AddPointer(L.getInternalPointer());
+}
+
typedef std::pair<SVal, uintptr_t> SValData;
typedef std::pair<SVal, SVal> SValPair;
@@ -142,6 +149,49 @@
return D;
}
+const PointerToMemberData *BasicValueFactory::getPointerToMemberData(
+ const DeclaratorDecl *DD, llvm::ImmutableList<const CXXBaseSpecifier*> L) {
+ llvm::FoldingSetNodeID ID;
+ PointerToMemberData::Profile(ID, DD, L);
+ void *InsertPos;
+
+ PointerToMemberData *D =
+ PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!D) {
+ D = (PointerToMemberData*) BPAlloc.Allocate<PointerToMemberData>();
+ new (D) PointerToMemberData(DD, L);
+ PointerToMemberDataSet.InsertNode(D, InsertPos);
+ }
+
+ return D;
+}
+
+const clang::ento::PointerToMemberData *BasicValueFactory::accumCXXBase(
+ llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
+ const nonloc::PointerToMember &PTM) {
+ nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
+ const DeclaratorDecl *DD = nullptr;
+ llvm::ImmutableList<const CXXBaseSpecifier *> PathList;
+
+ if (PTMDT.isNull() || PTMDT.is<const DeclaratorDecl *>()) {
+ if (PTMDT.is<const DeclaratorDecl *>())
+ DD = PTMDT.get<const DeclaratorDecl *>();
+
+ PathList = CXXBaseListFactory.getEmptyList();
+ } else { // const PointerToMemberData *
+ const PointerToMemberData *PTMD =
+ PTMDT.get<const PointerToMemberData *>();
+ DD = PTMD->getDeclaratorDecl();
+
+ PathList = PTMD->getCXXBaseList();
+ }
+
+ for (const auto &I : PathRange)
+ PathList = consCXXBase(I, PathList);
+ return getPointerToMemberData(DD, PathList);
+}
+
const llvm::APSInt*
BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
const llvm::APSInt& V1, const llvm::APSInt& V2) {
Index: include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -32,6 +32,7 @@
class CompoundValData;
class LazyCompoundValData;
+class PointerToMemberData;
class ProgramState;
class BasicValueFactory;
class MemRegion;
@@ -459,6 +460,42 @@
}
};
+class PointerToMember : public NonLoc {
+ friend class ento::SValBuilder;
+
+public:
+ typedef llvm::PointerUnion<const DeclaratorDecl *,
+ const PointerToMemberData *> PTMDataType;
+ const PTMDataType getPTMData() const {
+ return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
+ }
+ bool isNullMemberPointer() const {
+ return getPTMData().isNull();
+ }
+ const DeclaratorDecl *getDecl() const;
+ template<typename AdjustedDecl>
+ const AdjustedDecl* getDeclAs() const {
+ return dyn_cast_or_null<AdjustedDecl>(getDecl());
+ }
+ typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ explicit PointerToMember(const PTMDataType D)
+ : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
+ friend class SVal;
+ PointerToMember() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == PointerToMemberKind;
+ }
+
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == PointerToMemberKind;
+ }
+};
+
} // end namespace ento::nonloc
//==------------------------------------------------------------------------==//
Index: include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
+++ include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
@@ -66,6 +66,7 @@
NONLOC_SVAL(LazyCompoundVal, NonLoc)
NONLOC_SVAL(LocAsInteger, NonLoc)
NONLOC_SVAL(SymbolVal, NonLoc)
+ NONLOC_SVAL(PointerToMember, NonLoc)
#undef NONLOC_SVAL
#undef LOC_SVAL
Index: include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -204,6 +204,8 @@
const LocationContext *LCtx,
unsigned count);
+ DefinedSVal getMemberPointer(const DeclaratorDecl *DD);
+
DefinedSVal getFunctionPointer(const FunctionDecl *func);
DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
@@ -226,6 +228,14 @@
BasicVals.getLazyCompoundValData(store, region));
}
+ NonLoc makePointerToMember(const DeclaratorDecl *DD) {
+ return nonloc::PointerToMember(DD);
+ }
+
+ NonLoc makePointerToMember(const PointerToMemberData *PTMD) {
+ return nonloc::PointerToMember(PTMD);
+ }
+
NonLoc makeZeroArrayIndex() {
return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
}
Index: include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -59,6 +59,29 @@
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
+class PointerToMemberData: public llvm::FoldingSetNode {
+ const DeclaratorDecl *D;
+ llvm::ImmutableList<const CXXBaseSpecifier *> L;
+
+public:
+ PointerToMemberData(const DeclaratorDecl *D,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L)
+ : D(D), L(L) {}
+
+ typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
+ iterator begin() const { return L.begin(); }
+ iterator end() const { return L.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const DeclaratorDecl *D,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
+ const DeclaratorDecl *getDeclaratorDecl() const {return D;}
+ llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
+ return L;
+ }
+};
+
class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
@@ -71,17 +94,20 @@
void * PersistentSValPairs;
llvm::ImmutableList<SVal>::Factory SValListFactory;
+ llvm::ImmutableList<const CXXBaseSpecifier*>::Factory CXXBaseListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+ llvm::FoldingSet<PointerToMemberData> PointerToMemberDataSet;
// This is private because external clients should use the factory
// method that takes a QualType.
const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
public:
BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc)
: Ctx(ctx), BPAlloc(Alloc), PersistentSVals(nullptr),
- PersistentSValPairs(nullptr), SValListFactory(Alloc) {}
+ PersistentSValPairs(nullptr), SValListFactory(Alloc),
+ CXXBaseListFactory(Alloc) {}
~BasicValueFactory();
@@ -172,14 +198,32 @@
const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store,
const TypedValueRegion *region);
+ const PointerToMemberData *getPointerToMemberData(
+ const DeclaratorDecl *DD,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L);
+
llvm::ImmutableList<SVal> getEmptySValList() {
return SValListFactory.getEmptyList();
}
llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
return SValListFactory.add(X, L);
}
+ llvm::ImmutableList<const CXXBaseSpecifier *> getEmptyCXXBaseList() {
+ return CXXBaseListFactory.getEmptyList();
+ }
+
+ llvm::ImmutableList<const CXXBaseSpecifier *> consCXXBase(
+ const CXXBaseSpecifier *CBS,
+ llvm::ImmutableList<const CXXBaseSpecifier *> L) {
+ return CXXBaseListFactory.add(CBS, L);
+ }
+
+ const clang::ento::PointerToMemberData *accumCXXBase(
+ llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
+ const nonloc::PointerToMember &PTM);
+
const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
const llvm::APSInt& V1,
const llvm::APSInt& V2);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits