/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/ProgramPoint.h
Line | Count | Source (jump to first uncovered line) |
1 | | //==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- 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 interface ProgramPoint, which identifies a |
10 | | // distinct location in a function. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H |
15 | | #define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H |
16 | | |
17 | | #include "clang/Analysis/AnalysisDeclContext.h" |
18 | | #include "clang/Analysis/CFG.h" |
19 | | #include "llvm/ADT/DenseMap.h" |
20 | | #include "llvm/ADT/FoldingSet.h" |
21 | | #include "llvm/ADT/Optional.h" |
22 | | #include "llvm/ADT/PointerIntPair.h" |
23 | | #include "llvm/ADT/StringRef.h" |
24 | | #include "llvm/Support/Casting.h" |
25 | | #include "llvm/Support/DataTypes.h" |
26 | | #include <cassert> |
27 | | #include <string> |
28 | | #include <utility> |
29 | | |
30 | | namespace clang { |
31 | | |
32 | | class AnalysisDeclContext; |
33 | | class LocationContext; |
34 | | |
35 | | /// ProgramPoints can be "tagged" as representing points specific to a given |
36 | | /// analysis entity. Tags are abstract annotations, with an associated |
37 | | /// description and potentially other information. |
38 | | class ProgramPointTag { |
39 | | public: |
40 | 34.1k | ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} |
41 | | virtual ~ProgramPointTag(); |
42 | | virtual StringRef getTagDescription() const = 0; |
43 | | |
44 | | /// Used to implement 'isKind' in subclasses. |
45 | 849k | const void *getTagKind() const { return TagKind; } |
46 | | |
47 | | private: |
48 | | const void *const TagKind; |
49 | | }; |
50 | | |
51 | | class SimpleProgramPointTag : public ProgramPointTag { |
52 | | std::string Desc; |
53 | | public: |
54 | | SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); |
55 | | StringRef getTagDescription() const override; |
56 | | }; |
57 | | |
58 | | class ProgramPoint { |
59 | | public: |
60 | | enum Kind { BlockEdgeKind, |
61 | | BlockEntranceKind, |
62 | | BlockExitKind, |
63 | | PreStmtKind, |
64 | | PreStmtPurgeDeadSymbolsKind, |
65 | | PostStmtPurgeDeadSymbolsKind, |
66 | | PostStmtKind, |
67 | | PreLoadKind, |
68 | | PostLoadKind, |
69 | | PreStoreKind, |
70 | | PostStoreKind, |
71 | | PostConditionKind, |
72 | | PostLValueKind, |
73 | | PostAllocatorCallKind, |
74 | | MinPostStmtKind = PostStmtKind, |
75 | | MaxPostStmtKind = PostAllocatorCallKind, |
76 | | PostInitializerKind, |
77 | | CallEnterKind, |
78 | | CallExitBeginKind, |
79 | | CallExitEndKind, |
80 | | FunctionExitKind, |
81 | | PreImplicitCallKind, |
82 | | PostImplicitCallKind, |
83 | | MinImplicitCallKind = PreImplicitCallKind, |
84 | | MaxImplicitCallKind = PostImplicitCallKind, |
85 | | LoopExitKind, |
86 | | EpsilonKind}; |
87 | | |
88 | | private: |
89 | | const void *Data1; |
90 | | llvm::PointerIntPair<const void *, 2, unsigned> Data2; |
91 | | |
92 | | // The LocationContext could be NULL to allow ProgramPoint to be used in |
93 | | // context insensitive analysis. |
94 | | llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; |
95 | | |
96 | | llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; |
97 | | |
98 | | protected: |
99 | 14.4M | ProgramPoint() = default; |
100 | | ProgramPoint(const void *P, |
101 | | Kind k, |
102 | | const LocationContext *l, |
103 | | const ProgramPointTag *tag = nullptr) |
104 | | : Data1(P), |
105 | | Data2(nullptr, (((unsigned) k) >> 0) & 0x3), |
106 | | L(l, (((unsigned) k) >> 2) & 0x3), |
107 | 347k | Tag(tag, (((unsigned) k) >> 4) & 0x3) { |
108 | 347k | assert(getKind() == k); |
109 | 0 | assert(getLocationContext() == l); |
110 | 0 | assert(getData1() == P); |
111 | 347k | } |
112 | | |
113 | | ProgramPoint(const void *P1, |
114 | | const void *P2, |
115 | | Kind k, |
116 | | const LocationContext *l, |
117 | | const ProgramPointTag *tag = nullptr) |
118 | | : Data1(P1), |
119 | | Data2(P2, (((unsigned) k) >> 0) & 0x3), |
120 | | L(l, (((unsigned) k) >> 2) & 0x3), |
121 | 9.39M | Tag(tag, (((unsigned) k) >> 4) & 0x3) {} |
122 | | |
123 | | protected: |
124 | 16.0M | const void *getData1() const { return Data1; } |
125 | 6.82M | const void *getData2() const { return Data2.getPointer(); } |
126 | 86.1k | void setData2(const void *d) { Data2.setPointer(d); } |
127 | | |
128 | | public: |
129 | | /// Create a new ProgramPoint object that is the same as the original |
130 | | /// except for using the specified tag value. |
131 | 1.48M | ProgramPoint withTag(const ProgramPointTag *tag) const { |
132 | 1.48M | return ProgramPoint(getData1(), getData2(), getKind(), |
133 | 1.48M | getLocationContext(), tag); |
134 | 1.48M | } |
135 | | |
136 | | /// Convert to the specified ProgramPoint type, asserting that this |
137 | | /// ProgramPoint is of the desired type. |
138 | | template<typename T> |
139 | 1.44M | T castAs() const { |
140 | 1.44M | assert(T::isKind(*this)); |
141 | 0 | T t; |
142 | 1.44M | ProgramPoint& PP = t; |
143 | 1.44M | PP = *this; |
144 | 1.44M | return t; |
145 | 1.44M | } clang::CallExitEnd clang::ProgramPoint::castAs<clang::CallExitEnd>() const Line | Count | Source | 139 | 21 | T castAs() const { | 140 | 21 | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 21 | ProgramPoint& PP = t; | 143 | 21 | PP = *this; | 144 | 21 | return t; | 145 | 21 | } |
clang::BlockEdge clang::ProgramPoint::castAs<clang::BlockEdge>() const Line | Count | Source | 139 | 228k | T castAs() const { | 140 | 228k | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 228k | ProgramPoint& PP = t; | 143 | 228k | PP = *this; | 144 | 228k | return t; | 145 | 228k | } |
clang::BlockEntrance clang::ProgramPoint::castAs<clang::BlockEntrance>() const Line | Count | Source | 139 | 139k | T castAs() const { | 140 | 139k | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 139k | ProgramPoint& PP = t; | 143 | 139k | PP = *this; | 144 | 139k | return t; | 145 | 139k | } |
clang::CallEnter clang::ProgramPoint::castAs<clang::CallEnter>() const Line | Count | Source | 139 | 35.3k | T castAs() const { | 140 | 35.3k | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 35.3k | ProgramPoint& PP = t; | 143 | 35.3k | PP = *this; | 144 | 35.3k | return t; | 145 | 35.3k | } |
clang::PostStmt clang::ProgramPoint::castAs<clang::PostStmt>() const Line | Count | Source | 139 | 1.04M | T castAs() const { | 140 | 1.04M | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 1.04M | ProgramPoint& PP = t; | 143 | 1.04M | PP = *this; | 144 | 1.04M | return t; | 145 | 1.04M | } |
Unexecuted instantiation: clang::LoopExit clang::ProgramPoint::castAs<clang::LoopExit>() const clang::ImplicitCallPoint clang::ProgramPoint::castAs<clang::ImplicitCallPoint>() const Line | Count | Source | 139 | 1 | T castAs() const { | 140 | 1 | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 1 | ProgramPoint& PP = t; | 143 | 1 | PP = *this; | 144 | 1 | return t; | 145 | 1 | } |
clang::PostInitializer clang::ProgramPoint::castAs<clang::PostInitializer>() const Line | Count | Source | 139 | 2 | T castAs() const { | 140 | 2 | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 2 | ProgramPoint& PP = t; | 143 | 2 | PP = *this; | 144 | 2 | return t; | 145 | 2 | } |
clang::StmtPoint clang::ProgramPoint::castAs<clang::StmtPoint>() const Line | Count | Source | 139 | 969 | T castAs() const { | 140 | 969 | assert(T::isKind(*this)); | 141 | 0 | T t; | 142 | 969 | ProgramPoint& PP = t; | 143 | 969 | PP = *this; | 144 | 969 | return t; | 145 | 969 | } |
|
146 | | |
147 | | /// Convert to the specified ProgramPoint type, returning None if this |
148 | | /// ProgramPoint is not of the desired type. |
149 | | template<typename T> |
150 | 42.6M | Optional<T> getAs() const { |
151 | 42.6M | if (!T::isKind(*this)) |
152 | 29.5M | return None; |
153 | 13.0M | T t; |
154 | 13.0M | ProgramPoint& PP = t; |
155 | 13.0M | PP = *this; |
156 | 13.0M | return t; |
157 | 42.6M | } llvm::Optional<clang::BlockEdge> clang::ProgramPoint::getAs<clang::BlockEdge>() const Line | Count | Source | 150 | 3.91M | Optional<T> getAs() const { | 151 | 3.91M | if (!T::isKind(*this)) | 152 | 3.57M | return None; | 153 | 337k | T t; | 154 | 337k | ProgramPoint& PP = t; | 155 | 337k | PP = *this; | 156 | 337k | return t; | 157 | 3.91M | } |
llvm::Optional<clang::FunctionExitPoint> clang::ProgramPoint::getAs<clang::FunctionExitPoint>() const Line | Count | Source | 150 | 141k | Optional<T> getAs() const { | 151 | 141k | if (!T::isKind(*this)) | 152 | 125k | return None; | 153 | 15.6k | T t; | 154 | 15.6k | ProgramPoint& PP = t; | 155 | 15.6k | PP = *this; | 156 | 15.6k | return t; | 157 | 141k | } |
llvm::Optional<clang::PostStmtPurgeDeadSymbols> clang::ProgramPoint::getAs<clang::PostStmtPurgeDeadSymbols>() const Line | Count | Source | 150 | 58.1k | Optional<T> getAs() const { | 151 | 58.1k | if (!T::isKind(*this)) | 152 | 57.3k | return None; | 153 | 808 | T t; | 154 | 808 | ProgramPoint& PP = t; | 155 | 808 | PP = *this; | 156 | 808 | return t; | 157 | 58.1k | } |
llvm::Optional<clang::PostStore> clang::ProgramPoint::getAs<clang::PostStore>() const Line | Count | Source | 150 | 1.26M | Optional<T> getAs() const { | 151 | 1.26M | if (!T::isKind(*this)) | 152 | 1.20M | return None; | 153 | 53.0k | T t; | 154 | 53.0k | ProgramPoint& PP = t; | 155 | 53.0k | PP = *this; | 156 | 53.0k | return t; | 157 | 1.26M | } |
llvm::Optional<clang::PostStmt> clang::ProgramPoint::getAs<clang::PostStmt>() const Line | Count | Source | 150 | 6.16M | Optional<T> getAs() const { | 151 | 6.16M | if (!T::isKind(*this)) | 152 | 1.14M | return None; | 153 | 5.02M | T t; | 154 | 5.02M | ProgramPoint& PP = t; | 155 | 5.02M | PP = *this; | 156 | 5.02M | return t; | 157 | 6.16M | } |
llvm::Optional<clang::PostInitializer> clang::ProgramPoint::getAs<clang::PostInitializer>() const Line | Count | Source | 150 | 1.61M | Optional<T> getAs() const { | 151 | 1.61M | if (!T::isKind(*this)) | 152 | 1.56M | return None; | 153 | 47.7k | T t; | 154 | 47.7k | ProgramPoint& PP = t; | 155 | 47.7k | PP = *this; | 156 | 47.7k | return t; | 157 | 1.61M | } |
llvm::Optional<clang::PostImplicitCall> clang::ProgramPoint::getAs<clang::PostImplicitCall>() const Line | Count | Source | 150 | 1.26M | Optional<T> getAs() const { | 151 | 1.26M | if (!T::isKind(*this)) | 152 | 1.26M | return None; | 153 | 2.43k | T t; | 154 | 2.43k | ProgramPoint& PP = t; | 155 | 2.43k | PP = *this; | 156 | 2.43k | return t; | 157 | 1.26M | } |
llvm::Optional<clang::CallExitEnd> clang::ProgramPoint::getAs<clang::CallExitEnd>() const Line | Count | Source | 150 | 704k | Optional<T> getAs() const { | 151 | 704k | if (!T::isKind(*this)) | 152 | 594k | return None; | 153 | 109k | T t; | 154 | 109k | ProgramPoint& PP = t; | 155 | 109k | PP = *this; | 156 | 109k | return t; | 157 | 704k | } |
llvm::Optional<clang::LoopExit> clang::ProgramPoint::getAs<clang::LoopExit>() const Line | Count | Source | 150 | 1.22M | Optional<T> getAs() const { | 151 | 1.22M | if (!T::isKind(*this)) | 152 | 1.22M | return None; | 153 | 544 | T t; | 154 | 544 | ProgramPoint& PP = t; | 155 | 544 | PP = *this; | 156 | 544 | return t; | 157 | 1.22M | } |
llvm::Optional<clang::PostAllocatorCall> clang::ProgramPoint::getAs<clang::PostAllocatorCall>() const Line | Count | Source | 150 | 136 | Optional<T> getAs() const { | 151 | 136 | if (!T::isKind(*this)) | 152 | 136 | return None; | 153 | 0 | T t; | 154 | 0 | ProgramPoint& PP = t; | 155 | 0 | PP = *this; | 156 | 0 | return t; | 157 | 136 | } |
llvm::Optional<clang::CallEnter> clang::ProgramPoint::getAs<clang::CallEnter>() const Line | Count | Source | 150 | 8.77M | Optional<T> getAs() const { | 151 | 8.77M | if (!T::isKind(*this)) | 152 | 8.69M | return None; | 153 | 78.5k | T t; | 154 | 78.5k | ProgramPoint& PP = t; | 155 | 78.5k | PP = *this; | 156 | 78.5k | return t; | 157 | 8.77M | } |
llvm::Optional<clang::EpsilonPoint> clang::ProgramPoint::getAs<clang::EpsilonPoint>() const Line | Count | Source | 150 | 1.22M | Optional<T> getAs() const { | 151 | 1.22M | if (!T::isKind(*this)) | 152 | 1.22M | return None; | 153 | 36 | T t; | 154 | 36 | ProgramPoint& PP = t; | 155 | 36 | PP = *this; | 156 | 36 | return t; | 157 | 1.22M | } |
llvm::Optional<clang::PreStmtPurgeDeadSymbols> clang::ProgramPoint::getAs<clang::PreStmtPurgeDeadSymbols>() const Line | Count | Source | 150 | 1.56M | Optional<T> getAs() const { | 151 | 1.56M | if (!T::isKind(*this)) | 152 | 1.40M | return None; | 153 | 162k | T t; | 154 | 162k | ProgramPoint& PP = t; | 155 | 162k | PP = *this; | 156 | 162k | return t; | 157 | 1.56M | } |
llvm::Optional<clang::CallExitBegin> clang::ProgramPoint::getAs<clang::CallExitBegin>() const Line | Count | Source | 150 | 381k | Optional<T> getAs() const { | 151 | 381k | if (!T::isKind(*this)) | 152 | 322k | return None; | 153 | 59.0k | T t; | 154 | 59.0k | ProgramPoint& PP = t; | 155 | 59.0k | PP = *this; | 156 | 59.0k | return t; | 157 | 381k | } |
llvm::Optional<clang::BlockEntrance> clang::ProgramPoint::getAs<clang::BlockEntrance>() const Line | Count | Source | 150 | 3.14M | Optional<T> getAs() const { | 151 | 3.14M | if (!T::isKind(*this)) | 152 | 2.86M | return None; | 153 | 287k | T t; | 154 | 287k | ProgramPoint& PP = t; | 155 | 287k | PP = *this; | 156 | 287k | return t; | 157 | 3.14M | } |
llvm::Optional<clang::PreImplicitCall> clang::ProgramPoint::getAs<clang::PreImplicitCall>() const Line | Count | Source | 150 | 523k | Optional<T> getAs() const { | 151 | 523k | if (!T::isKind(*this)) | 152 | 523k | return None; | 153 | 24 | T t; | 154 | 24 | ProgramPoint& PP = t; | 155 | 24 | PP = *this; | 156 | 24 | return t; | 157 | 523k | } |
llvm::Optional<clang::StmtPoint> clang::ProgramPoint::getAs<clang::StmtPoint>() const Line | Count | Source | 150 | 7.41M | Optional<T> getAs() const { | 151 | 7.41M | if (!T::isKind(*this)) | 152 | 580k | return None; | 153 | 6.83M | T t; | 154 | 6.83M | ProgramPoint& PP = t; | 155 | 6.83M | PP = *this; | 156 | 6.83M | return t; | 157 | 7.41M | } |
llvm::Optional<clang::PreLoad> clang::ProgramPoint::getAs<clang::PreLoad>() const Line | Count | Source | 150 | 138 | Optional<T> getAs() const { | 151 | 138 | if (!T::isKind(*this)) | 152 | 136 | return None; | 153 | 2 | T t; | 154 | 2 | ProgramPoint& PP = t; | 155 | 2 | PP = *this; | 156 | 2 | return t; | 157 | 138 | } |
llvm::Optional<clang::PreStore> clang::ProgramPoint::getAs<clang::PreStore>() const Line | Count | Source | 150 | 136 | Optional<T> getAs() const { | 151 | 136 | if (!T::isKind(*this)) | 152 | 136 | return None; | 153 | 0 | T t; | 154 | 0 | ProgramPoint& PP = t; | 155 | 0 | PP = *this; | 156 | 0 | return t; | 157 | 136 | } |
llvm::Optional<clang::PostCondition> clang::ProgramPoint::getAs<clang::PostCondition>() const Line | Count | Source | 150 | 136 | Optional<T> getAs() const { | 151 | 136 | if (!T::isKind(*this)) | 152 | 136 | return None; | 153 | 0 | T t; | 154 | 0 | ProgramPoint& PP = t; | 155 | 0 | PP = *this; | 156 | 0 | return t; | 157 | 136 | } |
llvm::Optional<clang::PostLoad> clang::ProgramPoint::getAs<clang::PostLoad>() const Line | Count | Source | 150 | 136 | Optional<T> getAs() const { | 151 | 136 | if (!T::isKind(*this)) | 152 | 134 | return None; | 153 | 2 | T t; | 154 | 2 | ProgramPoint& PP = t; | 155 | 2 | PP = *this; | 156 | 2 | return t; | 157 | 136 | } |
llvm::Optional<clang::PostLValue> clang::ProgramPoint::getAs<clang::PostLValue>() const Line | Count | Source | 150 | 134 | Optional<T> getAs() const { | 151 | 134 | if (!T::isKind(*this)) | 152 | 130 | return None; | 153 | 4 | T t; | 154 | 4 | ProgramPoint& PP = t; | 155 | 4 | PP = *this; | 156 | 4 | return t; | 157 | 134 | } |
llvm::Optional<clang::PreStmt> clang::ProgramPoint::getAs<clang::PreStmt>() const Line | Count | Source | 150 | 3.22M | Optional<T> getAs() const { | 151 | 3.22M | if (!T::isKind(*this)) | 152 | 3.18M | return None; | 153 | 43.5k | T t; | 154 | 43.5k | ProgramPoint& PP = t; | 155 | 43.5k | PP = *this; | 156 | 43.5k | return t; | 157 | 3.22M | } |
|
158 | | |
159 | 52.8M | Kind getKind() const { |
160 | 52.8M | unsigned x = Tag.getInt(); |
161 | 52.8M | x <<= 2; |
162 | 52.8M | x |= L.getInt(); |
163 | 52.8M | x <<= 2; |
164 | 52.8M | x |= Data2.getInt(); |
165 | 52.8M | return (Kind) x; |
166 | 52.8M | } |
167 | | |
168 | | /// Is this a program point corresponding to purge/removal of dead |
169 | | /// symbols and bindings. |
170 | 119 | bool isPurgeKind() { |
171 | 119 | Kind K = getKind(); |
172 | 119 | return (K == PostStmtPurgeDeadSymbolsKind || |
173 | 119 | K == PreStmtPurgeDeadSymbolsKind); |
174 | 119 | } |
175 | | |
176 | 11.7M | const ProgramPointTag *getTag() const { return Tag.getPointer(); } |
177 | | |
178 | 39.5M | const LocationContext *getLocationContext() const { |
179 | 39.5M | return L.getPointer(); |
180 | 39.5M | } |
181 | | |
182 | 1.04M | const StackFrameContext *getStackFrame() const { |
183 | 1.04M | return getLocationContext()->getStackFrame(); |
184 | 1.04M | } |
185 | | |
186 | | // For use with DenseMap. This hash is probably slow. |
187 | 0 | unsigned getHashValue() const { |
188 | 0 | llvm::FoldingSetNodeID ID; |
189 | 0 | Profile(ID); |
190 | 0 | return ID.ComputeHash(); |
191 | 0 | } |
192 | | |
193 | 1.22M | bool operator==(const ProgramPoint & RHS) const { |
194 | 1.22M | return Data1 == RHS.Data1 && |
195 | 1.22M | Data2 == RHS.Data21.15M && |
196 | 1.22M | L == RHS.L479k && |
197 | 1.22M | Tag == RHS.Tag479k ; |
198 | 1.22M | } |
199 | | |
200 | 0 | bool operator!=(const ProgramPoint &RHS) const { |
201 | 0 | return Data1 != RHS.Data1 || |
202 | 0 | Data2 != RHS.Data2 || |
203 | 0 | L != RHS.L || |
204 | 0 | Tag != RHS.Tag; |
205 | 0 | } |
206 | | |
207 | 4.80M | void Profile(llvm::FoldingSetNodeID& ID) const { |
208 | 4.80M | ID.AddInteger((unsigned) getKind()); |
209 | 4.80M | ID.AddPointer(getData1()); |
210 | 4.80M | ID.AddPointer(getData2()); |
211 | 4.80M | ID.AddPointer(getLocationContext()); |
212 | 4.80M | ID.AddPointer(getTag()); |
213 | 4.80M | } |
214 | | |
215 | | void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const; |
216 | | |
217 | | LLVM_DUMP_METHOD void dump() const; |
218 | | |
219 | | static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, |
220 | | const LocationContext *LC, |
221 | | const ProgramPointTag *tag); |
222 | | }; |
223 | | |
224 | | class BlockEntrance : public ProgramPoint { |
225 | | public: |
226 | | BlockEntrance(const CFGBlock *B, const LocationContext *L, |
227 | | const ProgramPointTag *tag = nullptr) |
228 | 155k | : ProgramPoint(B, BlockEntranceKind, L, tag) { |
229 | 155k | assert(B && "BlockEntrance requires non-null block"); |
230 | 155k | } |
231 | | |
232 | 575k | const CFGBlock *getBlock() const { |
233 | 575k | return reinterpret_cast<const CFGBlock*>(getData1()); |
234 | 575k | } |
235 | | |
236 | 139k | Optional<CFGElement> getFirstElement() const { |
237 | 139k | const CFGBlock *B = getBlock(); |
238 | 139k | return B->empty() ? Optional<CFGElement>()13.2k : B->front()126k ; |
239 | 139k | } |
240 | | |
241 | | private: |
242 | | friend class ProgramPoint; |
243 | 426k | BlockEntrance() = default; |
244 | 3.28M | static bool isKind(const ProgramPoint &Location) { |
245 | 3.28M | return Location.getKind() == BlockEntranceKind; |
246 | 3.28M | } |
247 | | }; |
248 | | |
249 | | class BlockExit : public ProgramPoint { |
250 | | public: |
251 | | BlockExit(const CFGBlock *B, const LocationContext *L) |
252 | 0 | : ProgramPoint(B, BlockExitKind, L) {} |
253 | | |
254 | 0 | const CFGBlock *getBlock() const { |
255 | 0 | return reinterpret_cast<const CFGBlock*>(getData1()); |
256 | 0 | } |
257 | | |
258 | 0 | const Stmt *getTerminator() const { |
259 | 0 | return getBlock()->getTerminatorStmt(); |
260 | 0 | } |
261 | | |
262 | | private: |
263 | | friend class ProgramPoint; |
264 | | BlockExit() = default; |
265 | 0 | static bool isKind(const ProgramPoint &Location) { |
266 | 0 | return Location.getKind() == BlockExitKind; |
267 | 0 | } |
268 | | }; |
269 | | |
270 | | class StmtPoint : public ProgramPoint { |
271 | | public: |
272 | | StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, |
273 | | const ProgramPointTag *tag) |
274 | 7.61M | : ProgramPoint(S, p2, k, L, tag) { |
275 | 7.61M | assert(S); |
276 | 7.61M | } |
277 | | |
278 | 7.99M | const Stmt *getStmt() const { return (const Stmt*) getData1(); } |
279 | | |
280 | | template <typename T> |
281 | 64.1k | const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } clang::ObjCMessageExpr const* clang::StmtPoint::getStmtAs<clang::ObjCMessageExpr>() const Line | Count | Source | 281 | 8 | const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } |
clang::DeclStmt const* clang::StmtPoint::getStmtAs<clang::DeclStmt>() const Line | Count | Source | 281 | 37.3k | const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } |
clang::BinaryOperator const* clang::StmtPoint::getStmtAs<clang::BinaryOperator>() const Line | Count | Source | 281 | 26.7k | const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } |
|
282 | | |
283 | | protected: |
284 | 13.1M | StmtPoint() = default; |
285 | | private: |
286 | | friend class ProgramPoint; |
287 | 7.41M | static bool isKind(const ProgramPoint &Location) { |
288 | 7.41M | unsigned k = Location.getKind(); |
289 | 7.41M | return k >= PreStmtKind && k <= MaxPostStmtKind7.04M ; |
290 | 7.41M | } |
291 | | }; |
292 | | |
293 | | |
294 | | class PreStmt : public StmtPoint { |
295 | | public: |
296 | | PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, |
297 | | const Stmt *SubStmt = nullptr) |
298 | 1.09M | : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} |
299 | | |
300 | 0 | const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } |
301 | | |
302 | | private: |
303 | | friend class ProgramPoint; |
304 | 43.5k | PreStmt() = default; |
305 | 3.22M | static bool isKind(const ProgramPoint &Location) { |
306 | 3.22M | return Location.getKind() == PreStmtKind; |
307 | 3.22M | } |
308 | | }; |
309 | | |
310 | | class PostStmt : public StmtPoint { |
311 | | protected: |
312 | 6.11M | PostStmt() = default; |
313 | | PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, |
314 | | const ProgramPointTag *tag = nullptr) |
315 | 0 | : StmtPoint(S, data, k, L, tag) {} |
316 | | |
317 | | public: |
318 | | explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L, |
319 | | const ProgramPointTag *tag = nullptr) |
320 | 733k | : StmtPoint(S, nullptr, k, L, tag) {} |
321 | | |
322 | | explicit PostStmt(const Stmt *S, const LocationContext *L, |
323 | | const ProgramPointTag *tag = nullptr) |
324 | 3.19M | : StmtPoint(S, nullptr, PostStmtKind, L, tag) {} |
325 | | |
326 | | private: |
327 | | friend class ProgramPoint; |
328 | 7.21M | static bool isKind(const ProgramPoint &Location) { |
329 | 7.21M | unsigned k = Location.getKind(); |
330 | 7.21M | return k >= MinPostStmtKind && k <= MaxPostStmtKind6.30M ; |
331 | 7.21M | } |
332 | | }; |
333 | | |
334 | | class FunctionExitPoint : public ProgramPoint { |
335 | | public: |
336 | | explicit FunctionExitPoint(const ReturnStmt *S, |
337 | | const LocationContext *LC, |
338 | | const ProgramPointTag *tag = nullptr) |
339 | 107k | : ProgramPoint(S, FunctionExitKind, LC, tag) {} |
340 | | |
341 | 0 | const CFGBlock *getBlock() const { |
342 | 0 | return &getLocationContext()->getCFG()->getExit(); |
343 | 0 | } |
344 | | |
345 | 15.6k | const ReturnStmt *getStmt() const { |
346 | 15.6k | return reinterpret_cast<const ReturnStmt *>(getData1()); |
347 | 15.6k | } |
348 | | |
349 | | private: |
350 | | friend class ProgramPoint; |
351 | 15.6k | FunctionExitPoint() = default; |
352 | 141k | static bool isKind(const ProgramPoint &Location) { |
353 | 141k | return Location.getKind() == FunctionExitKind; |
354 | 141k | } |
355 | | }; |
356 | | |
357 | | // PostCondition represents the post program point of a branch condition. |
358 | | class PostCondition : public PostStmt { |
359 | | public: |
360 | | PostCondition(const Stmt *S, const LocationContext *L, |
361 | | const ProgramPointTag *tag = nullptr) |
362 | 50.0k | : PostStmt(S, PostConditionKind, L, tag) {} |
363 | | |
364 | | private: |
365 | | friend class ProgramPoint; |
366 | 0 | PostCondition() = default; |
367 | 136 | static bool isKind(const ProgramPoint &Location) { |
368 | 136 | return Location.getKind() == PostConditionKind; |
369 | 136 | } |
370 | | }; |
371 | | |
372 | | class LocationCheck : public StmtPoint { |
373 | | protected: |
374 | 2 | LocationCheck() = default; |
375 | | LocationCheck(const Stmt *S, const LocationContext *L, |
376 | | ProgramPoint::Kind K, const ProgramPointTag *tag) |
377 | 652k | : StmtPoint(S, nullptr, K, L, tag) {} |
378 | | |
379 | | private: |
380 | | friend class ProgramPoint; |
381 | 0 | static bool isKind(const ProgramPoint &location) { |
382 | 0 | unsigned k = location.getKind(); |
383 | 0 | return k == PreLoadKind || k == PreStoreKind; |
384 | 0 | } |
385 | | }; |
386 | | |
387 | | class PreLoad : public LocationCheck { |
388 | | public: |
389 | | PreLoad(const Stmt *S, const LocationContext *L, |
390 | | const ProgramPointTag *tag = nullptr) |
391 | 573k | : LocationCheck(S, L, PreLoadKind, tag) {} |
392 | | |
393 | | private: |
394 | | friend class ProgramPoint; |
395 | 2 | PreLoad() = default; |
396 | 138 | static bool isKind(const ProgramPoint &location) { |
397 | 138 | return location.getKind() == PreLoadKind; |
398 | 138 | } |
399 | | }; |
400 | | |
401 | | class PreStore : public LocationCheck { |
402 | | public: |
403 | | PreStore(const Stmt *S, const LocationContext *L, |
404 | | const ProgramPointTag *tag = nullptr) |
405 | 78.5k | : LocationCheck(S, L, PreStoreKind, tag) {} |
406 | | |
407 | | private: |
408 | | friend class ProgramPoint; |
409 | 0 | PreStore() = default; |
410 | 136 | static bool isKind(const ProgramPoint &location) { |
411 | 136 | return location.getKind() == PreStoreKind; |
412 | 136 | } |
413 | | }; |
414 | | |
415 | | class PostLoad : public PostStmt { |
416 | | public: |
417 | | PostLoad(const Stmt *S, const LocationContext *L, |
418 | | const ProgramPointTag *tag = nullptr) |
419 | 227k | : PostStmt(S, PostLoadKind, L, tag) {} |
420 | | |
421 | | private: |
422 | | friend class ProgramPoint; |
423 | 2 | PostLoad() = default; |
424 | 136 | static bool isKind(const ProgramPoint &Location) { |
425 | 136 | return Location.getKind() == PostLoadKind; |
426 | 136 | } |
427 | | }; |
428 | | |
429 | | /// Represents a program point after a store evaluation. |
430 | | class PostStore : public PostStmt { |
431 | | public: |
432 | | /// Construct the post store point. |
433 | | /// \param Loc can be used to store the information about the location |
434 | | /// used in the form it was uttered in the code. |
435 | | PostStore(const Stmt *S, const LocationContext *L, const void *Loc, |
436 | | const ProgramPointTag *tag = nullptr) |
437 | 86.1k | : PostStmt(S, PostStoreKind, L, tag) { |
438 | 86.1k | assert(getData2() == nullptr); |
439 | 0 | setData2(Loc); |
440 | 86.1k | } |
441 | | |
442 | | /// Returns the information about the location used in the store, |
443 | | /// how it was uttered in the code. |
444 | 1.46k | const void *getLocationValue() const { |
445 | 1.46k | return getData2(); |
446 | 1.46k | } |
447 | | |
448 | | private: |
449 | | friend class ProgramPoint; |
450 | 53.0k | PostStore() = default; |
451 | 1.26M | static bool isKind(const ProgramPoint &Location) { |
452 | 1.26M | return Location.getKind() == PostStoreKind; |
453 | 1.26M | } |
454 | | }; |
455 | | |
456 | | class PostLValue : public PostStmt { |
457 | | public: |
458 | | PostLValue(const Stmt *S, const LocationContext *L, |
459 | | const ProgramPointTag *tag = nullptr) |
460 | 369k | : PostStmt(S, PostLValueKind, L, tag) {} |
461 | | |
462 | | private: |
463 | | friend class ProgramPoint; |
464 | 4 | PostLValue() = default; |
465 | 134 | static bool isKind(const ProgramPoint &Location) { |
466 | 134 | return Location.getKind() == PostLValueKind; |
467 | 134 | } |
468 | | }; |
469 | | |
470 | | /// Represents a point after we ran remove dead bindings BEFORE |
471 | | /// processing the given statement. |
472 | | class PreStmtPurgeDeadSymbols : public StmtPoint { |
473 | | public: |
474 | | PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, |
475 | | const ProgramPointTag *tag = nullptr) |
476 | 1.63M | : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } |
477 | | |
478 | | private: |
479 | | friend class ProgramPoint; |
480 | 162k | PreStmtPurgeDeadSymbols() = default; |
481 | 1.56M | static bool isKind(const ProgramPoint &Location) { |
482 | 1.56M | return Location.getKind() == PreStmtPurgeDeadSymbolsKind; |
483 | 1.56M | } |
484 | | }; |
485 | | |
486 | | /// Represents a point after we ran remove dead bindings AFTER |
487 | | /// processing the given statement. |
488 | | class PostStmtPurgeDeadSymbols : public StmtPoint { |
489 | | public: |
490 | | PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, |
491 | | const ProgramPointTag *tag = nullptr) |
492 | 304k | : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } |
493 | | |
494 | | private: |
495 | | friend class ProgramPoint; |
496 | 808 | PostStmtPurgeDeadSymbols() = default; |
497 | 58.1k | static bool isKind(const ProgramPoint &Location) { |
498 | 58.1k | return Location.getKind() == PostStmtPurgeDeadSymbolsKind; |
499 | 58.1k | } |
500 | | }; |
501 | | |
502 | | class BlockEdge : public ProgramPoint { |
503 | | public: |
504 | | BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) |
505 | 222k | : ProgramPoint(B1, B2, BlockEdgeKind, L) { |
506 | 222k | assert(B1 && "BlockEdge: source block must be non-null"); |
507 | 0 | assert(B2 && "BlockEdge: destination block must be non-null"); |
508 | 222k | } |
509 | | |
510 | 697k | const CFGBlock *getSrc() const { |
511 | 697k | return static_cast<const CFGBlock*>(getData1()); |
512 | 697k | } |
513 | | |
514 | 264k | const CFGBlock *getDst() const { |
515 | 264k | return static_cast<const CFGBlock*>(getData2()); |
516 | 264k | } |
517 | | |
518 | | private: |
519 | | friend class ProgramPoint; |
520 | 565k | BlockEdge() = default; |
521 | 4.14M | static bool isKind(const ProgramPoint &Location) { |
522 | 4.14M | return Location.getKind() == BlockEdgeKind; |
523 | 4.14M | } |
524 | | }; |
525 | | |
526 | | class PostInitializer : public ProgramPoint { |
527 | | public: |
528 | | /// Construct a PostInitializer point that represents a location after |
529 | | /// CXXCtorInitializer expression evaluation. |
530 | | /// |
531 | | /// \param I The initializer. |
532 | | /// \param Loc The location of the field being initialized. |
533 | | PostInitializer(const CXXCtorInitializer *I, |
534 | | const void *Loc, |
535 | | const LocationContext *L) |
536 | 20.3k | : ProgramPoint(I, Loc, PostInitializerKind, L) {} |
537 | | |
538 | 23.6k | const CXXCtorInitializer *getInitializer() const { |
539 | 23.6k | return static_cast<const CXXCtorInitializer *>(getData1()); |
540 | 23.6k | } |
541 | | |
542 | | /// Returns the location of the field. |
543 | 137 | const void *getLocationValue() const { |
544 | 137 | return getData2(); |
545 | 137 | } |
546 | | |
547 | | private: |
548 | | friend class ProgramPoint; |
549 | 47.7k | PostInitializer() = default; |
550 | 1.61M | static bool isKind(const ProgramPoint &Location) { |
551 | 1.61M | return Location.getKind() == PostInitializerKind; |
552 | 1.61M | } |
553 | | }; |
554 | | |
555 | | /// Represents an implicit call event. |
556 | | /// |
557 | | /// The nearest statement is provided for diagnostic purposes. |
558 | | class ImplicitCallPoint : public ProgramPoint { |
559 | | public: |
560 | | ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, |
561 | | const LocationContext *L, const ProgramPointTag *Tag) |
562 | 14.1k | : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} |
563 | | |
564 | 1 | const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } |
565 | 37 | SourceLocation getLocation() const { |
566 | 37 | return SourceLocation::getFromPtrEncoding(getData1()); |
567 | 37 | } |
568 | | |
569 | | protected: |
570 | 2.46k | ImplicitCallPoint() = default; |
571 | | private: |
572 | | friend class ProgramPoint; |
573 | 1 | static bool isKind(const ProgramPoint &Location) { |
574 | 1 | return Location.getKind() >= MinImplicitCallKind && |
575 | 1 | Location.getKind() <= MaxImplicitCallKind; |
576 | 1 | } |
577 | | }; |
578 | | |
579 | | /// Represents a program point just before an implicit call event. |
580 | | /// |
581 | | /// Explicit calls will appear as PreStmt program points. |
582 | | class PreImplicitCall : public ImplicitCallPoint { |
583 | | public: |
584 | | PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, |
585 | | const ProgramPointTag *Tag = nullptr) |
586 | 8.28k | : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} |
587 | | |
588 | | private: |
589 | | friend class ProgramPoint; |
590 | 24 | PreImplicitCall() = default; |
591 | 523k | static bool isKind(const ProgramPoint &Location) { |
592 | 523k | return Location.getKind() == PreImplicitCallKind; |
593 | 523k | } |
594 | | }; |
595 | | |
596 | | /// Represents a program point just after an implicit call event. |
597 | | /// |
598 | | /// Explicit calls will appear as PostStmt program points. |
599 | | class PostImplicitCall : public ImplicitCallPoint { |
600 | | public: |
601 | | PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, |
602 | | const ProgramPointTag *Tag = nullptr) |
603 | 5.90k | : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} |
604 | | |
605 | | private: |
606 | | friend class ProgramPoint; |
607 | 2.43k | PostImplicitCall() = default; |
608 | 1.26M | static bool isKind(const ProgramPoint &Location) { |
609 | 1.26M | return Location.getKind() == PostImplicitCallKind; |
610 | 1.26M | } |
611 | | }; |
612 | | |
613 | | class PostAllocatorCall : public StmtPoint { |
614 | | public: |
615 | | PostAllocatorCall(const Stmt *S, const LocationContext *L, |
616 | | const ProgramPointTag *Tag = nullptr) |
617 | 624 | : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {} |
618 | | |
619 | | private: |
620 | | friend class ProgramPoint; |
621 | 0 | PostAllocatorCall() = default; |
622 | 136 | static bool isKind(const ProgramPoint &Location) { |
623 | 136 | return Location.getKind() == PostAllocatorCallKind; |
624 | 136 | } |
625 | | }; |
626 | | |
627 | | /// Represents a point when we begin processing an inlined call. |
628 | | /// CallEnter uses the caller's location context. |
629 | | class CallEnter : public ProgramPoint { |
630 | | public: |
631 | | CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, |
632 | | const LocationContext *callerCtx) |
633 | 35.3k | : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {} |
634 | | |
635 | 2.84k | const Stmt *getCallExpr() const { |
636 | 2.84k | return static_cast<const Stmt *>(getData1()); |
637 | 2.84k | } |
638 | | |
639 | 180k | const StackFrameContext *getCalleeContext() const { |
640 | 180k | return static_cast<const StackFrameContext *>(getData2()); |
641 | 180k | } |
642 | | |
643 | | /// Returns the entry block in the CFG for the entered function. |
644 | 70.6k | const CFGBlock *getEntry() const { |
645 | 70.6k | const StackFrameContext *CalleeCtx = getCalleeContext(); |
646 | 70.6k | const CFG *CalleeCFG = CalleeCtx->getCFG(); |
647 | 70.6k | return &(CalleeCFG->getEntry()); |
648 | 70.6k | } |
649 | | |
650 | | private: |
651 | | friend class ProgramPoint; |
652 | 113k | CallEnter() = default; |
653 | 8.80M | static bool isKind(const ProgramPoint &Location) { |
654 | 8.80M | return Location.getKind() == CallEnterKind; |
655 | 8.80M | } |
656 | | }; |
657 | | |
658 | | /// Represents a point when we start the call exit sequence (for inlined call). |
659 | | /// |
660 | | /// The call exit is simulated with a sequence of nodes, which occur between |
661 | | /// CallExitBegin and CallExitEnd. The following operations occur between the |
662 | | /// two program points: |
663 | | /// - CallExitBegin |
664 | | /// - Bind the return value |
665 | | /// - Run Remove dead bindings (to clean up the dead symbols from the callee). |
666 | | /// - CallExitEnd |
667 | | class CallExitBegin : public ProgramPoint { |
668 | | public: |
669 | | // CallExitBegin uses the callee's location context. |
670 | | CallExitBegin(const StackFrameContext *L, const ReturnStmt *RS) |
671 | 43.0k | : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { } |
672 | | |
673 | 54.9k | const ReturnStmt *getReturnStmt() const { |
674 | 54.9k | return static_cast<const ReturnStmt *>(getData1()); |
675 | 54.9k | } |
676 | | |
677 | | private: |
678 | | friend class ProgramPoint; |
679 | 59.0k | CallExitBegin() = default; |
680 | 381k | static bool isKind(const ProgramPoint &Location) { |
681 | 381k | return Location.getKind() == CallExitBeginKind; |
682 | 381k | } |
683 | | }; |
684 | | |
685 | | /// Represents a point when we finish the call exit sequence (for inlined call). |
686 | | /// \sa CallExitBegin |
687 | | class CallExitEnd : public ProgramPoint { |
688 | | public: |
689 | | // CallExitEnd uses the caller's location context. |
690 | | CallExitEnd(const StackFrameContext *CalleeCtx, |
691 | | const LocationContext *CallerCtx) |
692 | 41.2k | : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {} |
693 | | |
694 | 78.2k | const StackFrameContext *getCalleeContext() const { |
695 | 78.2k | return static_cast<const StackFrameContext *>(getData1()); |
696 | 78.2k | } |
697 | | |
698 | | private: |
699 | | friend class ProgramPoint; |
700 | 109k | CallExitEnd() = default; |
701 | 704k | static bool isKind(const ProgramPoint &Location) { |
702 | 704k | return Location.getKind() == CallExitEndKind; |
703 | 704k | } |
704 | | }; |
705 | | |
706 | | /// Represents a point when we exit a loop. |
707 | | /// When this ProgramPoint is encountered we can be sure that the symbolic |
708 | | /// execution of the corresponding LoopStmt is finished on the given path. |
709 | | /// Note: It is possible to encounter a LoopExit element when we haven't even |
710 | | /// encountered the loop itself. At the current state not all loop exits will |
711 | | /// result in a LoopExit program point. |
712 | | class LoopExit : public ProgramPoint { |
713 | | public: |
714 | | LoopExit(const Stmt *LoopStmt, const LocationContext *LC) |
715 | 148 | : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {} |
716 | | |
717 | 0 | const Stmt *getLoopStmt() const { |
718 | 0 | return static_cast<const Stmt *>(getData1()); |
719 | 0 | } |
720 | | |
721 | | private: |
722 | | friend class ProgramPoint; |
723 | 544 | LoopExit() = default; |
724 | 1.22M | static bool isKind(const ProgramPoint &Location) { |
725 | 1.22M | return Location.getKind() == LoopExitKind; |
726 | 1.22M | } |
727 | | }; |
728 | | |
729 | | /// This is a meta program point, which should be skipped by all the diagnostic |
730 | | /// reasoning etc. |
731 | | class EpsilonPoint : public ProgramPoint { |
732 | | public: |
733 | | EpsilonPoint(const LocationContext *L, const void *Data1, |
734 | | const void *Data2 = nullptr, |
735 | | const ProgramPointTag *tag = nullptr) |
736 | 40 | : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} |
737 | | |
738 | 0 | const void *getData() const { return getData1(); } |
739 | | |
740 | | private: |
741 | | friend class ProgramPoint; |
742 | 36 | EpsilonPoint() = default; |
743 | 1.22M | static bool isKind(const ProgramPoint &Location) { |
744 | 1.22M | return Location.getKind() == EpsilonKind; |
745 | 1.22M | } |
746 | | }; |
747 | | |
748 | | } // end namespace clang |
749 | | |
750 | | |
751 | | namespace llvm { // Traits specialization for DenseMap |
752 | | |
753 | | template <> struct DenseMapInfo<clang::ProgramPoint> { |
754 | | |
755 | 0 | static inline clang::ProgramPoint getEmptyKey() { |
756 | 0 | uintptr_t x = |
757 | 0 | reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; |
758 | 0 | return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); |
759 | 0 | } |
760 | | |
761 | 0 | static inline clang::ProgramPoint getTombstoneKey() { |
762 | 0 | uintptr_t x = |
763 | 0 | reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; |
764 | 0 | return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); |
765 | 0 | } |
766 | | |
767 | 0 | static unsigned getHashValue(const clang::ProgramPoint &Loc) { |
768 | 0 | return Loc.getHashValue(); |
769 | 0 | } |
770 | | |
771 | | static bool isEqual(const clang::ProgramPoint &L, |
772 | 0 | const clang::ProgramPoint &R) { |
773 | 0 | return L == R; |
774 | 0 | } |
775 | | |
776 | | }; |
777 | | |
778 | | } // end namespace llvm |
779 | | |
780 | | #endif |