Also, move the REGISTER_*_WITH_PROGRAMSTATE macros to ProgramStateTrait.h.
This doesn't get rid of /all/ explicit uses of ProgramStatePartialTrait,
but it does get a lot of them.
llvm-svn: 167276
#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "llvm/ADT/ImmutableMap.h"
-
-/// Declares an immutable map of type NameTy, suitable for placement into
-/// the ProgramState. The macro should not be used inside namespaces.
-#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
- class Name {}; \
- typedef llvm::ImmutableMap<Key, Value> Name ## Ty; \
- namespace clang { \
- namespace ento { \
- template <> \
- struct ProgramStateTrait<Name> \
- : public ProgramStatePartialTrait<Name ## Ty> { \
- static void *GDMIndex() { static int Index; return &Index; } \
- }; \
- } \
- }
namespace clang {
namespace ento {
namespace ento {
template <typename T> struct ProgramStatePartialTrait;
+ /// Declares a program state trait for type \p Type called \p Name, and
+ /// introduce a typedef named \c NameTy.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
+ namespace { \
+ class Name {}; \
+ typedef Type Name ## Ty; \
+ } \
+ namespace clang { \
+ namespace ento { \
+ template <> \
+ struct ProgramStateTrait<Name> \
+ : public ProgramStatePartialTrait<Name ## Ty> { \
+ static void *GDMIndex() { static int Index; return &Index; } \
+ }; \
+ } \
+ }
+
+
// Partial-specialization for ImmutableMap.
template <typename Key, typename Data, typename Info>
}
};
+ /// Helper for REGISTER_MAP_WITH_PROGRAMSTATE.
+ #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
+
+ /// Declares an immutable map of type \p NameTy, suitable for placement into
+ /// the ProgramState.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
+ CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
+
// Partial-specialization for ImmutableSet.
}
};
+ /// Declares an immutable list of type \p NameTy, suitable for placement into
+ /// the ProgramState.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
+
+
// Partial-specialization for ImmutableList.
template <typename T>
}
};
+ /// Declares an immutable list of type \p NameTy, suitable for placement into
+ /// the ProgramState.
+ /// The macro should not be used inside namespaces, or for traits that must
+ /// be accessible from more than one translation unit.
+ #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
+ REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
+
+
// Partial specialization for bool.
template <> struct ProgramStatePartialTrait<bool> {
typedef bool data_type;
NonLoc right) const;
};
-class CStringLength {
-public:
- typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap;
-};
} //end anonymous namespace
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<CStringLength>
- : public ProgramStatePartialTrait<CStringLength::EntryMap> {
- static void *GDMIndex() { return CStringChecker::getTag(); }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
//===----------------------------------------------------------------------===//
// Individual checks and utility methods.
}
bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
return !Entries.isEmpty();
}
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return state;
}
}
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
// Then loop over the entries in the current state.
- for (CStringLength::EntryMap::iterator I = Entries.begin(),
+ for (CStringLengthTy::iterator I = Entries.begin(),
E = Entries.end(); I != E; ++I) {
const MemRegion *MR = I.getKey();
void CStringChecker::checkLiveSymbols(ProgramStateRef state,
SymbolReaper &SR) const {
// Mark all symbols in our string length map as valid.
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
return;
ProgramStateRef state = C.getState();
- CStringLength::EntryMap Entries = state->get<CStringLength>();
+ CStringLengthTy Entries = state->get<CStringLength>();
if (Entries.isEmpty())
return;
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+ CStringLengthTy::Factory &F = state->get_context<CStringLength>();
+ for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
I != E; ++I) {
SVal Len = I.getData();
if (SymbolRef Sym = Len.getAsSymbol()) {
/// to the call post-visit. The values are unsigned integers, which are either
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
/// points to data, which should be tainted on return.
-namespace { struct TaintArgsOnPostVisit{}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<TaintArgsOnPostVisit>
- : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > {
- static void *GDMIndex() { return GenericTaintChecker::getTag(); }
-};
-}}
+REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
// Depending on what was tainted at pre-visit, we determined a set of
// arguments which should be tainted after the function returns. These are
// stored in the state as TaintArgsOnPostVisit set.
- llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>();
+ TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
if (TaintArgs.isEmpty())
return false;
/// ProgramState traits to store the currently allocated (and not yet freed)
/// symbols. This is a map from the allocated content symbol to the
/// corresponding AllocationState.
-typedef llvm::ImmutableMap<SymbolRef,
- MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy;
-
-namespace { struct AllocatedData {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<AllocatedData>
- : public ProgramStatePartialTrait<AllocatedSetTy > {
- static void *GDMIndex() { static int index = 0; return &index; }
-};
-}}
+REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData,
+ SymbolRef,
+ MacOSKeychainAPIChecker::AllocationState)
static bool isEnclosingFunctionParam(const Expr *E) {
E = E->IgnoreParenCasts();
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- AllocatedSetTy ASet = State->get<AllocatedData>();
+ AllocatedDataTy ASet = State->get<AllocatedData>();
if (ASet.isEmpty())
return;
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
+ for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) {
if (SR.isLive(I->first))
continue;
if (C.getLocationContext()->getParent() != 0)
return;
- AllocatedSetTy AS = state->get<AllocatedData>();
+ AllocatedDataTy AS = state->get<AllocatedData>();
if (AS.isEmpty())
return;
// found here, so report it.
bool Changed = false;
AllocationPairVec Errors;
- for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
+ for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
Changed = true;
state = state->remove<AllocatedData>(I->first);
// If the allocated symbol is null or if error code was returned at
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap;
-class RegionState {};
-class ReallocPairs {};
-namespace clang {
-namespace ento {
- template <>
- struct ProgramStateTrait<RegionState>
- : public ProgramStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { static int x; return &x; }
- };
-
- template <>
- struct ProgramStateTrait<ReallocPairs>
- : public ProgramStatePartialTrait<ReallocMap> {
- static void *GDMIndex() { static int x; return &x; }
- };
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
+REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
namespace {
class StopTrackingCallback : public SymbolVisitor {
}
// Cleanup the Realloc Pairs Map.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
if (SymReaper.isDead(I->first) ||
SymReaper.isDead(I->second.ReallocatedSym)) {
state = state->remove<ReallocPairs>(I->first);
// Realloc returns 0 when reallocation fails, which means that we should
// restore the state of the pointer being reallocated.
- ReallocMap RP = state->get<ReallocPairs>();
- for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
+ ReallocPairsTy RP = state->get<ReallocPairs>();
+ for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
// If the symbol is assumed to be NULL, remove it from consideration.
ConstraintManager &CMgr = state->getConstraintManager();
ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
ProgramStateRef prevState) {
- ReallocMap currMap = currState->get<ReallocPairs>();
- ReallocMap prevMap = prevState->get<ReallocPairs>();
+ ReallocPairsTy currMap = currState->get<ReallocPairs>();
+ ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
- for (ReallocMap::iterator I = prevMap.begin(), E = prevMap.end();
+ for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end();
I != E; ++I) {
SymbolRef sym = I.getKey();
if (!currMap.lookup(sym))
};
} // end anonymous namespace
-// ProgramState trait - a map from array symbol to it's state.
-typedef llvm::ImmutableMap<SymbolRef, DefinedSVal> ArraySizeM;
-
-namespace { struct ArraySizeMap {}; }
-namespace clang { namespace ento {
-template<> struct ProgramStateTrait<ArraySizeMap>
- : public ProgramStatePartialTrait<ArraySizeM > {
- static void *GDMIndex() { return ObjCContainersChecker::getTag(); }
-};
-}}
+// ProgramState trait - a map from array symbol to its state.
+REGISTER_MAP_WITH_PROGRAMSTATE(ArraySizeMap, SymbolRef, DefinedSVal)
void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
CheckerContext &C) const {
} // end anonymous namespace
// GDM Entry for tracking lock state.
-namespace { class LockSet {}; }
-namespace clang {
-namespace ento {
-template <> struct ProgramStateTrait<LockSet> :
- public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > {
- static void *GDMIndex() { static int x = 0; return &x; }
-};
-} // end of ento (ProgramState) namespace
-} // end clang namespace
+REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
- llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>();
+ LockSetTy LS = state->get<LockSet>();
// FIXME: Better analysis requires IPA for wrappers.
// FIXME: check for double unlocks
// RefBindings - State used to track object reference counts.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<RefBindings>
- : public ProgramStatePartialTrait<RefBindings> {
- static void *GDMIndex() {
- static int RefBIndex = 0;
- return &RefBIndex;
- }
-};
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal)
static inline const RefVal *getRefBinding(ProgramStateRef State,
SymbolRef Sym) {
// too bad since the number of symbols we will track in practice are
// probably small and evalAssume is only called at branches and a few
// other places.
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
if (B.isEmpty())
return state;
bool changed = false;
- RefBindings::Factory &RefBFactory = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
// Check if the symbol is null stop tracking the symbol.
ConstraintManager &CMgr = state->getConstraintManager();
ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, /*Tag=*/0,
Ctx, I->first, I->second);
if (!state)
B = state->get<RefBindings>();
SmallVector<SymbolRef, 10> Leaked;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I)
state = handleSymbolDeath(state, I->first, I->second, Leaked);
processLeaks(state, Leaked, Ctx, Pred);
ExplodedNode *Pred = C.getPredecessor();
ProgramStateRef state = C.getState();
- RefBindings B = state->get<RefBindings>();
+ RefBindingsTy B = state->get<RefBindings>();
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
return;
// Now generate a new node that nukes the old bindings.
- RefBindings::Factory &F = state->get_context<RefBindings>();
+ RefBindingsTy::Factory &F = state->get_context<RefBindings>();
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
E = SymReaper.dead_end(); I != E; ++I)
void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const {
- RefBindings B = State->get<RefBindings>();
+ RefBindingsTy B = State->get<RefBindings>();
if (!B.isEmpty())
Out << Sep << NL;
- for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
Out << I->first << " : ";
I->second.print(Out);
Out << NL;
return true;
}
-/// The GDM component containing the dynamic dispatch bifurcation info. When
-/// the exact type of the receiver is not known, we want to explore both paths -
-/// one on which we do inline it and the other one on which we don't. This is
-/// done to ensure we do not drop coverage.
-/// This is the map from the receiver region to a bool, specifying either we
-/// consider this region's information precise or not along the given path.
-namespace clang {
-namespace ento {
-enum DynamicDispatchMode { DynamicDispatchModeInlined = 1,
- DynamicDispatchModeConservative };
-
-struct DynamicDispatchBifurcationMap {};
-typedef llvm::ImmutableMap<const MemRegion*,
- unsigned int> DynamicDispatchBifur;
-template<> struct ProgramStateTrait<DynamicDispatchBifurcationMap>
- : public ProgramStatePartialTrait<DynamicDispatchBifur> {
- static void *GDMIndex() { static int index; return &index; }
-};
-
-}}
+// The GDM component containing the dynamic dispatch bifurcation info. When
+// the exact type of the receiver is not known, we want to explore both paths -
+// one on which we do inline it and the other one on which we don't. This is
+// done to ensure we do not drop coverage.
+// This is the map from the receiver region to a bool, specifying either we
+// consider this region's information precise or not along the given path.
+namespace {
+ enum DynamicDispatchMode {
+ DynamicDispatchModeInlined = 1,
+ DynamicDispatchModeConservative
+ };
+}
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
+ const MemRegion *, unsigned)
bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
NodeBuilder &Bldr, ExplodedNode *Pred,
// Check if we've performed the split already - note, we only want
// to split the path once per memory region.
ProgramStateRef State = Pred->getState();
- const unsigned int *BState =
+ const unsigned *BState =
State->get<DynamicDispatchBifurcationMap>(BifurReg);
if (BState) {
// If we are on "inline path", keep inlining if possible.
}
/// The GDM component containing the dynamic type info. This is a map from a
-/// symbol to it's most likely type.
-namespace clang {
-namespace ento {
-typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> DynamicTypeMap;
-template<> struct ProgramStateTrait<DynamicTypeMap>
- : public ProgramStatePartialTrait<DynamicTypeMap> {
- static void *GDMIndex() { static int index; return &index; }
-};
-}}
+/// symbol to its most likely type.
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicTypeMap,
+ const MemRegion *,
+ DynamicTypeInfo)
DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const {
Reg = Reg->StripCasts();
using namespace clang;
using namespace ento;
-namespace { class ConstraintRange {}; }
-static int ConstraintRangeIndex = 0;
-
/// A Range represents the closed range [from, to]. The caller must
/// guarantee that from <= to. Note that Range is immutable, so as not
/// to subvert RangeSet's immutability.
};
} // end anonymous namespace
-typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
-
-namespace clang {
-namespace ento {
-template<>
-struct ProgramStateTrait<ConstraintRange>
- : public ProgramStatePartialTrait<ConstraintRangeTy> {
- static inline void *GDMIndex() { return &ConstraintRangeIndex; }
-};
-}
-}
+REGISTER_MAP_WITH_PROGRAMSTATE(ConstraintRange, SymbolRef, RangeSet)
namespace {
class RangeConstraintManager : public SimpleConstraintManager{