//== 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 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(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 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(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; } void print(std::ostream& OS) const; void printStdErr() const; typedef const SymbolID* symbol_iterator; symbol_iterator symbol_begin() const; symbol_iterator symbol_end() const; static RVal MakeVal(BasicValueFactory& BasicVals, DeclRefExpr* E); // Implement isa 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 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(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 support. static inline bool classof(const RVal* V) { return V->getBaseKind() == LValKind; } static inline bool IsLValType(QualType T) { return T->isPointerType() || T->isObjCQualifiedIdType(); } }; //==------------------------------------------------------------------------==// // Subclasses of NonLVal. //==------------------------------------------------------------------------==// namespace nonlval { enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind, LValAsIntegerKind }; class SymbolVal : public NonLVal { public: SymbolVal(unsigned SymID) : NonLVal(SymbolValKind, reinterpret_cast((uintptr_t) SymID)) {} SymbolID getSymbol() const { return (SymbolID) reinterpret_cast(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(&C)) {} const SymIntConstraint& getConstraint() const { return *reinterpret_cast(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(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 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& data) : NonLVal(LValAsIntegerKind, &data) { assert (isa(data.first)); } public: LVal getLVal() const { return cast(((std::pair*) Data)->first); } const LVal& getPersistentLVal() const { const RVal& V = ((std::pair*) Data)->first; return cast(V); } unsigned getNumBits() const { return ((std::pair*) Data)->second; } // Implement isa 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, DeclValKind, FuncValKind, ConcreteIntKind, StringLiteralValKind, FieldOffsetKind, ArrayOffsetKind }; class SymbolVal : public LVal { public: SymbolVal(unsigned SymID) : LVal(SymbolValKind, reinterpret_cast((uintptr_t) SymID)) {} SymbolID getSymbol() const { return (SymbolID) reinterpret_cast(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(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 DeclVal : public LVal { public: DeclVal(const VarDecl* vd) : LVal(DeclValKind, vd) {} VarDecl* getDecl() const { return static_cast(Data); } inline bool operator==(const DeclVal& R) const { return getDecl() == R.getDecl(); } inline bool operator!=(const DeclVal& R) const { return getDecl() != R.getDecl(); } // Implement isa support. static inline bool classof(const RVal* V) { return V->getBaseKind() == LValKind && V->getSubKind() == DeclValKind; } static inline bool classof(const LVal* V) { return V->getSubKind() == DeclValKind; } }; class FuncVal : public LVal { public: FuncVal(const FunctionDecl* fd) : LVal(FuncValKind, fd) {} FunctionDecl* getDecl() const { return static_cast(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 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(Data); } // Transfer functions for binary/unary operations on ConcreteInts. RVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const ConcreteInt& R) const; // Implement isa 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 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; } }; class FieldOffset : public LVal { FieldOffset(const std::pair& data) : LVal(FieldOffsetKind, &data) {} public: LVal getBase() const { return reinterpret_cast*> (Data)->first; } const LVal& getPersistentBase() const { return reinterpret_cast*> (Data)->first; } FieldDecl* getFieldDecl() const { return (FieldDecl*) reinterpret_cast*> (Data)->second; } // Implement isa support. static inline bool classof(const RVal* V) { return V->getBaseKind() == LValKind && V->getSubKind() == FieldOffsetKind; } static inline bool classof(const LVal* V) { return V->getSubKind() == FieldOffsetKind; } static inline RVal Make(BasicValueFactory& Vals, RVal Base, FieldDecl* D) { if (Base.isUnknownOrUndef()) return Base; return FieldOffset(Vals.getPersistentRValWithData(cast(Base), (uintptr_t) D)); } }; class ArrayOffset : public LVal { ArrayOffset(const std::pair& data) : LVal(ArrayOffsetKind,&data) {} public: LVal getBase() const { return reinterpret_cast*> (Data)->first; } const LVal& getPersistentBase() const { return reinterpret_cast*> (Data)->first; } RVal getOffset() const { return reinterpret_cast*> (Data)->second; } const RVal& getPersistentOffset() const { return reinterpret_cast*> (Data)->second; } // Implement isa support. static inline bool classof(const RVal* V) { return V->getBaseKind() == LValKind && V->getSubKind() == ArrayOffsetKind; } static inline bool classof(const LVal* V) { return V->getSubKind() == ArrayOffsetKind; } static inline RVal Make(BasicValueFactory& Vals, RVal Base, RVal Offset) { if (Base.isUnknownOrUndef()) return Base; if (Offset.isUndef()) return Offset; return ArrayOffset(Vals.getPersistentRValPair(cast(Base), Offset)); } }; } // end clang::lval namespace } // end clang namespace #endif