Coverage Report

Created: 2020-09-15 12:33

/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.73k
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) {
45
7.73k
  MR = MR->StripCasts();
46
7.73k
47
  // Look up the dynamic type in the GDM.
48
7.73k
  if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
49
2.64k
    return *DTI;
50
5.09k
51
  // Otherwise, fall back to what we know about the region.
52
5.09k
  if (const auto *TR = dyn_cast<TypedRegion>(MR))
53
357
    return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
54
4.74k
55
4.74k
  if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
56
4.73k
    SymbolRef Sym = SR->getSymbol();
57
4.73k
    return DynamicTypeInfo(Sym->getType());
58
4.73k
  }
59
1
60
1
  return {};
61
1
}
62
63
const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
64
37
                                             const MemRegion *MR) {
65
37
  return State->get<DynamicTypeMap>(MR);
66
37
}
67
68
288
static void unbox(QualType &Ty) {
69
  // FIXME: Why are we being fed references to pointers in the first place?
70
638
  while (Ty->isReferenceType() || 
Ty->isPointerType()510
)
71
350
    Ty = Ty->getPointeeType();
72
288
  Ty = Ty.getCanonicalType().getUnqualifiedType();
73
288
}
74
75
const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
76
                                          const MemRegion *MR,
77
                                          QualType CastFromTy,
78
120
                                          QualType CastToTy) {
79
120
  const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
80
120
  if (!Lookup)
81
64
    return nullptr;
82
56
83
56
  unbox(CastFromTy);
84
56
  unbox(CastToTy);
85
56
86
56
  for (const DynamicCastInfo &Cast : *Lookup)
87
112
    if (Cast.equals(CastFromTy, CastToTy))
88
32
      return &Cast;
89
56
90
24
  return nullptr;
91
56
}
92
93
DynamicTypeInfo getClassObjectDynamicTypeInfo(ProgramStateRef State,
94
50
                                              SymbolRef Sym) {
95
50
  const DynamicTypeInfo *DTI = State->get<DynamicClassObjectMap>(Sym);
96
35
  return DTI ? *DTI : 
DynamicTypeInfo{}15
;
97
50
}
98
99
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
100
3.99k
                                   DynamicTypeInfo NewTy) {
101
3.99k
  State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
102
3.99k
  assert(State);
103
3.99k
  return State;
104
3.99k
}
105
106
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
107
3.30k
                                   QualType NewTy, bool CanBeSubClassed) {
108
3.30k
  return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
109
3.30k
}
110
111
ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
112
                                          const MemRegion *MR,
113
                                          QualType CastFromTy,
114
                                          QualType CastToTy,
115
88
                                          bool CastSucceeds) {
116
88
  if (!MR)
117
0
    return State;
118
88
119
88
  if (CastSucceeds) {
120
47
    assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
121
47
           "DynamicTypeInfo should always be a pointer.");
122
47
    State = State->set<DynamicTypeMap>(MR, CastToTy);
123
47
  }
124
88
125
88
  unbox(CastFromTy);
126
88
  unbox(CastToTy);
127
88
128
88
  DynamicCastInfo::CastResult ResultKind =
129
47
      CastSucceeds ? DynamicCastInfo::CastResult::Success
130
41
                   : DynamicCastInfo::CastResult::Failure;
131
88
132
88
  CastSet::Factory &F = State->get_context<CastSet>();
133
88
134
88
  const CastSet *TempSet = State->get<DynamicCastMap>(MR);
135
64
  CastSet Set = TempSet ? 
*TempSet24
: F.getEmptySet();
136
88
137
88
  Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
138
88
  State = State->set<DynamicCastMap>(MR, Set);
139
88
140
88
  assert(State);
141
88
  return State;
142
88
}
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
26.2k
static bool isLive(SymbolReaper &SR, const MemRegion *MR) {
159
26.2k
  return SR.isLiveRegion(MR);
160
26.2k
}
161
162
146
static bool isLive(SymbolReaper &SR, SymbolRef Sym) { return SR.isLive(Sym); }
163
164
template <typename MapTy>
165
703k
static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) {
166
703k
  const auto &Map = State->get<MapTy>();
167
703k
168
703k
  for (const auto &Elem : Map)
169
26.4k
    if (!isLive(SR, Elem.first))
170
2.74k
      State = State->remove<MapTy>(Elem.first);
171
703k
172
703k
  return State;
173
703k
}
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
350k
static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) {
166
350k
  const auto &Map = State->get<MapTy>();
167
350k
168
350k
  for (const auto &Elem : Map)
169
26.0k
    if (!isLive(SR, Elem.first))
170
2.64k
      State = State->remove<MapTy>(Elem.first);
171
350k
172
350k
  return State;
173
350k
}
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
3.03k
static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) {
166
3.03k
  const auto &Map = State->get<MapTy>();
167
3.03k
168
3.03k
  for (const auto &Elem : Map)
169
215
    if (!isLive(SR, Elem.first))
170
63
      State = State->remove<MapTy>(Elem.first);
171
3.03k
172
3.03k
  return State;
173
3.03k
}
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
350k
static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) {
166
350k
  const auto &Map = State->get<MapTy>();
167
350k
168
350k
  for (const auto &Elem : Map)
169
146
    if (!isLive(SR, Elem.first))
170
34
      State = State->remove<MapTy>(Elem.first);
171
350k
172
350k
  return State;
173
350k
}
174
175
350k
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) {
176
350k
  return removeDeadImpl<DynamicTypeMap>(State, SR);
177
350k
}
178
179
3.03k
ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
180
3.03k
  return removeDeadImpl<DynamicCastMap>(State, SR);
