21#include "llvm/Support/Casting.h"
22#include "llvm/Support/raw_ostream.h"
39 clang::ento::DynamicTypeInfo)
44DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
const MemRegion *MR) {
45 MR = MR->StripCasts();
48 if (
const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
52 if (
const auto *TR = dyn_cast<TypedRegion>(MR))
53 return DynamicTypeInfo(TR->getLocationType(),
false);
55 if (
const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
56 SymbolRef Sym = SR->getSymbol();
57 return DynamicTypeInfo(Sym->getType());
63const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
64 const MemRegion *MR) {
65 return State->get<DynamicTypeMap>(MR);
68static void unbox(QualType &Ty) {
70 while (Ty->isReferenceType() || Ty->isPointerType())
71 Ty = Ty->getPointeeType();
72 Ty = Ty.getCanonicalType().getUnqualifiedType();
75const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
79 const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
86 for (
const DynamicCastInfo &Cast : *Lookup)
87 if (Cast.equals(CastFromTy, CastToTy))
93DynamicTypeInfo getClassObjectDynamicTypeInfo(ProgramStateRef State,
95 const DynamicTypeInfo *DTI = State->get<DynamicClassObjectMap>(Sym);
96 return DTI ? *DTI : DynamicTypeInfo{};
99ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
const MemRegion *MR,
100 DynamicTypeInfo NewTy) {
101 State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
106ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
const MemRegion *MR,
107 QualType NewTy,
bool CanBeSubClassed) {
108 return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
111ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
120 assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
121 "DynamicTypeInfo should always be a pointer.");
122 State = State->set<DynamicTypeMap>(MR, CastToTy);
128 DynamicCastInfo::CastResult ResultKind =
129 CastSucceeds ? DynamicCastInfo::CastResult::Success
130 : DynamicCastInfo::CastResult::Failure;
132 CastSet::Factory &F = State->get_context<CastSet>();
134 const CastSet *TempSet = State->get<DynamicCastMap>(MR);
135 CastSet Set = TempSet ? *TempSet : F.getEmptySet();
137 Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
138 State = State->set<DynamicCastMap>(MR, Set);
144ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State,
146 DynamicTypeInfo NewTy) {
147 State = State->set<DynamicClassObjectMap>(Sym, NewTy);
151ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State,
152 SymbolRef Sym, QualType NewTy,
153 bool CanBeSubClassed) {
154 return setClassObjectDynamicTypeInfo(State, Sym,
155 DynamicTypeInfo(NewTy, CanBeSubClassed));
158static bool isLive(SymbolReaper &SR,
const MemRegion *MR) {
159 return SR.isLiveRegion(MR);
162static bool isLive(SymbolReaper &SR, SymbolRef Sym) {
return SR.isLive(Sym); }
164template <
typename MapTy>
165static ProgramStateRef removeDeadImpl(ProgramStateRef State, SymbolReaper &SR) {
166 const auto &Map = State->get<
MapTy>();
168 for (
const auto &Elem : Map)
169 if (!isLive(SR, Elem.first))
170 State = State->remove<
MapTy>(Elem.first);
175ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) {
176 return removeDeadImpl<DynamicTypeMap>(State, SR);
179ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
180 return removeDeadImpl<DynamicCastMap>(State, SR);
183ProgramStateRef removeDeadClassObjectTypes(ProgramStateRef State,
185 return removeDeadImpl<DynamicClassObjectMap>(State, SR);
192static raw_ostream &printJson(
const MemRegion *Region, raw_ostream &Out,
193 const char *NL,
unsigned int Space,
bool IsDot) {
194 return Out <<
"\"region\": \"" << Region <<
"\"";
197static raw_ostream &printJson(
const SymExpr *Symbol, raw_ostream &Out,
198 const char *NL,
unsigned int Space,
bool IsDot) {
199 return Out <<
"\"symbol\": \"" << Symbol <<
"\"";
202static raw_ostream &printJson(
const DynamicTypeInfo &DTI, raw_ostream &Out,
203 const char *NL,
unsigned int Space,
bool IsDot) {
204 Out <<
"\"dyn_type\": ";
205 if (!DTI.isValid()) {
208 QualType ToPrint = DTI.getType();
209 if (ToPrint->isAnyPointerType())
210 ToPrint = ToPrint->getPointeeType();
212 Out <<
'\"' << ToPrint <<
"\", \"sub_classable\": "
213 << (DTI.canBeASubClass() ?
"true" :
"false");
218static raw_ostream &printJson(
const DynamicCastInfo &DCI, raw_ostream &Out,
219 const char *NL,
unsigned int Space,
bool IsDot) {
220 return Out <<
"\"from\": \"" << DCI.from() <<
"\", \"to\": \"" << DCI.to()
221 <<
"\", \"kind\": \"" << (DCI.succeeds() ?
"success" :
"fail")
225template <
class T,
class U>
226static raw_ostream &printJson(
const std::pair<T, U> &Pair, raw_ostream &Out,
227 const char *NL,
unsigned int Space,
bool IsDot) {
228 printJson(Pair.first, Out, NL, Space, IsDot) <<
", ";
229 return printJson(Pair.second, Out, NL, Space, IsDot);
232template <
class ContainerTy>
233static raw_ostream &printJsonContainer(
const ContainerTy &Container,
234 raw_ostream &Out,
const char *NL,
235 unsigned int Space,
bool IsDot) {
236 if (Container.isEmpty()) {
237 return Out <<
"null";
242 for (
auto I = Container.begin(); I != Container.end(); ++I) {
243 const auto &Element = *I;
245 Indent(Out, Space, IsDot) <<
"{ ";
246 printJson(Element, Out, NL, Space, IsDot) <<
" }";
248 if (std::next(I) != Container.end())
254 return Indent(Out, Space, IsDot) <<
"]";
257static raw_ostream &printJson(
const CastSet &Set, raw_ostream &Out,
258 const char *NL,
unsigned int Space,
bool IsDot) {
259 Out <<
"\"casts\": ";
260 return printJsonContainer(Set, Out, NL, Space, IsDot);
263template <
class MapTy>
264static void printJsonImpl(raw_ostream &Out, ProgramStateRef State,
265 const char *Name,
const char *NL,
unsigned int Space,
266 bool IsDot,
bool PrintEvenIfEmpty =
true) {
267 const auto &Map = State->get<
MapTy>();
268 if (Map.isEmpty() && !PrintEvenIfEmpty)
271 Indent(Out, Space, IsDot) <<
"\"" << Name <<
"\": ";
272 printJsonContainer(Map, Out, NL, Space, IsDot) <<
"," << NL;
275static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State,
276 const char *NL,
unsigned int Space,
278 printJsonImpl<DynamicTypeMap>(Out, State,
"dynamic_types", NL, Space, IsDot);
281static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
282 const char *NL,
unsigned int Space,
284 printJsonImpl<DynamicCastMap>(Out, State,
"dynamic_casts", NL, Space, IsDot);
287static void printClassObjectDynamicTypesJson(raw_ostream &Out,
288 ProgramStateRef State,
289 const char *NL,
unsigned int Space,
293 printJsonImpl<DynamicClassObjectMap>(Out, State,
"class_object_types", NL,
298void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
299 const char *NL,
unsigned int Space,
bool IsDot) {
300 printDynamicTypesJson(Out, State, NL, Space, IsDot);
301 printDynamicCastsJson(Out, State, NL, Space, IsDot);
302 printClassObjectDynamicTypesJson(Out, State, NL, Space, IsDot);
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::DenseMap< Stmt *, Stmt * > MapTy
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set type Name and registers the factory for such sets in the program state,...
Stores the currently inferred strictest bound on the runtime type of a region in a given state along ...
MemRegion - The root abstract class for all memory regions.
The JSON file list parser is used to communicate input to InstallAPI.