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/MemRegion.h" |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
20 | |
21 | namespace clang { |
22 | |
23 | namespace ento { |
24 | |
25 | /// SValVisitor - this class implements a simple visitor for SVal |
26 | /// subclasses. |
27 | template <typename ImplClass, typename RetTy = void> class SValVisitor { |
28 | ImplClass &derived() { return *static_cast<ImplClass *>(this); } |
29 | |
30 | public: |
31 | RetTy Visit(SVal V) { |
32 | // Dispatch to VisitFooVal for each FooVal. |
33 | switch (V.getKind()) { |
34 | #define BASIC_SVAL(Id, Parent) \ |
35 | case SVal::Id##Kind: \ |
36 | return derived().Visit##Id(V.castAs<Id>()); |
37 | #define LOC_SVAL(Id, Parent) \ |
38 | case SVal::Loc##Id##Kind: \ |
39 | return derived().Visit##Id(V.castAs<loc::Id>()); |
40 | #define NONLOC_SVAL(Id, Parent) \ |
41 | case SVal::NonLoc##Id##Kind: \ |
42 | return derived().Visit##Id(V.castAs<nonloc::Id>()); |
43 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" |
44 | } |
45 | llvm_unreachable("Unknown SVal kind!" ); |
46 | } |
47 | |
48 | // Dispatch to the more generic handler as a default implementation. |
49 | #define BASIC_SVAL(Id, Parent) \ |
50 | RetTy Visit##Id(Id V) { return derived().Visit##Parent(V.castAs<Id>()); } |
51 | #define ABSTRACT_SVAL(Id, Parent) BASIC_SVAL(Id, Parent) |
52 | #define LOC_SVAL(Id, Parent) \ |
53 | RetTy Visit##Id(loc::Id V) { return derived().VisitLoc(V.castAs<Loc>()); } |
54 | #define NONLOC_SVAL(Id, Parent) \ |
55 | RetTy Visit##Id(nonloc::Id V) { \ |
56 | return derived().VisitNonLoc(V.castAs<NonLoc>()); \ |
57 | } |
58 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" |
59 | |
60 | // Base case, ignore it. :) |
61 | RetTy VisitSVal(SVal V) { return RetTy(); } |
62 | }; |
63 | |
64 | /// SymExprVisitor - this class implements a simple visitor for SymExpr |
65 | /// subclasses. |
66 | template <typename ImplClass, typename RetTy = void> class SymExprVisitor { |
67 | public: |
68 | |
69 | #define DISPATCH(CLASS) \ |
70 | return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S)) |
71 | |
72 | RetTy Visit(SymbolRef S) { |
73 | // Dispatch to VisitSymbolFoo for each SymbolFoo. |
74 | switch (S->getKind()) { |
75 | #define SYMBOL(Id, Parent) \ |
76 | case SymExpr::Id ## Kind: DISPATCH(Id); |
77 | #include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def" |
78 | } |
79 | llvm_unreachable("Unknown SymExpr kind!" ); |
80 | } |
81 | |
82 | // If the implementation chooses not to implement a certain visit method, fall |
83 | // back on visiting the superclass. |
84 | #define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); } |
85 | #define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent) |
86 | #include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def" |
87 | |
88 | // Base case, ignore it. :) |
89 | RetTy VisitSymExpr(SymbolRef S) { return RetTy(); } |
90 | |
91 | #undef DISPATCH |
92 | }; |
93 | |
94 | /// MemRegionVisitor - this class implements a simple visitor for MemRegion |
95 | /// subclasses. |
96 | template <typename ImplClass, typename RetTy = void> class MemRegionVisitor { |
97 | public: |
98 | |
99 | #define DISPATCH(CLASS) \ |
100 | return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R)) |
101 | |
102 | RetTy Visit(const MemRegion *R) { |
103 | // Dispatch to VisitFooRegion for each FooRegion. |
104 | switch (R->getKind()) { |
105 | #define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id); |
106 | #include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" |
107 | } |
108 | llvm_unreachable("Unknown MemRegion kind!" ); |
109 | } |
110 | |
111 | // If the implementation chooses not to implement a certain visit method, fall |
112 | // back on visiting the superclass. |
113 | #define REGION(Id, Parent) \ |
114 | RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); } |
115 | #define ABSTRACT_REGION(Id, Parent) \ |
116 | REGION(Id, Parent) |
117 | #include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def" |
118 | |
119 | // Base case, ignore it. :) |
120 | RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); } |
121 | |
122 | #undef DISPATCH |
123 | }; |
124 | |
125 | /// FullSValVisitor - a convenient mixed visitor for all three: |
126 | /// SVal, SymExpr and MemRegion subclasses. |
127 | template <typename ImplClass, typename RetTy = void> |
128 | class FullSValVisitor : public SValVisitor<ImplClass, RetTy>, |
129 | public SymExprVisitor<ImplClass, RetTy>, |
130 | public MemRegionVisitor<ImplClass, RetTy> { |
131 | public: |
132 | using SValVisitor<ImplClass, RetTy>::Visit; |
133 | using SymExprVisitor<ImplClass, RetTy>::Visit; |
134 | using MemRegionVisitor<ImplClass, RetTy>::Visit; |
135 | }; |
136 | |
137 | } // end namespace ento |
138 | |
139 | } // end namespace clang |
140 | |
141 | #endif |
142 | |