181
3.03k
}
182
183
ProgramStateRef removeDeadClassObjectTypes(ProgramStateRef State,
184
350k
                                           SymbolReaper &SR) {
185
350k
  return removeDeadImpl<DynamicClassObjectMap>(State, SR);
186
350k
}
187
188
//===----------------------------------------------------------------------===//
189
//               Implementation of the 'printer-to-JSON' function
190
//===----------------------------------------------------------------------===//
191
192
static raw_ostream &printJson(const MemRegion *Region, raw_ostream &Out,
193
6
                              const char *NL, unsigned int Space, bool IsDot) {
194
6
  return Out << "\"region\": \"" << Region << "\"";
195
6
}
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
7
                              const char *NL, unsigned int Space, bool IsDot) {
204
7
  Out << "\"dyn_type\": ";
205
7
  if (!DTI.isValid()) {
206
0
    Out << "null";
207
7
  } else {
208
7
    QualType ToPrint = DTI.getType();
209
7
    if (ToPrint->isAnyPointerType())
210
5
      ToPrint = ToPrint->getPointeeType();
211
7
212
7
    Out << '\"' << ToPrint.getAsString() << "\", \"sub_classable\": "
213
4
        << (DTI.canBeASubClass() ? 
"true"3
: "false");
214
7
  }
215
7
  return Out;
216
7
}
217
218
static raw_ostream &printJson(const DynamicCastInfo &DCI, raw_ostream &Out,
219
2
                              const char *NL, unsigned int Space, bool IsDot) {
220
2
  return Out << "\"from\": \"" << DCI.from().getAsString() << "\", \"to\": \""
221
2
             << DCI.to().getAsString() << "\", \"kind\": \""
222
1
             << (DCI.succeeds() ? "success" : "fail") << "\"";
223
2
}
224
225
template <class T, class U>
226
static raw_ostream &printJson(const std::pair<T, U> &Pair, raw_ostream &Out,
227
8
                              const char *NL, unsigned int Space, bool IsDot) {
228
8
  printJson(Pair.first, Out, NL, Space, IsDot) << ", ";
229
8
  return printJson(Pair.second, Out, NL, Space, IsDot);
230
8
}
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
5
                              const char *NL, unsigned int Space, bool IsDot) {
228
5
  printJson(Pair.first, Out, NL, Space, IsDot) << ", ";
229
5
  return printJson(Pair.second, Out, NL, Space, IsDot);
230
5
}
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
1
                              const char *NL, unsigned int Space, bool IsDot) {
228
1
  printJson(Pair.first, Out, NL, Space, IsDot) << ", ";
229
1
  return printJson(Pair.second, Out, NL, Space, IsDot);
230
1
}
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
254
                                       unsigned int Space, bool IsDot) {
236
254
  if (Container.isEmpty()) {
237
246
    return Out << "null";
238
246
  }
239
8
240
8
  ++Space;
241
8
  Out << '[' << NL;
242
18
  for (auto I = Container.begin(); I != Container.end(); 
++I10
) {
243
10
    const auto &Element = *I;
244
10
245
10
    Indent(Out, Space, IsDot) << "{ ";
246
10
    printJson(Element, Out, NL, Space, IsDot) << " }";
247
10
248
10
    if (std::next(I) != Container.end())
249
2
      Out << ',';
250
10
    Out << NL;
251
10
  }
252
8
253
8
  --Space;
254
8
  return Indent(Out, Space, IsDot) << "]";
255
8
}
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
126
                                       unsigned int Space, bool IsDot) {
236
126
  if (Container.isEmpty()) {
237
121
    return Out << "null";
238
121
  }
239
5
240
5
  ++Space;
241
5
  Out << '[' << NL;
242
10
  for (auto I = Container.begin(); I != Container.end(); 
++I5
) {
243
5
    const auto &Element = *I;
244
5
245
5
    Indent(Out, Space, IsDot) << "{ ";
246
5
    printJson(Element, Out, NL, Space, IsDot) << " }";
247
5
248
5
    if (std::next(I) != Container.end())
249
0
      Out << ',';
250
5
    Out << NL;
251
5
  }
252
5
253
5
  --Space;
254
5
  return Indent(Out, Space, IsDot) << "]";
255
5
}
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
126
                                       unsigned int Space, bool IsDot) {
236
126
  if (Container.isEmpty()) {
237
125
    return Out << "null";
238
125
  }
239
1
240
1
  ++Space;
241
1
  Out << '[' << NL;
242
2
  for (auto I = Container.begin(); I != Container.end(); 
++I1
) {
243
1
    const auto &Element = *I;
244
1
245
1
    Indent(Out, Space, IsDot) << "{ ";
246
1
    printJson(Element, Out, NL, Space, IsDot) << " }";
247
1
248
1
    if (std::next(I) != Container.end())
249
0
      Out << ',';
250
1
    Out << NL;
251
1
  }
252
1
253
1
  --Space;
254
1
  return Indent(Out, Space, IsDot) << "]";
255
1
}
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
1
                                       unsigned int Space, bool IsDot) {
236
1
  if (Container.isEmpty()) {
237
0
    return Out << "null";
238
0
  }
239
1
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
2
245
2
    Indent(Out, Space, IsDot) << "{ ";
246
2
    printJson(Element, Out, NL, Space, IsDot) << " }";
247
2
248
2
    if (std::next(I) != Container.end())
249
1
      Out << ',';
250
2
    Out << NL;
251
2
  }
