//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
//  This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
 
//  interfaces, and also FullSValVisitor, which visits all three hierarchies.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
 
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
 
 
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 
 
 
namespace clang {
 
 
 
namespace ento {
 
 
 
/// SValVisitor - this class implements a simple visitor for SVal
 
/// subclasses.
 
template <typename ImplClass, typename RetTy = void> class SValVisitor {
 
public:
 
 
 
#define DISPATCH(NAME, CLASS) \
 
  return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
 
 
 
  RetTy Visit(SVal V) {
 
    // Dispatch to VisitFooVal for each FooVal.
 
    // Take namespaces (loc:: and nonloc::) into account.
 
    switch (V.getBaseKind()) {
 
#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
 
    case SVal::LocKind:
 
      switch (V.getSubKind()) {
 
#define LOC_SVAL(Id, Parent) \
 
      case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
 
      }
 
      llvm_unreachable("Unknown Loc sub-kind!");
 
    case SVal::NonLocKind:
 
      switch (V.getSubKind()) {
 
#define NONLOC_SVAL(Id, Parent) \
 
      case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
 
      }
 
      llvm_unreachable("Unknown NonLoc sub-kind!");
 
    }
 
    llvm_unreachable("Unknown SVal kind!");
 
  }
 
 
 
#define BASIC_SVAL(Id, Parent) \
 
  RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
 
#define ABSTRACT_SVAL(Id, Parent) \
 
  BASIC_SVAL(Id, Parent)
 
#define LOC_SVAL(Id, Parent) \
 
  RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
 
#define NONLOC_SVAL(Id, Parent) \
 
  RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
 
 
 
  // Base case, ignore it. :)
 
  RetTy VisitSVal(SVal V) { return RetTy(); }
 
 
 
#undef DISPATCH
 
};
 
 
 
/// SymExprVisitor - this class implements a simple visitor for SymExpr
 
/// subclasses.
 
template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
 
public:
 
 
 
#define DISPATCH(CLASS) \
 
    return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
 
 
 
  RetTy Visit(SymbolRef S) {
 
    // Dispatch to VisitSymbolFoo for each SymbolFoo.
 
    switch (S->getKind()) {
 
#define SYMBOL(Id, Parent) \
 
    case SymExpr::Id ## Kind: DISPATCH(Id);
 
#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
 
    }
 
    llvm_unreachable("Unknown SymExpr kind!");
 
  }
 
 
 
  // If the implementation chooses not to implement a certain visit method, fall
 
  // back on visiting the superclass.
 
#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
 
#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
 
#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
 
 
 
  // Base case, ignore it. :)
 
  RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
 
 
 
#undef DISPATCH
 
};
 
 
 
/// MemRegionVisitor - this class implements a simple visitor for MemRegion
 
/// subclasses.
 
template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
 
public:
 
 
 
#define DISPATCH(CLASS) \
 
  return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
 
 
 
  RetTy Visit(const MemRegion *R) {
 
    // Dispatch to VisitFooRegion for each FooRegion.
 
    switch (R->getKind()) {
 
#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
 
#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
 
    }
 
    llvm_unreachable("Unknown MemRegion kind!");
 
  }
 
 
 
  // If the implementation chooses not to implement a certain visit method, fall
 
  // back on visiting the superclass.
 
#define REGION(Id, Parent) \
 
  RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
 
#define ABSTRACT_REGION(Id, Parent) \
 
  REGION(Id, Parent)
 
#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
 
 
 
  // Base case, ignore it. :)
 
  RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
 
 
 
#undef DISPATCH
 
};
 
 
 
/// FullSValVisitor - a convenient mixed visitor for all three:
 
/// SVal, SymExpr and MemRegion subclasses.
 
template <typename ImplClass, typename RetTy = void>
 
class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
 
                        public SymExprVisitor<ImplClass, RetTy>,
 
                        public MemRegionVisitor<ImplClass, RetTy> {
 
public:
 
  using SValVisitor<ImplClass, RetTy>::Visit;
 
  using SymExprVisitor<ImplClass, RetTy>::Visit;
 
  using MemRegionVisitor<ImplClass, RetTy>::Visit;
 
};
 
 
 
} // end namespace ento
 
 
 
} // end namespace clang
 
 
 
#endif