blob: 70824eb561d083c57522cbb8210a730af4d0c668 [file] [log] [blame]
//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines SVal, Loc, and NonLoc, classes that represent
// abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H
#define LLVM_CLANG_ANALYSIS_RVALUE_H
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
// Base SVal types.
//==------------------------------------------------------------------------==//
namespace clang {
class CompoundValData;
class BasicValueFactory;
class MemRegion;
class GRStateManager;
class SVal {
public:
enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind };
enum { BaseBits = 2, BaseMask = 0x3 };
protected:
void* Data;
unsigned Kind;
protected:
SVal(const void* d, bool isLoc, unsigned ValKind)
: Data(const_cast<void*>(d)),
Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
explicit SVal(BaseKind k, void* D = NULL)
: Data(D), Kind(k) {}
public:
SVal() : Data(0), Kind(0) {}
~SVal() {};
/// BufferTy - A temporary buffer to hold a set of SVals.
typedef llvm::SmallVector<SVal,5> BufferTy;
inline unsigned getRawKind() const { return Kind; }
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
inline void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddInteger((unsigned) getRawKind());
ID.AddPointer(reinterpret_cast<void*>(Data));
}
inline bool operator==(const SVal& R) const {
return getRawKind() == R.getRawKind() && Data == R.Data;
}
inline bool operator!=(const SVal& R) const {
return !(*this == R);
}
static SVal GetSymbolValue(SymbolManager& SymMgr, VarDecl *D);
static SVal getSymbolValue(SymbolManager& SymMgr, const MemRegion* R,
const llvm::APSInt* Idx, QualType T);
static SVal getSymbolValue(SymbolManager& SymMgr, const MemRegion* R,
const FieldDecl* FD, QualType T);
inline bool isUnknown() const {
return getRawKind() == UnknownKind;
}
inline bool isUndef() const {
return getRawKind() == UndefinedKind;
}
inline bool isUnknownOrUndef() const {
return getRawKind() <= UnknownKind;
}
inline bool isValid() const {
return getRawKind() > UnknownKind;
}
bool isZeroConstant() const;
void print(std::ostream& OS) const;
void print(llvm::raw_ostream& OS) const;
void printStdErr() const;
class symbol_iterator {
SymbolRef SingleRef;
const SymbolRef* sptr;
public:
bool operator==(const symbol_iterator& X) {
return SingleRef == X.SingleRef && sptr == X.sptr;
}
bool operator!=(const symbol_iterator& X) {
return SingleRef != X.SingleRef || sptr != X.sptr;
}
symbol_iterator& operator++() {
if (sptr)
++sptr;
else
SingleRef = SymbolRef();
return *this;
}
SymbolRef operator*() const {
if (sptr)
return *sptr;
return SingleRef;
}
symbol_iterator(SymbolRef x) : SingleRef(x), sptr(0) {}
symbol_iterator() : sptr(0) {}
symbol_iterator(const SymbolRef* x) : sptr(x) {}
};
symbol_iterator symbol_begin() const;
symbol_iterator symbol_end() const;
// Implement isa<T> support.
static inline bool classof(const SVal*) { return true; }
};
class UnknownVal : public SVal {
public:
UnknownVal() : SVal(UnknownKind) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UnknownKind;
}
};
class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
UndefinedVal(void* D) : SVal(UndefinedKind, D) {}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == UndefinedKind;
}
void* getData() const { return Data; }
};
class NonLoc : public SVal {
protected:
NonLoc(unsigned SubKind, const void* d) : SVal(d, false, SubKind) {}
public:
void print(llvm::raw_ostream& Out) const;
// Utility methods to create NonLocs.
static NonLoc MakeVal(BasicValueFactory& BasicVals, unsigned X,
bool isUnsigned);
static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X,
unsigned BitWidth, bool isUnsigned);
static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T);
static NonLoc MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I);
static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
bool isUnsigned);
static NonLoc MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I);
static NonLoc MakeIntTruthVal(BasicValueFactory& BasicVals, bool b);
static NonLoc MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
BasicValueFactory& BasicVals);
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind;
}
};
class Loc : public SVal {
protected:
Loc(unsigned SubKind, const void* D)
: SVal(const_cast<void*>(D), true, SubKind) {}
// Equality operators.
NonLoc EQ(BasicValueFactory& BasicVals, const Loc& R) const;
NonLoc NE(BasicValueFactory& BasicVals, const Loc& R) const;
public:
void print(llvm::raw_ostream& Out) const;
static Loc MakeVal(AddrLabelExpr* E);
static Loc MakeVal(StringLiteral* S);
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind;
}
static inline bool IsLocType(QualType T) {
return T->isPointerType() || T->isObjCQualifiedIdType()
|| T->isBlockPointerType();
}
};
//==------------------------------------------------------------------------==//
// Subclasses of NonLoc.
//==------------------------------------------------------------------------==//
namespace nonloc {
enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind,
LocAsIntegerKind, CompoundValKind };
class SymbolVal : public NonLoc {
public:
SymbolVal(unsigned SymID)
: NonLoc(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
SymbolRef getSymbol() const {
return (SymbolRef) reinterpret_cast<uintptr_t>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == SymbolValKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == SymbolValKind;
}
};
class SymIntConstraintVal : public NonLoc {
public:
SymIntConstraintVal(const SymIntConstraint& C)
: NonLoc(SymIntConstraintValKind, reinterpret_cast<const void*>(&C)) {}
const SymIntConstraint& getConstraint() const {
return *reinterpret_cast<SymIntConstraint*>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == SymIntConstraintValKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == SymIntConstraintValKind;
}
};
class ConcreteInt : public NonLoc {
public:
ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
const llvm::APSInt& getValue() const {
return *static_cast<llvm::APSInt*>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const;
ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
class LocAsInteger : public NonLoc {
LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
NonLoc(LocAsIntegerKind, &data) {
assert (isa<Loc>(data.first));
}
public:
Loc getLoc() const {
return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
}
const Loc& getPersistentLoc() const {
const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
return cast<Loc>(V);
}
unsigned getNumBits() const {
return ((std::pair<SVal, unsigned>*) Data)->second;
}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind &&
V->getSubKind() == LocAsIntegerKind;
}
static inline bool classof(const NonLoc* V) {
return V->getSubKind() == LocAsIntegerKind;
}
static LocAsInteger Make(BasicValueFactory& Vals, Loc V, unsigned Bits);
};
class CompoundVal : public NonLoc {
friend class NonLoc;
CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
public:
const CompoundValData* getValue() const {
return static_cast<CompoundValData*>(Data);
}
typedef llvm::ImmutableList<SVal>::iterator iterator;
iterator begin() const;
iterator end() const;
static bool classof(const SVal* V) {
return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
}
static bool classof(const NonLoc* V) {
return V->getSubKind() == CompoundValKind;
}
};
} // end namespace clang::nonloc
//==------------------------------------------------------------------------==//
// Subclasses of Loc.
//==------------------------------------------------------------------------==//
namespace loc {
enum Kind { SymbolValKind, GotoLabelKind, MemRegionKind, FuncValKind,
ConcreteIntKind };
class SymbolVal : public Loc {
public:
SymbolVal(unsigned SymID)
: Loc(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
SymbolRef getSymbol() const {
return (SymbolRef) reinterpret_cast<uintptr_t>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == SymbolValKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == SymbolValKind;
}
};
class GotoLabel : public Loc {
public:
GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
LabelStmt* getLabel() const {
return static_cast<LabelStmt*>(Data);
}
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == GotoLabelKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == GotoLabelKind;
}
};
class MemRegionVal : public Loc {
public:
MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
const MemRegion* getRegion() const {
return static_cast<MemRegion*>(Data);
}
template <typename REGION>
const REGION* getRegionAs() const {
return llvm::dyn_cast<REGION>(getRegion());
}
inline bool operator==(const MemRegionVal& R) const {
return getRegion() == R.getRegion();
}
inline bool operator!=(const MemRegionVal& R) const {
return getRegion() != R.getRegion();
}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == MemRegionKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == MemRegionKind;
}
};
class FuncVal : public Loc {
public:
FuncVal(const FunctionDecl* fd) : Loc(FuncValKind, fd) {}
FunctionDecl* getDecl() const {
return static_cast<FunctionDecl*>(Data);
}
inline bool operator==(const FuncVal& R) const {
return getDecl() == R.getDecl();
}
inline bool operator!=(const FuncVal& R) const {
return getDecl() != R.getDecl();
}
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == FuncValKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == FuncValKind;
}
};
class ConcreteInt : public Loc {
public:
ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
const llvm::APSInt& getValue() const {
return *static_cast<llvm::APSInt*>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
// Implement isa<T> support.
static inline bool classof(const SVal* V) {
return V->getBaseKind() == LocKind &&
V->getSubKind() == ConcreteIntKind;
}
static inline bool classof(const Loc* V) {
return V->getSubKind() == ConcreteIntKind;
}
};
} // end clang::loc namespace
} // end clang namespace
#endif