text: //==- MemRegion.h - Abstract memory regions 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 MemRegion and its subclasses.  MemRegion defines a
  //  partially-typed abstraction of memory useful for path-sensitive dataflow
  //  analyses.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
  #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
  
  #include "clang/AST/ASTContext.h"
  #include "clang/AST/CharUnits.h"
  #include "clang/AST/Decl.h"
  #include "clang/AST/DeclObjC.h"
  #include "clang/AST/DeclarationName.h"
  #include "clang/AST/Expr.h"
  #include "clang/AST/ExprObjC.h"
  #include "clang/AST/Type.h"
  #include "clang/Basic/LLVM.h"
  #include "clang/Basic/SourceLocation.h"
  #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
  #include "llvm/ADT/DenseMap.h"
  #include "llvm/ADT/FoldingSet.h"
  #include "llvm/ADT/Optional.h"
  #include "llvm/ADT/PointerIntPair.h"
  #include "llvm/Support/Allocator.h"
  #include "llvm/Support/Casting.h"
  #include <cassert>
  #include <cstdint>
  #include <limits>
  #include <string>
  #include <utility>
  
  namespace clang {
  
  class AnalysisDeclContext;
  class CXXRecordDecl;
  class Decl;
  class LocationContext;
  class StackFrameContext;
  
  namespace ento {
  
  class CodeTextRegion;
  class MemRegion;
  class MemRegionManager;
  class MemSpaceRegion;
  class SValBuilder;
  class SymbolicRegion;
  class VarRegion;
  
  /// Represent a region's offset within the top level base region.
  class RegionOffset {
    /// The base region.
    const MemRegion *R = nullptr;
  
    /// The bit offset within the base region. Can be negative.
    int64_t Offset;
  
  public:
    // We're using a const instead of an enumeration due to the size required;
    // Visual Studio will only create enumerations of size int, not long long.
    static const int64_t Symbolic = std::numeric_limits<int64_t>::max();
  
    RegionOffset() = default;
    RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {}
  
    const MemRegion *getRegion() const { return R; }
  
    bool hasSymbolicOffset() const { return Offset == Symbolic; }
  
    int64_t getOffset() const {
      assert(!hasSymbolicOffset());
      return Offset;
    }
  
    bool isValid() const { return R; }
  };
  
  //===----------------------------------------------------------------------===//
  // Base region classes.
  //===----------------------------------------------------------------------===//
  
  /// MemRegion - The root abstract class for all memory regions.
  class MemRegion : public llvm::FoldingSetNode {
  public:
    enum Kind {
  #define REGION(Id, Parent) Id ## Kind,
  #define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
  #include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
    };
  
  private:
    const Kind kind;
    mutable Optional<RegionOffset> cachedOffset;
  
  protected:
    MemRegion(Kind k) : kind(k) {}
    virtual ~MemRegion();
  
  public:
    ASTContext &getContext() const;
  
    virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
  
    virtual MemRegionManager* getMemRegionManager() const = 0;
  
    const MemSpaceRegion *getMemorySpace() const;
  
    const MemRegion *getBaseRegion() const;
  
    /// Check if the region is a subregion of the given region.
    /// Each region is a subregion of itself.
    virtual bool isSubRegionOf(const MemRegion *R) const;
  
    const MemRegion *StripCasts(bool StripBaseCasts = true) const;
  
    /// \brief If this is a symbolic region, returns the region. Otherwise,
    /// goes up the base chain looking for the first symbolic base region.
    const SymbolicRegion *getSymbolicBase() const;
  
    bool hasGlobalsOrParametersStorage() const;
  
    bool hasStackStorage() const;
    
    bool hasStackNonParametersStorage() const;
    
    bool hasStackParametersStorage() const;
  
    /// Compute the offset within the top level memory object.
    RegionOffset getAsOffset() const;
  
    /// \brief Get a string representation of a region for debug use.
    std::string getString() const;
  
    virtual void dumpToStream(raw_ostream &os) const;
  
    void dump() const;
  
    /// \brief Returns true if this region can be printed in a user-friendly way.
    virtual bool canPrintPretty() const;
  
    /// \brief Print the region for use in diagnostics.
    virtual void printPretty(raw_ostream &os) const;
  
    /// \brief Returns true if this region's textual representation can be used
    /// as part of a larger expression.
    virtual bool canPrintPrettyAsExpr() const;
  
    /// \brief Print the region as expression.
    ///
    /// When this region represents a subexpression, the method is for printing
    /// an expression containing it.
    virtual void printPrettyAsExpr(raw_ostream &os) const;
  
    Kind getKind() const { return kind; }
  
    template<typename RegionTy> const RegionTy* getAs() const;
  
    virtual bool isBoundable() const { return false; }
  
    /// Get descriptive name for memory region. The name is obtained from
    /// the variable/field declaration retrieved from the memory region.
    /// Regions that point to an element of an array are returned as: "arr[0]".
    /// Regions that point to a struct are returned as: "st.var".
    //
    /// \param UseQuotes Set if the name should be quoted.
    ///
    /// \returns variable name for memory region
    std::string getDescriptiveName(bool UseQuotes = true) const;
  
    /// Retrieve source range from memory region. The range retrieval
    /// is based on the decl obtained from the memory region.
    /// For a VarRegion the range of the base region is returned.
    /// For a FieldRegion the range of the field is returned.
    /// If no declaration is found, an empty source range is returned.
    /// The client is responsible for checking if the returned range is valid.
    ///
    /// \returns source range for declaration retrieved from memory region
    SourceRange sourceRange() const;
  };
  
  /// MemSpaceRegion - A memory region that represents a "memory space";
  ///  for example, the set of global variables, the stack frame, etc.
  class MemSpaceRegion : public MemRegion {
  protected:
    MemRegionManager *Mgr;
  
    MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
      assert(classof(this));
      assert(mgr);
    }
  
    MemRegionManager* getMemRegionManager() const override { return Mgr; }
  
  public:
    bool isBoundable() const override { return false; }
  
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    static bool classof(const MemRegion *R) {
      Kind k = R->getKind();
      return k >= BEGIN_MEMSPACES && k <= END_MEMSPACES;
    }
  };
  
  /// CodeSpaceRegion - The memory space that holds the executable code of
  /// functions and blocks.
  class CodeSpaceRegion : public MemSpaceRegion {
    friend class MemRegionManager;
  
    CodeSpaceRegion(MemRegionManager *mgr)
        : MemSpaceRegion(mgr, CodeSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == CodeSpaceRegionKind;
    }
  };
  
  class GlobalsSpaceRegion : public MemSpaceRegion {
    virtual void anchor();
  
  protected:
    GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) {
      assert(classof(this));
    }
  
  public:
    static bool classof(const MemRegion *R) {
      Kind k = R->getKind();
      return k >= BEGIN_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
    }
  };
  
  /// \brief The region of the static variables within the current CodeTextRegion
  /// scope.
  ///
  /// Currently, only the static locals are placed there, so we know that these
  /// variables do not get invalidated by calls to other functions.
  class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
    friend class MemRegionManager;
  
    const CodeTextRegion *CR;
    
    StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
        : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
      assert(cr);
    }
  
  public:
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    const CodeTextRegion *getCodeRegion() const { return CR; }
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == StaticGlobalSpaceRegionKind;
    }
  };
  
  /// \brief The region for all the non-static global variables.
  ///
  /// This class is further split into subclasses for efficient implementation of
  /// invalidating a set of related global values as is done in
  /// RegionStoreManager::invalidateRegions (instead of finding all the dependent
  /// globals, we invalidate the whole parent region).
  class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
    void anchor() override;
  
  protected:
    NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
        : GlobalsSpaceRegion(mgr, k) {
      assert(classof(this));
    }
  
  public:
    static bool classof(const MemRegion *R) {
      Kind k = R->getKind();
      return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES &&
             k <= END_NON_STATIC_GLOBAL_MEMSPACES;
    }
  };
  
  /// \brief The region containing globals which are defined in system/external
  /// headers and are considered modifiable by system calls (ex: errno).
  class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion {
    friend class MemRegionManager;
  
    GlobalSystemSpaceRegion(MemRegionManager *mgr)
        : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == GlobalSystemSpaceRegionKind;
    }
  };
  
  /// \brief The region containing globals which are considered not to be modified
  /// or point to data which could be modified as a result of a function call
  /// (system or internal). Ex: Const global scalars would be modeled as part of
  /// this region. This region also includes most system globals since they have
  /// low chance of being modified.
  class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion {
    friend class MemRegionManager;
  
    GlobalImmutableSpaceRegion(MemRegionManager *mgr)
        : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == GlobalImmutableSpaceRegionKind;
    }
  };
  
  /// \brief The region containing globals which can be modified by calls to
  /// "internally" defined functions - (for now just) functions other then system
  /// calls.
  class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion {
    friend class MemRegionManager;
  
    GlobalInternalSpaceRegion(MemRegionManager *mgr)
        : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == GlobalInternalSpaceRegionKind;
    }
  };
  
  class HeapSpaceRegion : public MemSpaceRegion {
    friend class MemRegionManager;
    
    HeapSpaceRegion(MemRegionManager *mgr)
        : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == HeapSpaceRegionKind;
    }
  };
    
  class UnknownSpaceRegion : public MemSpaceRegion {
    friend class MemRegionManager;
  
    UnknownSpaceRegion(MemRegionManager *mgr)
        : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == UnknownSpaceRegionKind;
    }
  };
  
  class StackSpaceRegion : public MemSpaceRegion {
    virtual void anchor();
  
    const StackFrameContext *SFC;
  
  protected:
    StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
        : MemSpaceRegion(mgr, k), SFC(sfc) {
      assert(classof(this));
      assert(sfc);
    }
  
  public:
    const StackFrameContext *getStackFrame() const { return SFC; }
  
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    static bool classof(const MemRegion *R) {
      Kind k = R->getKind();
      return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES;
    }
  };
  
  class StackLocalsSpaceRegion : public StackSpaceRegion {
    friend class MemRegionManager;
  
    StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
        : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == StackLocalsSpaceRegionKind;
    }
  };
  
  class StackArgumentsSpaceRegion : public StackSpaceRegion {
  private:
    friend class MemRegionManager;
  
    StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
        : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
  
  public:
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *R) {
      return R->getKind() == StackArgumentsSpaceRegionKind;
    }
  };
  
  /// SubRegion - A region that subsets another larger region.  Most regions
  ///  are subclasses of SubRegion.
  class SubRegion : public MemRegion {
    virtual void anchor();
  
  protected:
    const MemRegion* superRegion;
  
    SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) {
      assert(classof(this));
      assert(sReg);
    }
  
  public:
    const MemRegion* getSuperRegion() const {
      return superRegion;
    }
  
    /// getExtent - Returns the size of the region in bytes.
    virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const {
      return UnknownVal();
    }
  
    MemRegionManager* getMemRegionManager() const override;
  
    bool isSubRegionOf(const MemRegion* R) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() > END_MEMSPACES;
    }
  };
  
  //===----------------------------------------------------------------------===//
  // MemRegion subclasses.
  //===----------------------------------------------------------------------===//
  
  /// AllocaRegion - A region that represents an untyped blob of bytes created
  ///  by a call to 'alloca'.
  class AllocaRegion : public SubRegion {
    friend class MemRegionManager;
  
    // Block counter. Used to distinguish different pieces of memory allocated by
    // alloca at the same call site.
    unsigned Cnt;
  
    const Expr *Ex;
  
    AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion)
        : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {
      assert(Ex);
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex,
                              unsigned Cnt, const MemRegion *superRegion);
  
  public:
    const Expr *getExpr() const { return Ex; }
  
    bool isBoundable() const override { return true; }
  
    DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == AllocaRegionKind;
    }
  };
  
  /// TypedRegion - An abstract class representing regions that are typed.
  class TypedRegion : public SubRegion {
    void anchor() override;
  
  protected:
    TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) {
      assert(classof(this));
    }
  
  public:
    virtual QualType getLocationType() const = 0;
  
    QualType getDesugaredLocationType(ASTContext &Context) const {
      return getLocationType().getDesugaredType(Context);
    }
  
    bool isBoundable() const override { return true; }
  
    static bool classof(const MemRegion* R) {
      unsigned k = R->getKind();
      return k >= BEGIN_TYPED_REGIONS && k <= END_TYPED_REGIONS;
    }
  };
  
  /// TypedValueRegion - An abstract class representing regions having a typed value.
  class TypedValueRegion : public TypedRegion {
    void anchor() override;
  
  protected:
    TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {
      assert(classof(this));
    }
  
  public:
    virtual QualType getValueType() const = 0;
  
    QualType getLocationType() const override {
      // FIXME: We can possibly optimize this later to cache this value.
      QualType T = getValueType();
      ASTContext &ctx = getContext();
      if (T->getAs<ObjCObjectType>())
        return ctx.getObjCObjectPointerType(T);
      return ctx.getPointerType(getValueType());
    }
  
    QualType getDesugaredValueType(ASTContext &Context) const {
      QualType T = getValueType();
      return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
    }
  
    DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
  
    static bool classof(const MemRegion* R) {
      unsigned k = R->getKind();
      return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
    }
  };
  
  class CodeTextRegion : public TypedRegion {
    void anchor() override;
  
  protected:
    CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) {
      assert(classof(this));
    }
  
  public:
    bool isBoundable() const override { return false; }
  
    static bool classof(const MemRegion* R) {
      Kind k = R->getKind();
      return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS;
    }
  };
  
  /// FunctionCodeRegion - A region that represents code texts of function.
  class FunctionCodeRegion : public CodeTextRegion {
    friend class MemRegionManager;
  
    const NamedDecl *FD;
  
    FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg)
        : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
      assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD,
                              const MemRegion*);
  
  public:
    QualType getLocationType() const override {
      const ASTContext &Ctx = getContext();
      if (const auto *D = dyn_cast<FunctionDecl>(FD)) {
        return Ctx.getPointerType(D->getType());
      }
  
      assert(isa<ObjCMethodDecl>(FD));
      assert(false && "Getting the type of ObjCMethod is not supported yet");
  
      // TODO: We might want to return a different type here (ex: id (*ty)(...))
      //       depending on how it is used.
      return {};
    }
  
    const NamedDecl *getDecl() const {
      return FD;
    }
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == FunctionCodeRegionKind;
    }
  };
    
  /// BlockCodeRegion - A region that represents code texts of blocks (closures).
  ///  Blocks are represented with two kinds of regions.  BlockCodeRegions
  ///  represent the "code", while BlockDataRegions represent instances of blocks,
  ///  which correspond to "code+data".  The distinction is important, because
  ///  like a closure a block captures the values of externally referenced
  ///  variables.
  class BlockCodeRegion : public CodeTextRegion {
    friend class MemRegionManager;
  
    const BlockDecl *BD;
    AnalysisDeclContext *AC;
    CanQualType locTy;
  
    BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
                    AnalysisDeclContext *ac, const CodeSpaceRegion* sreg)
        : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {
      assert(bd);
      assert(ac);
      assert(lTy->getTypePtr()->isBlockPointerType());
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
                              CanQualType, const AnalysisDeclContext*,
                              const MemRegion*);
  
  public:
    QualType getLocationType() const override {
      return locTy;
    }
    
    const BlockDecl *getDecl() const {
      return BD;
    }
  
    AnalysisDeclContext *getAnalysisDeclContext() const { return AC; }
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == BlockCodeRegionKind;
    }
  };
    
  /// BlockDataRegion - A region that represents a block instance.
  ///  Blocks are represented with two kinds of regions.  BlockCodeRegions
  ///  represent the "code", while BlockDataRegions represent instances of blocks,
  ///  which correspond to "code+data".  The distinction is important, because
  ///  like a closure a block captures the values of externally referenced
  ///  variables.
  class BlockDataRegion : public TypedRegion {
    friend class MemRegionManager;
  
    const BlockCodeRegion *BC;
    const LocationContext *LC; // Can be null
    unsigned BlockCount;
    void *ReferencedVars = nullptr;
    void *OriginalVars = nullptr;
  
    BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
                    unsigned count, const MemSpaceRegion *sreg)
        : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
          BlockCount(count) {
      assert(bc);
      assert(lc);
      assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
             isa<StackLocalsSpaceRegion>(sreg) ||
             isa<UnknownSpaceRegion>(sreg));
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
                              const LocationContext *, unsigned,
                              const MemRegion *);
  
  public:
    const BlockCodeRegion *getCodeRegion() const { return BC; }
  
    const BlockDecl *getDecl() const { return BC->getDecl(); }
  
    QualType getLocationType() const override { return BC->getLocationType(); }
  
    class referenced_vars_iterator {
      const MemRegion * const *R;
      const MemRegion * const *OriginalR;
  
    public:
      explicit referenced_vars_iterator(const MemRegion * const *r,
                                        const MemRegion * const *originalR)
          : R(r), OriginalR(originalR) {}
  
      const VarRegion *getCapturedRegion() const {
        return cast<VarRegion>(*R);
      }
  
      const VarRegion *getOriginalRegion() const {
        return cast<VarRegion>(*OriginalR);
      }
  
      bool operator==(const referenced_vars_iterator &I) const {
        assert((R == nullptr) == (I.R == nullptr));
        return I.R == R;
      }
  
      bool operator!=(const referenced_vars_iterator &I) const {
        assert((R == nullptr) == (I.R == nullptr));
        return I.R != R;
      }
  
      referenced_vars_iterator &operator++() {
        ++R;
        ++OriginalR;
        return *this;
      }
    };
  
    /// Return the original region for a captured region, if
    /// one exists.
    const VarRegion *getOriginalRegion(const VarRegion *VR) const;
        
    referenced_vars_iterator referenced_vars_begin() const;
    referenced_vars_iterator referenced_vars_end() const;  
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == BlockDataRegionKind;
    }
  
  private:
    void LazyInitializeReferencedVars();
    std::pair<const VarRegion *, const VarRegion *>
    getCaptureRegions(const VarDecl *VD);
  };
  
  /// SymbolicRegion - A special, "non-concrete" region. Unlike other region
  ///  classes, SymbolicRegion represents a region that serves as an alias for
  ///  either a real region, a NULL pointer, etc.  It essentially is used to
  ///  map the concept of symbolic values into the domain of regions.  Symbolic
  ///  regions do not need to be typed.
  class SymbolicRegion : public SubRegion {
    friend class MemRegionManager;
  
    const SymbolRef sym;
  
    SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg)
        : SubRegion(sreg, SymbolicRegionKind), sym(s) {
      assert(s);
      assert(s->getType()->isAnyPointerType() ||
             s->getType()->isReferenceType() ||
             s->getType()->isBlockPointerType());
      assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg));
    }
  
  public:
    SymbolRef getSymbol() const { return sym; }
  
    bool isBoundable() const override { return true; }
  
    DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID,
                              SymbolRef sym,
                              const MemRegion* superRegion);
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == SymbolicRegionKind;
    }
  };
  
  /// StringRegion - Region associated with a StringLiteral.
  class StringRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    const StringLiteral *Str;
  
    StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg)
        : TypedValueRegion(sreg, StringRegionKind), Str(str) {
      assert(str);
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID &ID,
                              const StringLiteral *Str,
                              const MemRegion *superRegion);
  
  public:
    const StringLiteral *getStringLiteral() const { return Str; }
  
    QualType getValueType() const override { return Str->getType(); }
  
    DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
  
    bool isBoundable() const override { return false; }
  
    void Profile(llvm::FoldingSetNodeID& ID) const override {
      ProfileRegion(ID, Str, superRegion);
    }
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == StringRegionKind;
    }
  };
    
  /// The region associated with an ObjCStringLiteral.
  class ObjCStringRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    const ObjCStringLiteral *Str;
  
    ObjCStringRegion(const ObjCStringLiteral *str,
                     const GlobalInternalSpaceRegion *sreg)
        : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {
      assert(str);
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID &ID,
                              const ObjCStringLiteral *Str,
                              const MemRegion *superRegion);
    
  public:
    const ObjCStringLiteral *getObjCStringLiteral() const { return Str; }
  
    QualType getValueType() const override { return Str->getType(); }
  
    bool isBoundable() const override { return false; }
  
    void Profile(llvm::FoldingSetNodeID& ID) const override {
      ProfileRegion(ID, Str, superRegion);
    }
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == ObjCStringRegionKind;
    }
  };
  
  /// CompoundLiteralRegion - A memory region representing a compound literal.
  ///   Compound literals are essentially temporaries that are stack allocated
  ///   or in the global constant pool.
  class CompoundLiteralRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    const CompoundLiteralExpr *CL;
  
    CompoundLiteralRegion(const CompoundLiteralExpr *cl,
                          const MemSpaceRegion *sReg)
        : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {
      assert(cl);
      assert(isa<GlobalInternalSpaceRegion>(sReg) ||
             isa<StackLocalsSpaceRegion>(sReg));
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID,
                              const CompoundLiteralExpr *CL,
                              const MemRegion* superRegion);
  
  public:
    QualType getValueType() const override { return CL->getType(); }
  
    bool isBoundable() const override { return !CL->isFileScope(); }
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    const CompoundLiteralExpr *getLiteralExpr() const { return CL; }
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == CompoundLiteralRegionKind;
    }
  };
  
  class DeclRegion : public TypedValueRegion {
  protected:
    const Decl *D;
  
    DeclRegion(const Decl *d, const MemRegion *sReg, Kind k)
        : TypedValueRegion(sReg, k), D(d) {
      assert(classof(this));
      assert(d);
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D,
                        const MemRegion* superRegion, Kind k);
  
  public:
    const Decl *getDecl() const { return D; }
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static bool classof(const MemRegion* R) {
      unsigned k = R->getKind();
      return k >= BEGIN_DECL_REGIONS && k <= END_DECL_REGIONS;
    }
  };
  
  class VarRegion : public DeclRegion {
    friend class MemRegionManager;
  
    // Constructors and private methods.
    VarRegion(const VarDecl *vd, const MemRegion *sReg)
        : DeclRegion(vd, sReg, VarRegionKind) {
      // VarRegion appears in unknown space when it's a block variable as seen
      // from a block using it, when this block is analyzed at top-level.
      // Other block variables appear within block data regions,
      // which, unlike everything else on this list, are not memory spaces.
      assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) ||
             isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg));
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD,
                              const MemRegion *superRegion) {
      DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
    }
  
  public:
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    const VarDecl *getDecl() const { return cast<VarDecl>(D); }
  
    const StackFrameContext *getStackFrame() const;
  
    QualType getValueType() const override {
      // FIXME: We can cache this if needed.
      return getDecl()->getType();
    }
  
    void dumpToStream(raw_ostream &os) const override;
  
    bool canPrintPrettyAsExpr() const override;
  
    void printPrettyAsExpr(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == VarRegionKind;
    }
  };
    
  /// CXXThisRegion - Represents the region for the implicit 'this' parameter
  ///  in a call to a C++ method.  This region doesn't represent the object
  ///  referred to by 'this', but rather 'this' itself.
  class CXXThisRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    CXXThisRegion(const PointerType *thisPointerTy,
                  const StackArgumentsSpaceRegion *sReg)
        : TypedValueRegion(sReg, CXXThisRegionKind),
          ThisPointerTy(thisPointerTy) {
      assert(ThisPointerTy->getPointeeType()->getAsCXXRecordDecl() &&
             "Invalid region type!");
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID &ID,
                              const PointerType *PT,
                              const MemRegion *sReg);
  
  public:
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    QualType getValueType() const override {
      return QualType(ThisPointerTy, 0);
    }
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == CXXThisRegionKind;
    }
  
  private:
    const PointerType *ThisPointerTy;
  };
  
  class FieldRegion : public DeclRegion {
    friend class MemRegionManager;
  
    FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
        : DeclRegion(fd, sReg, FieldRegionKind) {}
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
                              const MemRegion* superRegion) {
      DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
    }
  
  public:
    const FieldDecl *getDecl() const { return cast<FieldDecl>(D); }
  
    QualType getValueType() const override {
      // FIXME: We can cache this if needed.
      return getDecl()->getType();
    }
  
    DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    bool canPrintPretty() const override;
    void printPretty(raw_ostream &os) const override;
    bool canPrintPrettyAsExpr() const override;
    void printPrettyAsExpr(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == FieldRegionKind;
    }
  };
  
  class ObjCIvarRegion : public DeclRegion {
    friend class MemRegionManager;
  
    ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg);
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd,
                              const MemRegion* superRegion);
  
  public:
    const ObjCIvarDecl *getDecl() const;
    QualType getValueType() const override;
  
    bool canPrintPrettyAsExpr() const override;
    void printPrettyAsExpr(raw_ostream &os) const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == ObjCIvarRegionKind;
    }
  };
  
  //===----------------------------------------------------------------------===//
  // Auxiliary data classes for use with MemRegions.
  //===----------------------------------------------------------------------===//
  
  class RegionRawOffset {
    friend class ElementRegion;
  
    const MemRegion *Region;
    CharUnits Offset;
  
    RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero())
        : Region(reg), Offset(offset) {}
  
  public:
    // FIXME: Eventually support symbolic offsets.
    CharUnits getOffset() const { return Offset; }
    const MemRegion *getRegion() const { return Region; }
  
    void dumpToStream(raw_ostream &os) const;
    void dump() const;
  };
  
  /// \brief ElementRegin is used to represent both array elements and casts.
  class ElementRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    QualType ElementType;
    NonLoc Index;
  
    ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg)
        : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType),
          Index(Idx) {
      assert((!Idx.getAs<nonloc::ConcreteInt>() ||
              Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
             "The index must be signed");
      assert(!elementType.isNull() && !elementType->isVoidType() &&
             "Invalid region type!");
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
                              SVal Idx, const MemRegion* superRegion);
  
  public:
    NonLoc getIndex() const { return Index; }
  
    QualType getValueType() const override { return ElementType; }
  
    QualType getElementType() const { return ElementType; }
  
    /// Compute the offset within the array. The array might also be a subobject.
    RegionRawOffset getAsArrayOffset() const;
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID& ID) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == ElementRegionKind;
    }
  };
  
  // C++ temporary object associated with an expression.
  class CXXTempObjectRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    Expr const *Ex;
  
    CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg)
        : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {
      assert(E);
      assert(isa<StackLocalsSpaceRegion>(sReg) ||
             isa<GlobalInternalSpaceRegion>(sReg));
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID &ID,
                              Expr const *E, const MemRegion *sReg);
  
  public:
    const Expr *getExpr() const { return Ex; }
  
    QualType getValueType() const override { return Ex->getType(); }
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    static bool classof(const MemRegion* R) {
      return R->getKind() == CXXTempObjectRegionKind;
    }
  };
  
  // CXXBaseObjectRegion represents a base object within a C++ object. It is 
  // identified by the base class declaration and the region of its parent object.
  class CXXBaseObjectRegion : public TypedValueRegion {
    friend class MemRegionManager;
  
    llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
  
    CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
                        const SubRegion *SReg)
        : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {
      assert(RD);
    }
  
    static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
                              bool IsVirtual, const MemRegion *SReg);
  
  public:
    const CXXRecordDecl *getDecl() const { return Data.getPointer(); }
    bool isVirtual() const { return Data.getInt(); }
  
    QualType getValueType() const override;
  
    void dumpToStream(raw_ostream &os) const override;
  
    void Profile(llvm::FoldingSetNodeID &ID) const override;
  
    bool canPrintPrettyAsExpr() const override;
  
    void printPrettyAsExpr(raw_ostream &os) const override;
  
    static bool classof(const MemRegion *region) {
      return region->getKind() == CXXBaseObjectRegionKind;
    }
  };
  
  template<typename RegionTy>
  const RegionTy* MemRegion::getAs() const {
    if (const auto *RT = dyn_cast<RegionTy>(this))
      return RT;
  
    return nullptr;
  }
  
  //===----------------------------------------------------------------------===//
  // MemRegionManager - Factory object for creating regions.
  //===----------------------------------------------------------------------===//
  
  class MemRegionManager {
    ASTContext &C;
    llvm::BumpPtrAllocator& A;
    llvm::FoldingSet<MemRegion> Regions;
  
    GlobalInternalSpaceRegion *InternalGlobals = nullptr;
    GlobalSystemSpaceRegion *SystemGlobals = nullptr;
    GlobalImmutableSpaceRegion *ImmutableGlobals = nullptr;
  
    llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> 
      StackLocalsSpaceRegions;
    llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *>
      StackArgumentsSpaceRegions;
    llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *>
      StaticsGlobalSpaceRegions;
  
    HeapSpaceRegion *heap = nullptr;
    UnknownSpaceRegion *unknown = nullptr;
    CodeSpaceRegion *code = nullptr;
  
  public:
    MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {}
    ~MemRegionManager();
  
    ASTContext &getContext() { return C; }
    
    llvm::BumpPtrAllocator &getAllocator() { return A; }
  
    /// getStackLocalsRegion - Retrieve the memory region associated with the
    ///  specified stack frame.
    const StackLocalsSpaceRegion *
    getStackLocalsRegion(const StackFrameContext *STC);
  
    /// getStackArgumentsRegion - Retrieve the memory region associated with
    ///  function/method arguments of the specified stack frame.
    const StackArgumentsSpaceRegion *
    getStackArgumentsRegion(const StackFrameContext *STC);
  
    /// getGlobalsRegion - Retrieve the memory region associated with
    ///  global variables.
    const GlobalsSpaceRegion *getGlobalsRegion(
        MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind,
        const CodeTextRegion *R = nullptr);
  
    /// getHeapRegion - Retrieve the memory region associated with the
    ///  generic "heap".
    const HeapSpaceRegion *getHeapRegion();
  
    /// getUnknownRegion - Retrieve the memory region associated with unknown
    /// memory space.
    const UnknownSpaceRegion *getUnknownRegion();
  
    const CodeSpaceRegion *getCodeRegion();
  
    /// getAllocaRegion - Retrieve a region associated with a call to alloca().
    const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
                                        const LocationContext *LC);
  
    /// getCompoundLiteralRegion - Retrieve the region associated with a
    ///  given CompoundLiteral.
    const CompoundLiteralRegion*
    getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
                             const LocationContext *LC);
    
    /// getCXXThisRegion - Retrieve the [artificial] region associated with the
    ///  parameter 'this'.
    const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
                                          const LocationContext *LC);
  
    /// \brief Retrieve or create a "symbolic" memory region.
    const SymbolicRegion* getSymbolicRegion(SymbolRef Sym);
  
    /// \brief Return a unique symbolic region belonging to heap memory space.
    const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym);
  
    const StringRegion *getStringRegion(const StringLiteral *Str);
  
    const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str);
  
    /// getVarRegion - Retrieve or create the memory region associated with
    ///  a specified VarDecl and LocationContext.
    const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
  
    /// getVarRegion - Retrieve or create the memory region associated with
    ///  a specified VarDecl and super region.
    const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR);
  
    /// getElementRegion - Retrieve the memory region associated with the
    ///  associated element type, index, and super region.
    const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx,
                                          const SubRegion *superRegion,
                                          ASTContext &Ctx);
  
    const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
                                                   const SubRegion *superRegion) {
      return getElementRegion(ER->getElementType(), ER->getIndex(),
                              superRegion, ER->getContext());
    }
  
    /// getFieldRegion - Retrieve or create the memory region associated with
    ///  a specified FieldDecl.  'superRegion' corresponds to the containing
    ///  memory region (which typically represents the memory representing
    ///  a structure or class).
    const FieldRegion *getFieldRegion(const FieldDecl *fd,
                                      const SubRegion* superRegion);
  
    const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
                                               const SubRegion *superRegion) {
      return getFieldRegion(FR->getDecl(), superRegion);
    }
  
    /// getObjCIvarRegion - Retrieve or create the memory region associated with
    ///   a specified Objective-c instance variable.  'superRegion' corresponds
    ///   to the containing region (which typically represents the Objective-C
    ///   object).
    const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd,
                                            const SubRegion* superRegion);
  
    const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
                                                      LocationContext const *LC);
  
    /// Create a CXXBaseObjectRegion with the given base class for region
    /// \p Super.
    ///
    /// The type of \p Super is assumed be a class deriving from \p BaseClass.
    const CXXBaseObjectRegion *
    getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super,
                           bool IsVirtual);
  
    /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
    /// super region.
    const CXXBaseObjectRegion *
    getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, 
                                    const SubRegion *superRegion) {
      return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
                                    baseReg->isVirtual());
    }
  
    const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD);
    const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD,
                                              CanQualType locTy,
                                              AnalysisDeclContext *AC);
    
    /// getBlockDataRegion - Get the memory region associated with an instance
    ///  of a block.  Unlike many other MemRegions, the LocationContext*
    ///  argument is allowed to be NULL for cases where we have no known
    ///  context.
    const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc,
                                              const LocationContext *lc,
                                              unsigned blockCount);
  
    /// Create a CXXTempObjectRegion for temporaries which are lifetime-extended
    /// by static references. This differs from getCXXTempObjectRegion in the
    /// super-region used.
    const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
  
  private:
    template <typename RegionTy, typename SuperTy,
              typename Arg1Ty>
    RegionTy* getSubRegion(const Arg1Ty arg1,
                           const SuperTy* superRegion);
  
    template <typename RegionTy, typename SuperTy,
              typename Arg1Ty, typename Arg2Ty>
    RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
                           const SuperTy* superRegion);
  
    template <typename RegionTy, typename SuperTy,
              typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
    RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
                           const Arg3Ty arg3,
                           const SuperTy* superRegion);
  
    template <typename REG>
    const REG* LazyAllocate(REG*& region);
    
    template <typename REG, typename ARG>
    const REG* LazyAllocate(REG*& region, ARG a);
  };
  
  //===----------------------------------------------------------------------===//
  // Out-of-line member definitions.
  //===----------------------------------------------------------------------===//
  
  inline ASTContext &MemRegion::getContext() const {
    return getMemRegionManager()->getContext();
  }
  
  //===----------------------------------------------------------------------===//
  // Means for storing region/symbol handling traits.
  //===----------------------------------------------------------------------===//
  
  /// Information about invalidation for a particular region/symbol.
  class RegionAndSymbolInvalidationTraits {
    using StorageTypeForKinds = unsigned char;
  
    llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap;
    llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap;
  
    using const_region_iterator =
        llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator;
    using const_symbol_iterator =
        llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator;
  
  public:
    /// \brief Describes different invalidation traits.
    enum InvalidationKinds {
      /// Tells that a region's contents is not changed.
      TK_PreserveContents = 0x1,
  
      /// Suppress pointer-escaping of a region.
      TK_SuppressEscape = 0x2,
  
      // Do not invalidate super region.
      TK_DoNotInvalidateSuperRegion = 0x4,
  
      /// When applied to a MemSpaceRegion, indicates the entire memory space
      /// should be invalidated.
      TK_EntireMemSpace = 0x8
  
      // Do not forget to extend StorageTypeForKinds if number of traits exceed 
      // the number of bits StorageTypeForKinds can store.
    };
  
    void setTrait(SymbolRef Sym, InvalidationKinds IK);
    void setTrait(const MemRegion *MR, InvalidationKinds IK);
    bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const;
    bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const;
  };
  
  //===----------------------------------------------------------------------===//
  // Pretty-printing regions.
  //===----------------------------------------------------------------------===//
  inline raw_ostream &operator<<(raw_ostream &os, const MemRegion *R) {
    R->dumpToStream(os);
    return os;
  }
  
  } // namespace ento
  
  } // namespace clang
  
  #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
  