1//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
10//  interfaces, and also FullSValVisitor, which visits all three hierarchies.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
15#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
16
17#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
20
21namespace clang {
22
23namespace ento {
24
25/// SValVisitor - this class implements a simple visitor for SVal
26/// subclasses.
27template <typename ImplClass, typename RetTy = void> class SValVisitor {
28public:
29
30#define DISPATCH(NAME, CLASS) \
31  return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
32
33  RetTy Visit(SVal V) {
34    // Dispatch to VisitFooVal for each FooVal.
35    // Take namespaces (loc:: and nonloc::) into account.
36    switch (V.getBaseKind()) {
37#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
38#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
39    case SVal::LocKind:
40      switch (V.getSubKind()) {
41#define LOC_SVAL(Id, Parent) \
42      case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
43#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
44      }
45      llvm_unreachable("Unknown Loc sub-kind!");
46    case SVal::NonLocKind:
47      switch (V.getSubKind()) {
48#define NONLOC_SVAL(Id, Parent) \
49      case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
50#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
51      }
52      llvm_unreachable("Unknown NonLoc sub-kind!");
53    }
54    llvm_unreachable("Unknown SVal kind!");
55  }
56
57#define BASIC_SVAL(Id, Parent) \
58  RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
59#define ABSTRACT_SVAL(Id, Parent) \
60  BASIC_SVAL(Id, Parent)
61#define LOC_SVAL(Id, Parent) \
62  RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
63#define NONLOC_SVAL(Id, Parent) \
64  RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
65#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
66
67  // Base case, ignore it. :)
68  RetTy VisitSVal(SVal V) { return RetTy(); }
69
70#undef DISPATCH
71};
72
73/// SymExprVisitor - this class implements a simple visitor for SymExpr
74/// subclasses.
75template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
76public:
77
78#define DISPATCH(CLASS) \
79    return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
80
81  RetTy Visit(SymbolRef S) {
82    // Dispatch to VisitSymbolFoo for each SymbolFoo.
83    switch (S->getKind()) {
84#define SYMBOL(Id, Parent) \
85    case SymExpr::Id ## Kind: DISPATCH(Id);
86#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
87    }
88    llvm_unreachable("Unknown SymExpr kind!");
89  }
90
91  // If the implementation chooses not to implement a certain visit method, fall
92  // back on visiting the superclass.
93#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
94#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
95#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
96
97  // Base case, ignore it. :)
98  RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
99
100#undef DISPATCH
101};
102
103/// MemRegionVisitor - this class implements a simple visitor for MemRegion
104/// subclasses.
105template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
106public:
107
108#define DISPATCH(CLASS) \
109  return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
110
111  RetTy Visit(const MemRegion *R) {
112    // Dispatch to VisitFooRegion for each FooRegion.
113    switch (R->getKind()) {
114#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
115#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
116    }
117    llvm_unreachable("Unknown MemRegion kind!");
118  }
119
120  // If the implementation chooses not to implement a certain visit method, fall
121  // back on visiting the superclass.
122#define REGION(Id, Parent) \
123  RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
124#define ABSTRACT_REGION(Id, Parent) \
125  REGION(Id, Parent)
126#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
127
128  // Base case, ignore it. :)
129  RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
130
131#undef DISPATCH
132};
133
134/// FullSValVisitor - a convenient mixed visitor for all three:
135/// SVal, SymExpr and MemRegion subclasses.
136template <typename ImplClass, typename RetTy = void>
137class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
138                        public SymExprVisitor<ImplClass, RetTy>,
139                        public MemRegionVisitor<ImplClass, RetTy> {
140public:
141  using SValVisitor<ImplClass, RetTy>::Visit;
142  using SymExprVisitor<ImplClass, RetTy>::Visit;
143  using MemRegionVisitor<ImplClass, RetTy>::Visit;
144};
145
146} // end namespace ento
147
148} // end namespace clang
149
150#endif
151