1218887Sdim//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// This file defines SVal, Loc, and NonLoc, classes that represent 11218887Sdim// abstract r-values for use with path-sensitive value tracking. 12218887Sdim// 13218887Sdim//===----------------------------------------------------------------------===// 14218887Sdim 15218887Sdim#ifndef LLVM_CLANG_GR_RVALUE_H 16218887Sdim#define LLVM_CLANG_GR_RVALUE_H 17218887Sdim 18226633Sdim#include "clang/Basic/LLVM.h" 19249423Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 20218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 21218887Sdim#include "llvm/ADT/ImmutableList.h" 22218887Sdim 23218887Sdim//==------------------------------------------------------------------------==// 24218887Sdim// Base SVal types. 25218887Sdim//==------------------------------------------------------------------------==// 26218887Sdim 27218887Sdimnamespace clang { 28218887Sdim 29218887Sdimnamespace ento { 30218887Sdim 31218887Sdimclass CompoundValData; 32218887Sdimclass LazyCompoundValData; 33226633Sdimclass ProgramState; 34218887Sdimclass BasicValueFactory; 35218887Sdimclass MemRegion; 36249423Sdimclass TypedValueRegion; 37218887Sdimclass MemRegionManager; 38226633Sdimclass ProgramStateManager; 39218887Sdimclass SValBuilder; 40218887Sdim 41218887Sdim/// SVal - This represents a symbolic expression, which can be either 42218887Sdim/// an L-value or an R-value. 43218887Sdim/// 44218887Sdimclass SVal { 45218887Sdimpublic: 46218887Sdim enum BaseKind { 47218887Sdim // The enumerators must be representable using 2 bits. 48218887Sdim UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value) 49218887Sdim UnknownKind = 1, // for subclass UnknownVal (a void value) 50218887Sdim LocKind = 2, // for subclass Loc (an L-value) 51218887Sdim NonLocKind = 3 // for subclass NonLoc (an R-value that's not 52218887Sdim // an L-value) 53218887Sdim }; 54218887Sdim enum { BaseBits = 2, BaseMask = 0x3 }; 55218887Sdim 56218887Sdimprotected: 57226633Sdim const void *Data; 58218887Sdim 59218887Sdim /// The lowest 2 bits are a BaseKind (0 -- 3). 60218887Sdim /// The higher bits are an unsigned "kind" value. 61218887Sdim unsigned Kind; 62218887Sdim 63226633Sdim explicit SVal(const void *d, bool isLoc, unsigned ValKind) 64218887Sdim : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} 65218887Sdim 66226633Sdim explicit SVal(BaseKind k, const void *D = NULL) 67218887Sdim : Data(D), Kind(k) {} 68218887Sdim 69218887Sdimpublic: 70218887Sdim explicit SVal() : Data(0), Kind(0) {} 71218887Sdim 72249423Sdim /// \brief Convert to the specified SVal type, asserting that this SVal is of 73249423Sdim /// the desired type. 74249423Sdim template<typename T> 75249423Sdim T castAs() const { 76249423Sdim assert(T::isKind(*this)); 77249423Sdim T t; 78249423Sdim SVal& sv = t; 79249423Sdim sv = *this; 80249423Sdim return t; 81249423Sdim } 82249423Sdim 83249423Sdim /// \brief Convert to the specified SVal type, returning None if this SVal is 84249423Sdim /// not of the desired type. 85249423Sdim template<typename T> 86249423Sdim Optional<T> getAs() const { 87249423Sdim if (!T::isKind(*this)) 88249423Sdim return None; 89249423Sdim T t; 90249423Sdim SVal& sv = t; 91249423Sdim sv = *this; 92249423Sdim return t; 93249423Sdim } 94249423Sdim 95218887Sdim /// BufferTy - A temporary buffer to hold a set of SVals. 96226633Sdim typedef SmallVector<SVal,5> BufferTy; 97218887Sdim 98218887Sdim inline unsigned getRawKind() const { return Kind; } 99218887Sdim inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } 100218887Sdim inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } 101218887Sdim 102218887Sdim // This method is required for using SVal in a FoldingSetNode. It 103218887Sdim // extracts a unique signature for this SVal object. 104218887Sdim inline void Profile(llvm::FoldingSetNodeID& ID) const { 105218887Sdim ID.AddInteger((unsigned) getRawKind()); 106218887Sdim ID.AddPointer(Data); 107218887Sdim } 108218887Sdim 109218887Sdim inline bool operator==(const SVal& R) const { 110218887Sdim return getRawKind() == R.getRawKind() && Data == R.Data; 111218887Sdim } 112218887Sdim 113218887Sdim inline bool operator!=(const SVal& R) const { 114218887Sdim return !(*this == R); 115218887Sdim } 116218887Sdim 117218887Sdim inline bool isUnknown() const { 118218887Sdim return getRawKind() == UnknownKind; 119218887Sdim } 120218887Sdim 121218887Sdim inline bool isUndef() const { 122218887Sdim return getRawKind() == UndefinedKind; 123218887Sdim } 124218887Sdim 125218887Sdim inline bool isUnknownOrUndef() const { 126218887Sdim return getRawKind() <= UnknownKind; 127218887Sdim } 128218887Sdim 129218887Sdim inline bool isValid() const { 130218887Sdim return getRawKind() > UnknownKind; 131218887Sdim } 132218887Sdim 133218887Sdim bool isConstant() const; 134218887Sdim 135218887Sdim bool isConstant(int I) const; 136218887Sdim 137218887Sdim bool isZeroConstant() const; 138218887Sdim 139218887Sdim /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; 140218887Sdim bool hasConjuredSymbol() const; 141218887Sdim 142218887Sdim /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a 143218887Sdim /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. 144218887Sdim /// Otherwise return 0. 145226633Sdim const FunctionDecl *getAsFunctionDecl() const; 146218887Sdim 147251662Sdim /// \brief If this SVal is a location and wraps a symbol, return that 148251662Sdim /// SymbolRef. Otherwise return 0. 149251662Sdim /// 150251662Sdim /// Casts are ignored during lookup. 151251662Sdim /// \param IncludeBaseRegions The boolean that controls whether the search 152251662Sdim /// should continue to the base regions if the region is not symbolic. 153251662Sdim SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; 154218887Sdim 155218887Sdim /// Get the symbol in the SVal or its base region. 156218887Sdim SymbolRef getLocSymbolInBase() const; 157218887Sdim 158251662Sdim /// \brief If this SVal wraps a symbol return that SymbolRef. 159234353Sdim /// Otherwise, return 0. 160251662Sdim /// 161251662Sdim /// Casts are ignored during lookup. 162251662Sdim /// \param IncludeBaseRegions The boolean that controls whether the search 163251662Sdim /// should continue to the base regions if the region is not symbolic. 164251662Sdim SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; 165218887Sdim 166218887Sdim /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then 167218887Sdim /// return that expression. Otherwise return NULL. 168218887Sdim const SymExpr *getAsSymbolicExpression() const; 169218887Sdim 170234353Sdim const SymExpr* getAsSymExpr() const; 171234353Sdim 172218887Sdim const MemRegion *getAsRegion() const; 173218887Sdim 174226633Sdim void dumpToStream(raw_ostream &OS) const; 175218887Sdim void dump() const; 176218887Sdim 177234353Sdim SymExpr::symbol_iterator symbol_begin() const { 178218887Sdim const SymExpr *SE = getAsSymbolicExpression(); 179218887Sdim if (SE) 180234353Sdim return SE->symbol_begin(); 181218887Sdim else 182234353Sdim return SymExpr::symbol_iterator(); 183218887Sdim } 184218887Sdim 185234353Sdim SymExpr::symbol_iterator symbol_end() const { 186234353Sdim return SymExpr::symbol_end(); 187234353Sdim } 188218887Sdim}; 189218887Sdim 190218887Sdim 191218887Sdimclass UndefinedVal : public SVal { 192218887Sdimpublic: 193218887Sdim UndefinedVal() : SVal(UndefinedKind) {} 194218887Sdim 195249423Sdimprivate: 196249423Sdim friend class SVal; 197249423Sdim static bool isKind(const SVal& V) { 198249423Sdim return V.getBaseKind() == UndefinedKind; 199218887Sdim } 200218887Sdim}; 201218887Sdim 202218887Sdimclass DefinedOrUnknownSVal : public SVal { 203218887Sdimprivate: 204249423Sdim // We want calling these methods to be a compiler error since they are 205249423Sdim // tautologically false. 206249423Sdim bool isUndef() const LLVM_DELETED_FUNCTION; 207249423Sdim bool isValid() const LLVM_DELETED_FUNCTION; 208218887Sdim 209218887Sdimprotected: 210249423Sdim DefinedOrUnknownSVal() {} 211226633Sdim explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) 212218887Sdim : SVal(d, isLoc, ValKind) {} 213218887Sdim 214218887Sdim explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) 215218887Sdim : SVal(k, D) {} 216218887Sdim 217249423Sdimprivate: 218249423Sdim friend class SVal; 219249423Sdim static bool isKind(const SVal& V) { 220249423Sdim return !V.isUndef(); 221218887Sdim } 222218887Sdim}; 223218887Sdim 224218887Sdimclass UnknownVal : public DefinedOrUnknownSVal { 225218887Sdimpublic: 226218887Sdim explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} 227218887Sdim 228249423Sdimprivate: 229249423Sdim friend class SVal; 230249423Sdim static bool isKind(const SVal &V) { 231249423Sdim return V.getBaseKind() == UnknownKind; 232218887Sdim } 233218887Sdim}; 234218887Sdim 235218887Sdimclass DefinedSVal : public DefinedOrUnknownSVal { 236218887Sdimprivate: 237249423Sdim // We want calling these methods to be a compiler error since they are 238249423Sdim // tautologically true/false. 239249423Sdim bool isUnknown() const LLVM_DELETED_FUNCTION; 240249423Sdim bool isUnknownOrUndef() const LLVM_DELETED_FUNCTION; 241249423Sdim bool isValid() const LLVM_DELETED_FUNCTION; 242218887Sdimprotected: 243249423Sdim DefinedSVal() {} 244226633Sdim explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) 245218887Sdim : DefinedOrUnknownSVal(d, isLoc, ValKind) {} 246249423Sdimprivate: 247249423Sdim friend class SVal; 248249423Sdim static bool isKind(const SVal& V) { 249249423Sdim return !V.isUnknownOrUndef(); 250218887Sdim } 251218887Sdim}; 252218887Sdim 253249423Sdim 254249423Sdim/// \brief Represents an SVal that is guaranteed to not be UnknownVal. 255249423Sdimclass KnownSVal : public SVal { 256249423Sdim KnownSVal() {} 257249423Sdim friend class SVal; 258249423Sdim static bool isKind(const SVal &V) { 259249423Sdim return !V.isUnknown(); 260249423Sdim } 261249423Sdimpublic: 262249423Sdim KnownSVal(const DefinedSVal &V) : SVal(V) {} 263249423Sdim KnownSVal(const UndefinedVal &V) : SVal(V) {} 264249423Sdim}; 265249423Sdim 266218887Sdimclass NonLoc : public DefinedSVal { 267218887Sdimprotected: 268249423Sdim NonLoc() {} 269226633Sdim explicit NonLoc(unsigned SubKind, const void *d) 270218887Sdim : DefinedSVal(d, false, SubKind) {} 271218887Sdim 272218887Sdimpublic: 273226633Sdim void dumpToStream(raw_ostream &Out) const; 274218887Sdim 275249423Sdimprivate: 276249423Sdim friend class SVal; 277249423Sdim static bool isKind(const SVal& V) { 278249423Sdim return V.getBaseKind() == NonLocKind; 279218887Sdim } 280218887Sdim}; 281218887Sdim 282218887Sdimclass Loc : public DefinedSVal { 283218887Sdimprotected: 284249423Sdim Loc() {} 285226633Sdim explicit Loc(unsigned SubKind, const void *D) 286218887Sdim : DefinedSVal(const_cast<void*>(D), true, SubKind) {} 287218887Sdim 288218887Sdimpublic: 289226633Sdim void dumpToStream(raw_ostream &Out) const; 290218887Sdim 291218887Sdim static inline bool isLocType(QualType T) { 292218887Sdim return T->isAnyPointerType() || T->isBlockPointerType() || 293263508Sdim T->isReferenceType() || T->isNullPtrType(); 294218887Sdim } 295249423Sdim 296249423Sdimprivate: 297249423Sdim friend class SVal; 298249423Sdim static bool isKind(const SVal& V) { 299249423Sdim return V.getBaseKind() == LocKind; 300249423Sdim } 301218887Sdim}; 302218887Sdim 303218887Sdim//==------------------------------------------------------------------------==// 304218887Sdim// Subclasses of NonLoc. 305218887Sdim//==------------------------------------------------------------------------==// 306218887Sdim 307218887Sdimnamespace nonloc { 308218887Sdim 309243830Sdimenum Kind { ConcreteIntKind, SymbolValKind, 310218887Sdim LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; 311218887Sdim 312234353Sdim/// \brief Represents symbolic expression. 313218887Sdimclass SymbolVal : public NonLoc { 314218887Sdimpublic: 315218887Sdim SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} 316218887Sdim 317218887Sdim SymbolRef getSymbol() const { 318234353Sdim return (const SymExpr*) Data; 319218887Sdim } 320218887Sdim 321249423Sdim bool isExpression() const { 322234353Sdim return !isa<SymbolData>(getSymbol()); 323234353Sdim } 324234353Sdim 325249423Sdimprivate: 326249423Sdim friend class SVal; 327249423Sdim SymbolVal() {} 328249423Sdim static bool isKind(const SVal& V) { 329249423Sdim return V.getBaseKind() == NonLocKind && 330249423Sdim V.getSubKind() == SymbolValKind; 331218887Sdim } 332218887Sdim 333249423Sdim static bool isKind(const NonLoc& V) { 334249423Sdim return V.getSubKind() == SymbolValKind; 335218887Sdim } 336218887Sdim}; 337218887Sdim 338234353Sdim/// \brief Value representing integer constant. 339218887Sdimclass ConcreteInt : public NonLoc { 340218887Sdimpublic: 341218887Sdim explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} 342218887Sdim 343218887Sdim const llvm::APSInt& getValue() const { 344218887Sdim return *static_cast<const llvm::APSInt*>(Data); 345218887Sdim } 346218887Sdim 347218887Sdim // Transfer functions for binary/unary operations on ConcreteInts. 348218887Sdim SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, 349218887Sdim const ConcreteInt& R) const; 350218887Sdim 351218887Sdim ConcreteInt evalComplement(SValBuilder &svalBuilder) const; 352218887Sdim 353218887Sdim ConcreteInt evalMinus(SValBuilder &svalBuilder) const; 354218887Sdim 355249423Sdimprivate: 356249423Sdim friend class SVal; 357249423Sdim ConcreteInt() {} 358249423Sdim static bool isKind(const SVal& V) { 359249423Sdim return V.getBaseKind() == NonLocKind && 360249423Sdim V.getSubKind() == ConcreteIntKind; 361218887Sdim } 362218887Sdim 363249423Sdim static bool isKind(const NonLoc& V) { 364249423Sdim return V.getSubKind() == ConcreteIntKind; 365218887Sdim } 366218887Sdim}; 367218887Sdim 368218887Sdimclass LocAsInteger : public NonLoc { 369218887Sdim friend class ento::SValBuilder; 370218887Sdim 371249423Sdim explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) 372249423Sdim : NonLoc(LocAsIntegerKind, &data) { 373249423Sdim assert (data.first.getAs<Loc>()); 374249423Sdim } 375218887Sdim 376218887Sdimpublic: 377218887Sdim 378218887Sdim Loc getLoc() const { 379239462Sdim const std::pair<SVal, uintptr_t> *D = 380239462Sdim static_cast<const std::pair<SVal, uintptr_t> *>(Data); 381249423Sdim return D->first.castAs<Loc>(); 382218887Sdim } 383218887Sdim 384249423Sdim Loc getPersistentLoc() const { 385239462Sdim const std::pair<SVal, uintptr_t> *D = 386239462Sdim static_cast<const std::pair<SVal, uintptr_t> *>(Data); 387239462Sdim const SVal& V = D->first; 388249423Sdim return V.castAs<Loc>(); 389218887Sdim } 390218887Sdim 391218887Sdim unsigned getNumBits() const { 392239462Sdim const std::pair<SVal, uintptr_t> *D = 393239462Sdim static_cast<const std::pair<SVal, uintptr_t> *>(Data); 394239462Sdim return D->second; 395218887Sdim } 396218887Sdim 397249423Sdimprivate: 398249423Sdim friend class SVal; 399249423Sdim LocAsInteger() {} 400249423Sdim static bool isKind(const SVal& V) { 401249423Sdim return V.getBaseKind() == NonLocKind && 402249423Sdim V.getSubKind() == LocAsIntegerKind; 403218887Sdim } 404218887Sdim 405249423Sdim static bool isKind(const NonLoc& V) { 406249423Sdim return V.getSubKind() == LocAsIntegerKind; 407218887Sdim } 408218887Sdim}; 409218887Sdim 410218887Sdimclass CompoundVal : public NonLoc { 411218887Sdim friend class ento::SValBuilder; 412218887Sdim 413218887Sdim explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} 414218887Sdim 415218887Sdimpublic: 416218887Sdim const CompoundValData* getValue() const { 417218887Sdim return static_cast<const CompoundValData*>(Data); 418218887Sdim } 419218887Sdim 420218887Sdim typedef llvm::ImmutableList<SVal>::iterator iterator; 421218887Sdim iterator begin() const; 422218887Sdim iterator end() const; 423218887Sdim 424249423Sdimprivate: 425249423Sdim friend class SVal; 426249423Sdim CompoundVal() {} 427249423Sdim static bool isKind(const SVal& V) { 428249423Sdim return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; 429218887Sdim } 430218887Sdim 431249423Sdim static bool isKind(const NonLoc& V) { 432249423Sdim return V.getSubKind() == CompoundValKind; 433218887Sdim } 434218887Sdim}; 435218887Sdim 436218887Sdimclass LazyCompoundVal : public NonLoc { 437218887Sdim friend class ento::SValBuilder; 438218887Sdim 439218887Sdim explicit LazyCompoundVal(const LazyCompoundValData *D) 440218887Sdim : NonLoc(LazyCompoundValKind, D) {} 441218887Sdimpublic: 442218887Sdim const LazyCompoundValData *getCVData() const { 443218887Sdim return static_cast<const LazyCompoundValData*>(Data); 444218887Sdim } 445218887Sdim const void *getStore() const; 446249423Sdim const TypedValueRegion *getRegion() const; 447218887Sdim 448249423Sdimprivate: 449249423Sdim friend class SVal; 450249423Sdim LazyCompoundVal() {} 451249423Sdim static bool isKind(const SVal& V) { 452249423Sdim return V.getBaseKind() == NonLocKind && 453249423Sdim V.getSubKind() == LazyCompoundValKind; 454218887Sdim } 455249423Sdim static bool isKind(const NonLoc& V) { 456249423Sdim return V.getSubKind() == LazyCompoundValKind; 457218887Sdim } 458218887Sdim}; 459218887Sdim 460218887Sdim} // end namespace ento::nonloc 461218887Sdim 462218887Sdim//==------------------------------------------------------------------------==// 463218887Sdim// Subclasses of Loc. 464218887Sdim//==------------------------------------------------------------------------==// 465218887Sdim 466218887Sdimnamespace loc { 467218887Sdim 468239462Sdimenum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; 469218887Sdim 470218887Sdimclass GotoLabel : public Loc { 471218887Sdimpublic: 472218887Sdim explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} 473218887Sdim 474218887Sdim const LabelDecl *getLabel() const { 475218887Sdim return static_cast<const LabelDecl*>(Data); 476218887Sdim } 477218887Sdim 478249423Sdimprivate: 479249423Sdim friend class SVal; 480249423Sdim GotoLabel() {} 481249423Sdim static bool isKind(const SVal& V) { 482249423Sdim return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; 483218887Sdim } 484218887Sdim 485249423Sdim static bool isKind(const Loc& V) { 486249423Sdim return V.getSubKind() == GotoLabelKind; 487218887Sdim } 488218887Sdim}; 489218887Sdim 490218887Sdim 491218887Sdimclass MemRegionVal : public Loc { 492218887Sdimpublic: 493218887Sdim explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} 494218887Sdim 495234982Sdim /// \brief Get the underlining region. 496218887Sdim const MemRegion* getRegion() const { 497218887Sdim return static_cast<const MemRegion*>(Data); 498218887Sdim } 499218887Sdim 500234982Sdim /// \brief Get the underlining region and strip casts. 501239462Sdim const MemRegion* stripCasts(bool StripBaseCasts = true) const; 502218887Sdim 503218887Sdim template <typename REGION> 504218887Sdim const REGION* getRegionAs() const { 505249423Sdim return dyn_cast<REGION>(getRegion()); 506218887Sdim } 507218887Sdim 508218887Sdim inline bool operator==(const MemRegionVal& R) const { 509218887Sdim return getRegion() == R.getRegion(); 510218887Sdim } 511218887Sdim 512218887Sdim inline bool operator!=(const MemRegionVal& R) const { 513218887Sdim return getRegion() != R.getRegion(); 514218887Sdim } 515218887Sdim 516249423Sdimprivate: 517249423Sdim friend class SVal; 518249423Sdim MemRegionVal() {} 519249423Sdim static bool isKind(const SVal& V) { 520249423Sdim return V.getBaseKind() == LocKind && 521249423Sdim V.getSubKind() == MemRegionKind; 522218887Sdim } 523218887Sdim 524249423Sdim static bool isKind(const Loc& V) { 525249423Sdim return V.getSubKind() == MemRegionKind; 526218887Sdim } 527218887Sdim}; 528218887Sdim 529218887Sdimclass ConcreteInt : public Loc { 530218887Sdimpublic: 531218887Sdim explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} 532218887Sdim 533218887Sdim const llvm::APSInt& getValue() const { 534218887Sdim return *static_cast<const llvm::APSInt*>(Data); 535218887Sdim } 536218887Sdim 537218887Sdim // Transfer functions for binary/unary operations on ConcreteInts. 538218887Sdim SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, 539218887Sdim const ConcreteInt& R) const; 540218887Sdim 541249423Sdimprivate: 542249423Sdim friend class SVal; 543249423Sdim ConcreteInt() {} 544249423Sdim static bool isKind(const SVal& V) { 545249423Sdim return V.getBaseKind() == LocKind && 546249423Sdim V.getSubKind() == ConcreteIntKind; 547218887Sdim } 548218887Sdim 549249423Sdim static bool isKind(const Loc& V) { 550249423Sdim return V.getSubKind() == ConcreteIntKind; 551218887Sdim } 552218887Sdim}; 553218887Sdim 554218887Sdim} // end ento::loc namespace 555218887Sdim 556249423Sdim} // end ento namespace 557249423Sdim 558218887Sdim} // end clang namespace 559218887Sdim 560218887Sdimnamespace llvm { 561226633Sdimstatic inline raw_ostream &operator<<(raw_ostream &os, 562218887Sdim clang::ento::SVal V) { 563218887Sdim V.dumpToStream(os); 564218887Sdim return os; 565218887Sdim} 566218887Sdim 567249423Sdimtemplate <typename T> struct isPodLike; 568249423Sdimtemplate <> struct isPodLike<clang::ento::SVal> { 569249423Sdim static const bool value = true; 570249423Sdim}; 571249423Sdim 572218887Sdim} // end llvm namespace 573218887Sdim 574218887Sdim#endif 575