Coverage Report

Created: 2023-09-12 09:32

/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