summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
blob: 79424452240d71bf6601932a9b92d274de8f91cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//===- 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(), /*CanBeSub=*/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