1 //===- DynamicType.cpp - Dynamic type related APIs --------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
13 //===----------------------------------------------------------------------===//
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"
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)
30 /// A set factory of dynamic cast informations.
31 REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicCastInfo)
33 /// A map from symbols to cast informations.
34 REGISTER_MAP_WITH_PROGRAMSTATE(DynamicCastMap, const clang::ento::MemRegion *,
40 DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) {
41 MR = MR->StripCasts();
43 // Look up the dynamic type in the GDM.
44 if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
47 // Otherwise, fall back to what we know about the region.
48 if (const auto *TR = dyn_cast<TypedRegion>(MR))
49 return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
51 if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
52 SymbolRef Sym = SR->getSymbol();
53 return DynamicTypeInfo(Sym->getType());
59 const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
60 const MemRegion *MR) {
61 return State->get<DynamicTypeMap>(MR);
64 const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
68 const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
72 for (const DynamicCastInfo &Cast : *Lookup)
73 if (Cast.equals(CastFromTy, CastToTy))
79 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
80 DynamicTypeInfo NewTy) {
81 State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
86 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
87 QualType NewTy, bool CanBeSubClassed) {
88 return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
91 ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
100 assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
101 "DynamicTypeInfo should always be a pointer.");
102 State = State->set<DynamicTypeMap>(MR, CastToTy);
105 DynamicCastInfo::CastResult ResultKind =
106 CastSucceeds ? DynamicCastInfo::CastResult::Success
107 : DynamicCastInfo::CastResult::Failure;
109 CastSet::Factory &F = State->get_context<CastSet>();
111 const CastSet *TempSet = State->get<DynamicCastMap>(MR);
112 CastSet Set = TempSet ? *TempSet : F.getEmptySet();
114 Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
115 State = State->set<DynamicCastMap>(MR, Set);
121 template <typename MapTy>
122 ProgramStateRef removeDead(ProgramStateRef State, const MapTy &Map,
124 for (const auto &Elem : Map)
125 if (!SR.isLiveRegion(Elem.first))
126 State = State->remove<DynamicCastMap>(Elem.first);
131 ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) {
132 return removeDead(State, State->get<DynamicTypeMap>(), SR);
135 ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
136 return removeDead(State, State->get<DynamicCastMap>(), SR);
139 static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State,
140 const char *NL, unsigned int Space,
142 Indent(Out, Space, IsDot) << "\"dynamic_types\": ";
144 const DynamicTypeMapTy &Map = State->get<DynamicTypeMap>();
146 Out << "null," << NL;
152 for (DynamicTypeMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
153 const MemRegion *MR = I->first;
154 const DynamicTypeInfo &DTI = I->second;
155 Indent(Out, Space, IsDot)
156 << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
157 if (!DTI.isValid()) {
160 Out << '\"' << DTI.getType()->getPointeeType().getAsString()
161 << "\", \"sub_classable\": "
162 << (DTI.canBeASubClass() ? "true" : "false");
166 if (std::next(I) != Map.end())
172 Indent(Out, Space, IsDot) << "]," << NL;
175 static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
176 const char *NL, unsigned int Space,
178 Indent(Out, Space, IsDot) << "\"dynamic_casts\": ";
180 const DynamicCastMapTy &Map = State->get<DynamicCastMap>();
182 Out << "null," << NL;
188 for (DynamicCastMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
189 const MemRegion *MR = I->first;
190 const CastSet &Set = I->second;
192 Indent(Out, Space, IsDot) << "{ \"region\": \"" << MR << "\", \"casts\": ";
198 for (CastSet::iterator SI = Set.begin(); SI != Set.end(); ++SI) {
199 Indent(Out, Space, IsDot)
200 << "{ \"from\": \"" << SI->from().getAsString() << "\", \"to\": \""
201 << SI->to().getAsString() << "\", \"kind\": \""
202 << (SI->succeeds() ? "success" : "fail") << "\" }";
204 if (std::next(SI) != Set.end())
209 Indent(Out, Space, IsDot) << ']';
213 if (std::next(I) != Map.end())
219 Indent(Out, Space, IsDot) << "]," << NL;
222 void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
223 const char *NL, unsigned int Space, bool IsDot) {
224 printDynamicTypesJson(Out, State, NL, Space, IsDot);
225 printDynamicCastsJson(Out, State, NL, Space, IsDot);