252
1
253
1
  --Space;
254
1
  return Indent(Out, Space, IsDot) << "]";
255
1
}
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
1
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
2
245
2
    Indent(Out, Space, IsDot) << "{ ";
246
2
    printJson(Element, Out, NL, Space, IsDot) << " }";
247
2
248
2
    if (std::next(I) != Container.end())
249
1
      Out << ',';
250
2
    Out << NL;
251
2
  }
252
1
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
1
                              const char *NL, unsigned int Space, bool IsDot) {
259
1
  Out << "\"casts\": ";
260
1
  return printJsonContainer(Set, Out, NL, Space, IsDot);
261
1
}
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
378
                          bool IsDot, bool PrintEvenIfEmpty = true) {
267
378
  const auto &Map = State->get<MapTy>();
268
378
  if (Map.isEmpty() && 
!PrintEvenIfEmpty371
)
269
125
    return;
270
253
271
253
  Indent(Out, Space, IsDot) << "\"" << Name << "\": ";
272
253
  printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL;
273
253
}
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
126
                          bool IsDot, bool PrintEvenIfEmpty = true) {
267
126
  const auto &Map = State->get<MapTy>();
268
126
  if (Map.isEmpty() && 
!PrintEvenIfEmpty121
)
269
0
    return;
270
126
271
126
  Indent(Out, Space, IsDot) << "\"" << Name << "\": ";
272
126
  printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL;
273
126
}
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
126
                          bool IsDot, bool PrintEvenIfEmpty = true) {
267
126
  const auto &Map = State->get<MapTy>();
268
126
  if (Map.isEmpty() && 
!PrintEvenIfEmpty125
)
269
0
    return;
270
126
271
126
  Indent(Out, Space, IsDot) << "\"" << Name << "\": ";
272
126
  printJsonContainer(Map, Out, NL, Space, IsDot) << "," << NL;
273
126
}
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
126
                          bool IsDot, bool PrintEvenIfEmpty = true) {
267
126
  const auto &Map = State->get<MapTy>();
268
126
  if (Map.isEmpty() && 
!PrintEvenIfEmpty125
)
269
125
    return;
270
1
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
126
                                  bool IsDot) {
278
126
  printJsonImpl<DynamicTypeMap>(Out, State, "dynamic_types", NL, Space, IsDot);
279
126
}
280
281
static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
282
                                  const char *NL, unsigned int Space,
283
126
                                  bool IsDot) {
284
126
  printJsonImpl<DynamicCastMap>(Out, State, "dynamic_casts", NL, Space, IsDot);
285
126
}
286
287
static void printClassObjectDynamicTypesJson(raw_ostream &Out,
288
                                             ProgramStateRef State,
289
                                             const char *NL, unsigned int Space,
290
126
                                             bool IsDot) {
291
  // Let's print Class object type information only if we have something
292
  // meaningful to print.
293
126
  printJsonImpl<DynamicClassObjectMap>(Out, State, "class_object_types", NL,
294
126
                                       Space, IsDot,
295
126
                                       /*PrintEvenIfEmpty=*/false);
296
126
}
297
298
void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
299
126
                              const char *NL, unsigned int Space, bool IsDot) {
300
126
  printDynamicTypesJson(Out, State, NL, Space, IsDot);
301
126
  printDynamicCastsJson(Out, State, NL, Space, IsDot);
302
126
  printClassObjectDynamicTypesJson(Out, State, NL, Space, IsDot);
303
126
}
304
305
} // namespace ento
306
} // namespace clang