/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicType.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- DynamicType.cpp - Dynamic type related APIs --------------*- 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 APIs that track and query dynamic type information. This |
10 | | // information can be used to devirtualize calls during the symbolic execution |
11 | | // or do type checking. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" |
16 | | #include "clang/Basic/JsonSupport.h" |
17 | | #include "clang/Basic/LLVM.h" |
18 | | #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" |
19 | | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
20 | | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
21 | | #include "llvm/Support/Casting.h" |
22 | | #include "llvm/Support/raw_ostream.h" |
23 | | #include <cassert> |
24 | | |
25 | | /// The GDM component containing the dynamic type info. This is a map from a |
26 | | /// symbol to its most likely type. |
27 | | REGISTER_MAP_WITH_PROGRAMSTATE(DynamicTypeMap, const clang::ento::MemRegion *, |
28 | | clang::ento::DynamicTypeInfo) |
29 | | |
30 | | /// A set factory of dynamic cast informations. |
31 | | REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicCastInfo) |
32 | | |
33 | | /// A map from symbols to cast informations. |
34 | | REGISTER_MAP_WITH_PROGRAMSTATE(DynamicCastMap, const clang::ento::MemRegion *, |
35 | | CastSet) |
36 | | |
37 | | // A map from Class object symbols to the most likely pointed-to type. |
38 | | REGISTER_MAP_WITH_PROGRAMSTATE(DynamicClassObjectMap, clang::ento::SymbolRef, |
39 | | clang::ento::DynamicTypeInfo) |
40 | | |
41 | | namespace clang { |
42 | | namespace ento { |
43 | | |
44 | 7.97k | DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) { |
45 | 7.97k | MR = MR->StripCasts(); |
46 | | |
47 | | // Look up the dynamic type in the GDM. |
48 | 7.97k | if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR)) |
49 | 2.77k | return *DTI; |
50 | | |
51 | | // Otherwise, fall back to what we know about the region. |
52 | 5.20k | if (const auto *TR = dyn_cast<TypedRegion>(MR)) |
53 | 368 | return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false); |
54 | | |
55 | 4.83k | if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) { |
56 | 4.83k | SymbolRef Sym = SR->getSymbol(); |
57 | 4.83k | return DynamicTypeInfo(Sym->getType()); |
58 | 4.83k | } |
59 | | |
60 | 1 | return {}; |
61 | 4.83k | } |
62 | | |
63 | | const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State, |
64 | 37 | const MemRegion *MR) { |
65 | 37 | return State->get<DynamicTypeMap>(MR); |
66 | 37 | } |
67 | | |
68 | 1.68k | static void unbox(QualType &Ty) { |
69 | | // FIXME: Why are we being fed references to pointers in the first place? |
70 | 3.65k | while (Ty->isReferenceType() || Ty->isPointerType()3.02k ) |
71 | 1.97k | Ty = Ty->getPointeeType(); |
72 | 1.68k | Ty = Ty.getCanonicalType().getUnqualifiedType(); |
73 | 1.68k | } |
74 | | |
75 | | const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State, |
76 | | const MemRegion *MR, |
77 | | QualType CastFromTy, |
78 | 676 | QualType CastToTy) { |
79 | 676 | const auto *Lookup = State->get<DynamicCastMap>().lookup(MR); |
80 | 676 | if (!Lookup) |
81 | 204 | return nullptr; |
82 | | |
83 | 472 | unbox(CastFromTy); |
84 | 472 | unbox(CastToTy); |
85 | | |
86 | 472 | for (const DynamicCastInfo &Cast : *Lookup) |
87 | 976 | if (Cast.equals(CastFromTy, CastToTy)) |
88 | 288 | return &Cast; |
89 | | |
90 | 184 | return nullptr; |
91 | 472 | } |
92 | | |
93 | | DynamicTypeInfo getClassObjectDynamicTypeInfo(ProgramStateRef State, |
94 | 49 | SymbolRef Sym) { |
95 | 49 | const DynamicTypeInfo *DTI = State->get<DynamicClassObjectMap>(Sym); |
96 | 49 | return DTI ? *DTI34 : DynamicTypeInfo{}15 ; |
97 | 49 | } |
98 | | |
99 | | ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, |
100 | 4.07k | DynamicTypeInfo NewTy) { |
101 | 4.07k | State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy); |
102 | 4.07k | assert(State); |
103 | 4.07k | return State; |
104 | 4.07k | } |
105 | | |
106 | | ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, |
107 | 3.33k | QualType NewTy, bool CanBeSubClassed) { |
108 | 3.33k | return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed)); |
109 | 3.33k | } |
110 | | |
111 | | ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State, |
112 | | const MemRegion *MR, |
113 | | QualType CastFromTy, |
114 | | QualType CastToTy, |
115 | 388 | bool CastSucceeds) { |
116 | 388 | if (!MR) |
117 | 18 | return State; |
118 | | |
119 | 370 | if (CastSucceeds) { |
120 | 196 | assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) && |
121 | 196 | "DynamicTypeInfo should always be a pointer."); |
122 | 196 | State = State->set<DynamicTypeMap>(MR, CastToTy); |
123 | 196 | } |
124 | | |
125 | 370 | unbox(CastFromTy); |
126 | 370 | unbox(CastToTy); |
127 | | |
128 | 370 | DynamicCastInfo::CastResult ResultKind = |
129 | 370 | CastSucceeds ? DynamicCastInfo::CastResult::Success196 |
130 | 370 | : DynamicCastInfo::CastResult::Failure174 ; |
131 | | |
132 | 370 | CastSet::Factory &F = State->get_context<CastSet>(); |
133 | | |
134 | 370 | const CastSet *TempSet = State->get<DynamicCastMap>(MR); |
135 | 370 | CastSet Set = TempSet ? *TempSet184 : F.getEmptySet()186 ; |
136 | | |
137 | 370 | Set = F.add(Set, {CastFromTy, CastToTy, ResultKind}); |
138 | 370 | State = State->set<DynamicCastMap>(MR, Set); |
139 | | |
140 | 370 | assert(State); |
141 | 370 | return State; |
142 | 370 | } |
143 | | |
144 | | ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State, |
145 | | SymbolRef Sym, |
146 | 30 | DynamicTypeInfo NewTy) { |
147 | 30 | State = State->set<DynamicClassObjectMap>(Sym, NewTy); |
148 | 30 | return State; |
149 | 30 | } |
150 | | |
151 | | ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State, |
152 | | SymbolRef Sym, QualType NewTy, |
153 | 30 | bool CanBeSubClassed) { |
154 | 30 | return setClassObjectDynamicTypeInfo(State, Sym, |
155 | 30 | DynamicTypeInfo(NewTy, CanBeSubClassed)); |
156 | 30 | } |
157 | | |
158 | 25.8k | static bool isLive(SymbolReaper &SR, const MemRegion *MR) { |
159 | 25.8k | return SR.isLiveRegion(MR); |
160 | 25.8k | } |
161 | | |
162 | 146 | static bool isLive(SymbolReaper &SR, SymbolRef Sym) { return SR.isLive(Sym); } |
163 | | |
164 | | template <typename MapTy> |
165 | 812k | static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) { |
166 | 812k | const auto &Map = State->get<MapTy>(); |
167 | | |
168 | 812k | for (const auto &Elem : Map) |
169 | 25.9k | if (!isLive(SR, Elem.first)) |
170 | 3.09k | State = State->remove<MapTy>(Elem.first); |
171 | | |
172 | 812k | return State; |
173 | 812k | } DynamicType.cpp:llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> clang::ento::removeDeadImpl<(anonymous namespace)::DynamicTypeMap>(llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, clang::ento::SymbolReaper&) Line | Count | Source | 165 | 404k | static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) { | 166 | 404k | const auto &Map = State->get<MapTy>(); | 167 | | | 168 | 404k | for (const auto &Elem : Map) | 169 | 24.7k | if (!isLive(SR, Elem.first)) | 170 | 2.76k | State = State->remove<MapTy>(Elem.first); | 171 | | | 172 | 404k | return State; | 173 | 404k | } |
DynamicType.cpp:llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> clang::ento::removeDeadImpl<(anonymous namespace)::DynamicCastMap>(llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, clang::ento::SymbolReaper&) Line | Count | Source | 165 | 4.26k | static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) { | 166 | 4.26k | const auto &Map = State->get<MapTy>(); | 167 | | | 168 | 4.26k | for (const auto &Elem : Map) | 169 | 1.05k | if (!isLive(SR, Elem.first)) | 170 | 297 | State = State->remove<MapTy>(Elem.first); | 171 | | | 172 | 4.26k | return State; | 173 | 4.26k | } |
DynamicType.cpp:llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const> clang::ento::removeDeadImpl<(anonymous namespace)::DynamicClassObjectMap>(llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, clang::ento::SymbolReaper&) Line | Count | Source | 165 | 404k | static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) { | 166 | 404k | const auto &Map = State->get<MapTy>(); | 167 | | | 168 | 404k | for (const auto &Elem : Map) | 169 | 146 | if (!isLive(SR, Elem.first)) | 170 | 34 | State = State->remove<MapTy>(Elem.first); | 171 | | | 172 | 404k | return State; | 173 | 404k | } |
|
174 | | |
175 | 404k | ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) { |
176 | 404k | return removeDeadImpl<DynamicTypeMap>(State, SR); |
177 | 404k | } |
178 | | |
179 | 4.26k | ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) { |
180 | 4.26k | return removeDeadImpl<DynamicCastMap>(State, SR); |
181 | 4.26k | } |
182 | | |
183 | | ProgramStateRef removeDeadClassObjectTypes(ProgramStateRef State, |
184 | 404k | SymbolReaper &SR) { |
185 | 404k | return removeDeadImpl<DynamicClassObjectMap>(State, SR); |
186 | 404k | } |
187 | | |
188 | | //===----------------------------------------------------------------------===// |
189 | | // Implementation of the 'printer-to-JSON' function |
190 | | //===----------------------------------------------------------------------===// |
191 | | |
192 | | static raw_ostream &printJson(const MemRegion *Region, raw_ostream &Out, |
193 | 30 | const char *NL, unsigned int Space, bool IsDot) { |
194 | 30 | return Out << "\"region\": \"" << Region << "\""; |
195 | 30 | } |
196 | | |
197 | | static raw_ostream &printJson(const SymExpr *Symbol, raw_ostream &Out, |
198 | 2 | const char *NL, unsigned int Space, bool IsDot) { |
199 | 2 | return Out << "\"symbol\": \"" << Symbol << "\""; |
200 | 2 | } |
201 | | |
202 | | static raw_ostream &printJson(const DynamicTypeInfo &DTI, raw_ostream &Out, |
203 | 19 | const char *NL, unsigned int Space, bool IsDot) { |
204 | 19 | Out << "\"dyn_type\": "; |
205 | 19 | if (!DTI.isValid()) { |
206 | 0 | Out << "null"; |
207 | 19 | } else { |
208 | 19 | QualType ToPrint = DTI.getType(); |
209 | 19 | if (ToPrint->isAnyPointerType()) |
210 | 5 | ToPrint = ToPrint->getPointeeType(); |
211 | | |
212 | 19 | Out << '\"' << ToPrint << "\", \"sub_classable\": " |
213 | 19 | << (DTI.canBeASubClass() ? "true"15 : "false"4 ); |
214 | 19 | } |
215 | 19 | return Out; |
216 | 19 | } |
217 | | |
218 | | static raw_ostream &printJson(const DynamicCastInfo &DCI, raw_ostream &Out, |
219 | 14 | const char *NL, unsigned int Space, bool IsDot) { |
220 | 14 | return Out << "\"from\": \"" << DCI.from() << "\", \"to\": \"" << DCI.to() |
221 | 14 | << "\", \"kind\": \"" << (DCI.succeeds() ? "success"13 : "fail"1 ) |
222 | 14 | << "\""; |
223 | 14 | } |
224 | | |
225 | | template <class T, class U> |
226 | | static raw_ostream &printJson(const std::pair<T, U> &Pair, raw_ostream &Out, |
227 | 32 | const char *NL, unsigned int Space, bool IsDot) { |
228 | 32 | printJson(Pair.first, Out, NL, Space, IsDot) << ", "; |
229 | 32 | return printJson(Pair.second, Out, NL, Space, IsDot); |
230 | 32 | } DynamicType.cpp:llvm::raw_ostream& clang::ento::printJson<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo>(std::__1::pair<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo> const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 227 | 17 | const char *NL, unsigned int Space, bool IsDot) { | 228 | 17 | printJson(Pair.first, Out, NL, Space, IsDot) << ", "; | 229 | 17 | return printJson(Pair.second, Out, NL, Space, IsDot); | 230 | 17 | } |
DynamicType.cpp:llvm::raw_ostream& clang::ento::printJson<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > >(std::__1::pair<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > > const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 227 | 13 | const char *NL, unsigned int Space, bool IsDot) { | 228 | 13 | printJson(Pair.first, Out, NL, Space, IsDot) << ", "; | 229 | 13 | return printJson(Pair.second, Out, NL, Space, IsDot); | 230 | 13 | } |
DynamicType.cpp:llvm::raw_ostream& clang::ento::printJson<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo>(std::__1::pair<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo> const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 227 | 2 | const char *NL, unsigned int Space, bool IsDot) { | 228 | 2 | printJson(Pair.first, Out, NL, Space, IsDot) << ", "; | 229 | 2 | return printJson(Pair.second, Out, NL, Space, IsDot); | 230 | 2 | } |
|
231 | | |
232 | | template <class ContainerTy> |
233 | | static raw_ostream &printJsonContainer(const ContainerTy &Container, |
234 | | raw_ostream &Out, const char *NL, |
235 | 330 | unsigned int Space, bool IsDot) { |
236 | 330 | if (Container.isEmpty()) { |
237 | 286 | return Out << "null"; |
238 | 286 | } |
239 | | |
240 | 44 | ++Space; |
241 | 44 | Out << '[' << NL; |
242 | 90 | for (auto I = Container.begin(); I != Container.end(); ++I46 ) { |
243 | 46 | const auto &Element = *I; |
244 | | |
245 | 46 | Indent(Out, Space, IsDot) << "{ "; |
246 | 46 | printJson(Element, Out, NL, Space, IsDot) << " }"; |
247 | | |
248 | 46 | if (std::next(I) != Container.end()) |
249 | 2 | Out << ','; |
250 | 46 | Out << NL; |
251 | 46 | } |
252 | | |
253 | 44 | --Space; |
254 | 44 | return Indent(Out, Space, IsDot) << "]"; |
255 | 330 | } DynamicType.cpp:llvm::raw_ostream& clang::ento::printJsonContainer<llvm::ImmutableMap<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo> > >(llvm::ImmutableMap<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, clang::ento::DynamicTypeInfo> > const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 235 | 158 | unsigned int Space, bool IsDot) { | 236 | 158 | if (Container.isEmpty()) { | 237 | 141 | return Out << "null"; | 238 | 141 | } | 239 | | | 240 | 17 | ++Space; | 241 | 17 | Out << '[' << NL; | 242 | 34 | for (auto I = Container.begin(); I != Container.end(); ++I17 ) { | 243 | 17 | const auto &Element = *I; | 244 | | | 245 | 17 | Indent(Out, Space, IsDot) << "{ "; | 246 | 17 | printJson(Element, Out, NL, Space, IsDot) << " }"; | 247 | | | 248 | 17 | if (std::next(I) != Container.end()) | 249 | 0 | Out << ','; | 250 | 17 | Out << NL; | 251 | 17 | } | 252 | | | 253 | 17 | --Space; | 254 | 17 | return Indent(Out, Space, IsDot) << "]"; | 255 | 158 | } |
DynamicType.cpp:llvm::raw_ostream& clang::ento::printJsonContainer<llvm::ImmutableMap<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> >, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > > > >(llvm::ImmutableMap<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> >, llvm::ImutKeyValueInfo<clang::ento::MemRegion const*, llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > > > const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 235 | 158 | unsigned int Space, bool IsDot) { | 236 | 158 | if (Container.isEmpty()) { | 237 | 145 | return Out << "null"; | 238 | 145 | } | 239 | | | 240 | 13 | ++Space; | 241 | 13 | Out << '[' << NL; | 242 | 26 | for (auto I = Container.begin(); I != Container.end(); ++I13 ) { | 243 | 13 | const auto &Element = *I; | 244 | | | 245 | 13 | Indent(Out, Space, IsDot) << "{ "; | 246 | 13 | printJson(Element, Out, NL, Space, IsDot) << " }"; | 247 | | | 248 | 13 | if (std::next(I) != Container.end()) | 249 | 0 | Out << ','; | 250 | 13 | Out << NL; | 251 | 13 | } | 252 | | | 253 | 13 | --Space; | 254 | 13 | return Indent(Out, Space, IsDot) << "]"; | 255 | 158 | } |
DynamicType.cpp:llvm::raw_ostream& clang::ento::printJsonContainer<llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > >(llvm::ImmutableSet<clang::ento::DynamicCastInfo, llvm::ImutContainerInfo<clang::ento::DynamicCastInfo> > const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 235 | 13 | unsigned int Space, bool IsDot) { | 236 | 13 | if (Container.isEmpty()) { | 237 | 0 | return Out << "null"; | 238 | 0 | } | 239 | | | 240 | 13 | ++Space; | 241 | 13 | Out << '[' << NL; | 242 | 27 | for (auto I = Container.begin(); I != Container.end(); ++I14 ) { | 243 | 14 | const auto &Element = *I; | 244 | | | 245 | 14 | Indent(Out, Space, IsDot) << "{ "; | 246 | 14 | printJson(Element, Out, NL, Space, IsDot) << " }"; | 247 | | | 248 | 14 | if (std::next(I) != Container.end()) | 249 | 1 | Out << ','; | 250 | 14 | Out << NL; | 251 | 14 | } | 252 | | | 253 | 13 | --Space; | 254 | 13 | return Indent(Out, Space, IsDot) << "]"; | 255 | 13 | } |
DynamicType.cpp:llvm::raw_ostream& clang::ento::printJsonContainer<llvm::ImmutableMap<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo> > >(llvm::ImmutableMap<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo, llvm::ImutKeyValueInfo<clang::ento::SymExpr const*, clang::ento::DynamicTypeInfo> > const&, llvm::raw_ostream&, char const*, unsigned int, bool) Line | Count | Source | 235 | 1 | unsigned int Space, bool IsDot) { | 236 | 1 | if (Container.isEmpty()) { | 237 | 0 | return Out << "null"; | 238 | 0 | } | 239 | | | 240 | 1 | ++Space; | 241 | 1 | Out << '[' << NL; | 242 | 3 | for (auto I = Container.begin(); I != Container.end(); ++I2 ) { | 243 | 2 | const auto &Element = *I; | 244 | | | 245 | 2 | Indent(Out, Space, IsDot) << "{ "; | 246 | 2 | printJson(Element, Out, NL, Space, IsDot) << " }"; | 247 | | | 248 | 2 | if (std::next(I) != Container.end()) | 249 | 1 | Out << ','; | 250 | 2 | Out << NL; | 251 | 2 | } | 252 | | | 253 | 1 | --Space; | 254 | 1 | return Indent(Out, Space, IsDot) << "]"; | 255 | 1 | } |
|
256 | | |
257 | | static raw_ostream &printJson(const CastSet &Set, raw_ostream &Out, |
258 | 13 | const char *NL, unsigned int Space, bool IsDot) { |
259 | 13 | Out << "\"casts\": "; |
260 | 13 | return printJsonContainer(Set, Out, NL, Space, IsDot); |
261 | 13 | } |
262 | | |
263 | | template <class MapTy> |
264 | | static void printJsonImpl(raw_ostream &Out, ProgramStateRef State, |
265 | | const char *Name, const char *NL, unsigned int Space, |
266 | 474 | bool IsDot, bool PrintEvenIfEmpty = true) { |
267 | 474 | const auto &Map = State->get<MapTy>(); |
268 | 474 | if (Map.isEmpty() && !PrintEvenIfEmpty443 ) |
269 | 157 | return; |
270 | | |
271 | 317 | Indent(Out, Space, IsDot) << "\"" << Name << "\": "; |
272 | 317 | printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL; |
273 | 317 | } DynamicType.cpp:void clang::ento::printJsonImpl<(anonymous namespace)::DynamicTypeMap>(llvm::raw_ostream&, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, char const*, char const*, unsigned int, bool, bool) Line | Count | Source | 266 | 158 | bool IsDot, bool PrintEvenIfEmpty = true) { | 267 | 158 | const auto &Map = State->get<MapTy>(); | 268 | 158 | if (Map.isEmpty() && !PrintEvenIfEmpty141 ) | 269 | 0 | return; | 270 | | | 271 | 158 | Indent(Out, Space, IsDot) << "\"" << Name << "\": "; | 272 | 158 | printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL; | 273 | 158 | } |
DynamicType.cpp:void clang::ento::printJsonImpl<(anonymous namespace)::DynamicCastMap>(llvm::raw_ostream&, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, char const*, char const*, unsigned int, bool, bool) Line | Count | Source | 266 | 158 | bool IsDot, bool PrintEvenIfEmpty = true) { | 267 | 158 | const auto &Map = State->get<MapTy>(); | 268 | 158 | if (Map.isEmpty() && !PrintEvenIfEmpty145 ) | 269 | 0 | return; | 270 | | | 271 | 158 | Indent(Out, Space, IsDot) << "\"" << Name << "\": "; | 272 | 158 | printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL; | 273 | 158 | } |
DynamicType.cpp:void clang::ento::printJsonImpl<(anonymous namespace)::DynamicClassObjectMap>(llvm::raw_ostream&, llvm::IntrusiveRefCntPtr<clang::ento::ProgramState const>, char const*, char const*, unsigned int, bool, bool) Line | Count | Source | 266 | 158 | bool IsDot, bool PrintEvenIfEmpty = true) { | 267 | 158 | const auto &Map = State->get<MapTy>(); | 268 | 158 | if (Map.isEmpty() && !PrintEvenIfEmpty157 ) | 269 | 157 | return; | 270 | | | 271 | 1 | Indent(Out, Space, IsDot) << "\"" << Name << "\": "; | 272 | 1 | printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL; | 273 | 1 | } |
|
274 | | |
275 | | static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State, |
276 | | const char *NL, unsigned int Space, |
277 | 158 | bool IsDot) { |
278 | 158 | printJsonImpl<DynamicTypeMap>(Out, State, "dynamic_types", NL, Space, IsDot); |
279 | 158 | } |
280 | | |
281 | | static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State, |
282 | | const char *NL, unsigned int Space, |
283 | 158 | bool IsDot) { |
284 | 158 | printJsonImpl<DynamicCastMap>(Out, State, "dynamic_casts", NL, Space, IsDot); |
285 | 158 | } |
286 | | |
287 | | static void printClassObjectDynamicTypesJson(raw_ostream &Out, |
288 | | ProgramStateRef State, |
289 | | const char *NL, unsigned int Space, |
290 | 158 | bool IsDot) { |
291 | | // Let's print Class object type information only if we have something |
292 | | // meaningful to print. |
293 | 158 | printJsonImpl<DynamicClassObjectMap>(Out, State, "class_object_types", NL, |
294 | 158 | Space, IsDot, |
295 | 158 | /*PrintEvenIfEmpty=*/false); |
296 | 158 | } |
297 | | |
298 | | void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State, |
299 | 158 | const char *NL, unsigned int Space, bool IsDot) { |
300 | 158 | printDynamicTypesJson(Out, State, NL, Space, IsDot); |
301 | 158 | printDynamicCastsJson(Out, State, NL, Space, IsDot); |
302 | 158 | printClassObjectDynamicTypesJson(Out, State, NL, Space, IsDot); |
303 | 158 | } |
304 | | |
305 | | } // namespace ento |
306 | | } // namespace clang |