428 lines
11 KiB
C++
428 lines
11 KiB
C++
//== RValues.h - Abstract RValues for Path-Sens. Value Tracking -*- 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 RVal, LVal, and NonLVal, 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/BasicValueFactory.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
//==------------------------------------------------------------------------==//
|
|
// Base RVal types.
|
|
//==------------------------------------------------------------------------==//
|
|
|
|
namespace clang {
|
|
|
|
class MemRegion;
|
|
class GRStateManager;
|
|
|
|
class RVal {
|
|
public:
|
|
enum BaseKind { UndefinedKind, UnknownKind, LValKind, NonLValKind };
|
|
enum { BaseBits = 2, BaseMask = 0x3 };
|
|
|
|
protected:
|
|
void* Data;
|
|
unsigned Kind;
|
|
|
|
protected:
|
|
RVal(const void* d, bool isLVal, unsigned ValKind)
|
|
: Data(const_cast<void*>(d)),
|
|
Kind((isLVal ? LValKind : NonLValKind) | (ValKind << BaseBits)) {}
|
|
|
|
explicit RVal(BaseKind k, void* D = NULL)
|
|
: Data(D), Kind(k) {}
|
|
|
|
public:
|
|
~RVal() {};
|
|
|
|
/// BufferTy - A temporary buffer to hold a set of RVals.
|
|
typedef llvm::SmallVector<RVal,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 RVal& R) const {
|
|
return getRawKind() == R.getRawKind() && Data == R.Data;
|
|
}
|
|
|
|
|
|
inline bool operator!=(const RVal& R) const {
|
|
return !(*this == R);
|
|
}
|
|
|
|
static RVal GetSymbolValue(SymbolManager& SymMgr, VarDecl *D);
|
|
|
|
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 printStdErr() const;
|
|
|
|
typedef const SymbolID* symbol_iterator;
|
|
symbol_iterator symbol_begin() const;
|
|
symbol_iterator symbol_end() const;
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal*) { return true; }
|
|
};
|
|
|
|
class UnknownVal : public RVal {
|
|
public:
|
|
UnknownVal() : RVal(UnknownKind) {}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == UnknownKind;
|
|
}
|
|
};
|
|
|
|
class UndefinedVal : public RVal {
|
|
public:
|
|
UndefinedVal() : RVal(UndefinedKind) {}
|
|
UndefinedVal(void* D) : RVal(UndefinedKind, D) {}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == UndefinedKind;
|
|
}
|
|
|
|
void* getData() const { return Data; }
|
|
};
|
|
|
|
class NonLVal : public RVal {
|
|
protected:
|
|
NonLVal(unsigned SubKind, const void* d) : RVal(d, false, SubKind) {}
|
|
|
|
public:
|
|
void print(std::ostream& Out) const;
|
|
|
|
// Utility methods to create NonLVals.
|
|
static NonLVal MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T);
|
|
|
|
static NonLVal MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I);
|
|
|
|
static NonLVal MakeIntTruthVal(BasicValueFactory& BasicVals, bool b);
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == NonLValKind;
|
|
}
|
|
};
|
|
|
|
class LVal : public RVal {
|
|
protected:
|
|
LVal(unsigned SubKind, const void* D)
|
|
: RVal(const_cast<void*>(D), true, SubKind) {}
|
|
|
|
// Equality operators.
|
|
NonLVal EQ(BasicValueFactory& BasicVals, const LVal& R) const;
|
|
NonLVal NE(BasicValueFactory& BasicVals, const LVal& R) const;
|
|
|
|
public:
|
|
void print(std::ostream& Out) const;
|
|
|
|
static LVal MakeVal(AddrLabelExpr* E);
|
|
|
|
static LVal MakeVal(StringLiteral* S);
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == LValKind;
|
|
}
|
|
|
|
static inline bool IsLValType(QualType T) {
|
|
return T->isPointerType() || T->isObjCQualifiedIdType()
|
|
|| T->isBlockPointerType();
|
|
}
|
|
};
|
|
|
|
//==------------------------------------------------------------------------==//
|
|
// Subclasses of NonLVal.
|
|
//==------------------------------------------------------------------------==//
|
|
|
|
namespace nonlval {
|
|
|
|
enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind,
|
|
LValAsIntegerKind };
|
|
|
|
class SymbolVal : public NonLVal {
|
|
public:
|
|
SymbolVal(unsigned SymID)
|
|
: NonLVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
|
|
|
SymbolID getSymbol() const {
|
|
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
|
}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == NonLValKind &&
|
|
V->getSubKind() == SymbolValKind;
|
|
}
|
|
|
|
static inline bool classof(const NonLVal* V) {
|
|
return V->getSubKind() == SymbolValKind;
|
|
}
|
|
};
|
|
|
|
class SymIntConstraintVal : public NonLVal {
|
|
public:
|
|
SymIntConstraintVal(const SymIntConstraint& C)
|
|
: NonLVal(SymIntConstraintValKind, reinterpret_cast<const void*>(&C)) {}
|
|
|
|
const SymIntConstraint& getConstraint() const {
|
|
return *reinterpret_cast<SymIntConstraint*>(Data);
|
|
}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == NonLValKind &&
|
|
V->getSubKind() == SymIntConstraintValKind;
|
|
}
|
|
|
|
static inline bool classof(const NonLVal* V) {
|
|
return V->getSubKind() == SymIntConstraintValKind;
|
|
}
|
|
};
|
|
|
|
class ConcreteInt : public NonLVal {
|
|
public:
|
|
ConcreteInt(const llvm::APSInt& V) : NonLVal(ConcreteIntKind, &V) {}
|
|
|
|
const llvm::APSInt& getValue() const {
|
|
return *static_cast<llvm::APSInt*>(Data);
|
|
}
|
|
|
|
// Transfer functions for binary/unary operations on ConcreteInts.
|
|
RVal 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 RVal* V) {
|
|
return V->getBaseKind() == NonLValKind &&
|
|
V->getSubKind() == ConcreteIntKind;
|
|
}
|
|
|
|
static inline bool classof(const NonLVal* V) {
|
|
return V->getSubKind() == ConcreteIntKind;
|
|
}
|
|
};
|
|
|
|
class LValAsInteger : public NonLVal {
|
|
LValAsInteger(const std::pair<RVal, uintptr_t>& data) :
|
|
NonLVal(LValAsIntegerKind, &data) {
|
|
assert (isa<LVal>(data.first));
|
|
}
|
|
|
|
public:
|
|
|
|
LVal getLVal() const {
|
|
return cast<LVal>(((std::pair<RVal, uintptr_t>*) Data)->first);
|
|
}
|
|
|
|
const LVal& getPersistentLVal() const {
|
|
const RVal& V = ((std::pair<RVal, uintptr_t>*) Data)->first;
|
|
return cast<LVal>(V);
|
|
}
|
|
|
|
unsigned getNumBits() const {
|
|
return ((std::pair<RVal, unsigned>*) Data)->second;
|
|
}
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == NonLValKind &&
|
|
V->getSubKind() == LValAsIntegerKind;
|
|
}
|
|
|
|
static inline bool classof(const NonLVal* V) {
|
|
return V->getSubKind() == LValAsIntegerKind;
|
|
}
|
|
|
|
static inline LValAsInteger Make(BasicValueFactory& Vals, LVal V,
|
|
unsigned Bits) {
|
|
return LValAsInteger(Vals.getPersistentRValWithData(V, Bits));
|
|
}
|
|
};
|
|
|
|
} // end namespace clang::nonlval
|
|
|
|
//==------------------------------------------------------------------------==//
|
|
// Subclasses of LVal.
|
|
//==------------------------------------------------------------------------==//
|
|
|
|
namespace lval {
|
|
|
|
enum Kind { SymbolValKind, GotoLabelKind, MemRegionKind, FuncValKind,
|
|
ConcreteIntKind, StringLiteralValKind };
|
|
|
|
class SymbolVal : public LVal {
|
|
public:
|
|
SymbolVal(unsigned SymID)
|
|
: LVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
|
|
|
SymbolID getSymbol() const {
|
|
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
|
}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == SymbolValKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == SymbolValKind;
|
|
}
|
|
};
|
|
|
|
class GotoLabel : public LVal {
|
|
public:
|
|
GotoLabel(LabelStmt* Label) : LVal(GotoLabelKind, Label) {}
|
|
|
|
LabelStmt* getLabel() const {
|
|
return static_cast<LabelStmt*>(Data);
|
|
}
|
|
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == GotoLabelKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == GotoLabelKind;
|
|
}
|
|
};
|
|
|
|
|
|
class MemRegionVal : public LVal {
|
|
public:
|
|
MemRegionVal(const MemRegion* r) : LVal(MemRegionKind, r) {}
|
|
|
|
MemRegion* getRegion() const {
|
|
return static_cast<MemRegion*>(Data);
|
|
}
|
|
|
|
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 RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == MemRegionKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == MemRegionKind;
|
|
}
|
|
};
|
|
|
|
class FuncVal : public LVal {
|
|
public:
|
|
FuncVal(const FunctionDecl* fd) : LVal(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 RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == FuncValKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == FuncValKind;
|
|
}
|
|
};
|
|
|
|
class ConcreteInt : public LVal {
|
|
public:
|
|
ConcreteInt(const llvm::APSInt& V) : LVal(ConcreteIntKind, &V) {}
|
|
|
|
const llvm::APSInt& getValue() const {
|
|
return *static_cast<llvm::APSInt*>(Data);
|
|
}
|
|
|
|
// Transfer functions for binary/unary operations on ConcreteInts.
|
|
RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
|
|
const ConcreteInt& R) const;
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == ConcreteIntKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == ConcreteIntKind;
|
|
}
|
|
};
|
|
|
|
class StringLiteralVal : public LVal {
|
|
public:
|
|
StringLiteralVal(StringLiteral* L) : LVal(StringLiteralValKind, L) {}
|
|
|
|
StringLiteral* getLiteral() const { return (StringLiteral*) Data; }
|
|
|
|
// Implement isa<T> support.
|
|
static inline bool classof(const RVal* V) {
|
|
return V->getBaseKind() == LValKind &&
|
|
V->getSubKind() == StringLiteralValKind;
|
|
}
|
|
|
|
static inline bool classof(const LVal* V) {
|
|
return V->getSubKind() == StringLiteralValKind;
|
|
}
|
|
};
|
|
|
|
} // end clang::lval namespace
|
|
} // end clang namespace
|
|
|
|
#endif
|