blob: 22c4cc4a624a7b4e540434bd29a3a9db5ff5a532 [file] [log] [blame]
//===- DynamicTypeMap.cpp - Dynamic Type Info related APIs ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines APIs that track and query dynamic type information. This
// information can be used to devirtualize calls during the symbolic execution
// or do type checking.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
namespace clang {
namespace ento {
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
const MemRegion *Reg) {
Reg = Reg->StripCasts();
// Look up the dynamic type in the GDM.
const DynamicTypeInfo *GDMType = State->get<DynamicTypeMap>(Reg);
if (GDMType)
return *GDMType;
// Otherwise, fall back to what we know about the region.
if (const auto *TR = dyn_cast<TypedRegion>(Reg))
return DynamicTypeInfo(TR->getLocationType(), /*CanBeSubclass=*/false);
if (const auto *SR = dyn_cast<SymbolicRegion>(Reg)) {
SymbolRef Sym = SR->getSymbol();
return DynamicTypeInfo(Sym->getType());
}
return {};
}
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
DynamicTypeInfo NewTy) {
Reg = Reg->StripCasts();
ProgramStateRef NewState = State->set<DynamicTypeMap>(Reg, NewTy);
assert(NewState);
return NewState;
}
void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
const char *NL, unsigned int Space, bool IsDot) {
Indent(Out, Space, IsDot) << "\"dynamic_types\": ";
const DynamicTypeMapTy &DTM = State->get<DynamicTypeMap>();
if (DTM.isEmpty()) {
Out << "null," << NL;
return;
}
++Space;
Out << '[' << NL;
for (DynamicTypeMapTy::iterator I = DTM.begin(); I != DTM.end(); ++I) {
const MemRegion *MR = I->first;
const DynamicTypeInfo &DTI = I->second;
Out << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
if (DTI.isValid()) {
Out << '\"' << DTI.getType()->getPointeeType().getAsString()
<< "\" \"sub_classable\": "
<< (DTI.canBeASubClass() ? "true" : "false");
} else {
Out << "null"; // Invalid type info
}
Out << "\" }";
if (std::next(I) != DTM.end())
Out << ',';
Out << NL;
}
--Space;
Indent(Out, Space, IsDot) << "]," << NL;
}
void *ProgramStateTrait<DynamicTypeMap>::GDMIndex() {
static int index = 0;
return &index;
}
} // namespace ento
} // namespace clang