Charusso updated this revision to Diff 221070.
Charusso marked 9 inline comments as done.
Charusso added a comment.

- Try to do the math.
- Create a consistent dynamic type API.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67079/new/

https://reviews.llvm.org/D67079

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
  clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/DynamicType.cpp
  clang/test/Analysis/cast-value-hierarchy-failures-set.cpp
  clang/test/Analysis/cast-value-hierarchy-succeeds.cpp
  clang/test/Analysis/cast-value-hierarchy.cpp
  clang/test/Analysis/cast-value-notes.cpp
  clang/test/Analysis/cast-value-state-dump.cpp
  clang/test/Analysis/expr-inspection.c

Index: clang/test/Analysis/expr-inspection.c
===================================================================
--- clang/test/Analysis/expr-inspection.c
+++ clang/test/Analysis/expr-inspection.c
@@ -38,7 +38,7 @@
 // CHECK-NEXT:     { "symbol": "reg_$0<int x>", "range": "{ [-2147483648, 13] }" }
 // CHECK-NEXT:   ],
 // CHECK-NEXT:   "dynamic_types": null,
-// CHECK-NEXT:   "dynamic_casts": null,
+// CHECK-NEXT:   "failed_casts": null,
 // CHECK-NEXT:   "constructing_objects": null,
 // CHECK-NEXT:   "checker_messages": null
 // CHECK-NEXT: }
Index: clang/test/Analysis/cast-value-state-dump.cpp
===================================================================
--- clang/test/Analysis/cast-value-state-dump.cpp
+++ clang/test/Analysis/cast-value-state-dump.cpp
@@ -11,19 +11,31 @@
 class Triangle : public Shape {};
 class Circle : public Shape {};
 class Square : public Shape {};
+class Octagram : public Shape {};
 } // namespace clang
 
 using namespace llvm;
 using namespace clang;
 
 void evalNonNullParamNonNullReturn(const Shape *S) {
+  if (isa<Triangle>(S)) {
+    // expected-note@-1 {{Assuming 'S' is not a 'Triangle'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
+  if (isa<Octagram>(S)) {
+    // expected-note@-1 {{Assuming 'S' is not an 'Octagram'}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
   const auto *C = dyn_cast_or_null<Circle>(S);
   // expected-note@-1 {{Assuming 'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
 
-  // FIXME: We assumed that 'S' is a 'Circle' therefore it is not a 'Square'.
   if (dyn_cast_or_null<Square>(S)) {
-    // expected-note@-1 {{Assuming 'S' is not a 'Square'}}
+    // expected-note@-1 {{'S' is not a 'Square'}}
     // expected-note@-2 {{Taking false branch}}
     return;
   }
@@ -33,11 +45,11 @@
   // CHECK:      "dynamic_types": [
   // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "dyn_type": "const class clang::Circle", "sub_classable": true }
   // CHECK-NEXT: ],
-  // CHECK-NEXT: "dynamic_casts": [
-  // CHECK:        { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "casts": [
-  // CHECK-NEXT:     { "from": "const struct clang::Shape *", "to": "const class clang::Circle *", "kind": "success" },
-  // CHECK-NEXT:     { "from": "const struct clang::Shape *", "to": "const class clang::Square *", "kind": "fail" }
+  // CHECK-NEXT: "failed_casts": [
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "casts": [
+  // CHECK-NEXT:     "const class clang::Square *", "class clang::Triangle *", "class clang::Octagram *"
   // CHECK-NEXT:   ]}
+  // CHECK-NEXT: ],
 
   (void)(1 / !C);
   // expected-note@-1 {{'C' is non-null}}
Index: clang/test/Analysis/cast-value-notes.cpp
===================================================================
--- clang/test/Analysis/cast-value-notes.cpp
+++ clang/test/Analysis/cast-value-notes.cpp
@@ -37,12 +37,6 @@
     return;
   }
 
-  if (dyn_cast_or_null<Triangle>(C)) {
-    // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}}
-    // expected-note@-2 {{Taking false branch}}
-    return;
-  }
-
   if (isa<Triangle>(C)) {
     // expected-note@-1 {{'C' is not a 'Triangle'}}
     // expected-note@-2 {{Taking false branch}}
@@ -65,14 +59,8 @@
   // expected-note@-1 {{'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
 
-  if (!isa<Triangle>(C)) {
-    // expected-note@-1 {{Assuming 'C' is a 'Triangle'}}
-    // expected-note@-2 {{Taking false branch}}
-    return;
-  }
-
-  if (!isa<Triangle>(C)) {
-    // expected-note@-1 {{'C' is a 'Triangle'}}
+  if (isa<Triangle>(C)) {
+    // expected-note@-1 {{'C' is not a 'Triangle'}}
     // expected-note@-2 {{Taking false branch}}
     return;
   }
Index: clang/test/Analysis/cast-value-hierarchy.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/cast-value-hierarchy.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -verify %s
+
+#include "Inputs/llvm.h"
+
+using namespace llvm;
+
+void clang_analyzer_warnIfReached();
+                    //   X
+struct X {};        //  / \.
+struct Y : X {};    // Y-. \.
+struct Z : X, Y {}; //    `-Z
+// expected-warning@-1 {{direct base 'X' is inaccessible due to ambiguity:\n    struct Z -> struct X\n    struct Z -> struct Y -> struct X}}
+
+void test_triangle_feasible(const X *x) {
+  if (isa<Y>(x))
+    if (isa<Z>(x))
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_triangle_infeasible(const X *x) {
+  if (!isa<Y>(x))
+    if (isa<Z>(x))
+      clang_analyzer_warnIfReached(); // no-warning
+}
+
+struct A {};        //   A
+struct B : A {};    //  / \.
+struct C : A {};    // B   C
+struct D : B, C {}; //  \ / \.
+struct E : C {};    //   D   E
+
+void test_failures_set(const A *a) {
+  if (isa<B>(a) || isa<C>(a))
+    if (isa<D>(a))
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test_faiures_set_infeasible(const A *a) {
+  if (!isa<B>(a) && isa<C>(a))
+    if (isa<D>(a))
+      clang_analyzer_warnIfReached(); // no-warning
+}
+
+void test_downcast(const A *a) {
+  if (isa<B>(a)) {
+    if (isa<D>(a))
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test_downcast_infeasible(const A *a) {
+  if (isa<B>(a))
+    if (isa<C>(a))
+      clang_analyzer_warnIfReached(); // no-warning
+}
+
+void test_upcast(const A *a) {
+  if (isa<D>(a) && isa<B>(a)) {
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+    if (isa<C>(a))
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test_downcast_chaining_infeasible(const A *a) {
+  if (isa<B>(a) && !isa<C>(a))
+    if (isa<D>(a) || isa<E>(a))
+      clang_analyzer_warnIfReached(); // no-warning
+}
Index: clang/test/Analysis/cast-value-hierarchy-succeeds.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/cast-value-hierarchy-succeeds.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -verify %s 2>&1 | FileCheck %s
+
+// expected-no-diagnostics
+
+#include "Inputs/llvm.h"
+
+using namespace llvm;
+
+void clang_analyzer_printState();
+
+struct A {};     // A
+struct B : A {}; // `-B
+struct C : B {}; //   `-C
+struct D : C {}; //     `-D
+
+void test_downcast(const A *a) {
+  clang_analyzer_printState();
+  // CHECK: "dynamic_types": null
+
+  if (!isa<C>(a))
+    return;
+
+  clang_analyzer_printState();
+  // CHECK:      "dynamic_types": [
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct A * a>}", "dyn_type": "struct C", "sub_classable": true }
+
+  if (!isa<D>(a))
+    return;
+
+  // A succeeded cast gives more precision what is the most-derived class.
+  clang_analyzer_printState();
+  // CHECK:      "dynamic_types": [
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct A * a>}", "dyn_type": "struct D", "sub_classable": true }
+
+  if (!isa<B>(a))
+    return;
+
+  // A succeeded upcast does not give more information.
+  clang_analyzer_printState();
+  // CHECK:      "dynamic_types": [
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct A * a>}", "dyn_type": "struct D", "sub_classable": true }
+}
Index: clang/test/Analysis/cast-value-hierarchy-failures-set.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/cast-value-hierarchy-failures-set.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
+// RUN:  -verify %s 2>&1 | FileCheck %s
+
+// expected-no-diagnostics
+
+#include "Inputs/llvm.h"
+
+using namespace llvm;
+
+void clang_analyzer_printState();
+
+struct A {};     // A
+struct B : A {}; // `-B
+struct C : B {}; //   `-C
+struct D : C {}; //     `-D
+
+void test_downcast(const A *a) {
+  if (isa<C>(a))
+    return;
+
+  clang_analyzer_printState();
+  // CHECK:    "failed_casts": [
+  // CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct A * a>}", "casts": [
+  // CHECK-NEXT:   "struct C *"
+  // CHECK-NEXT: ]}
+
+  // A failed upcast gives more precision what the type cannot be.
+  if (isa<B>(a))
+    return;
+
+  clang_analyzer_printState();
+  // CHECK:    "failed_casts": [
+  // CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct A * a>}", "casts": [
+  // CHECK-NEXT:   "struct B *"
+  // CHECK-NEXT: ]}
+
+  // A failed downcast does not give more information.
+  if (isa<D>(a))
+    return;
+
+  clang_analyzer_printState();
+  // CHECK:    "failed_casts": [
+  // CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct A * a>}", "casts": [
+  // CHECK-NEXT:   "struct B *"
+  // CHECK-NEXT: ]}
+}
Index: clang/lib/StaticAnalyzer/Core/DynamicType.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/DynamicType.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicType.cpp
@@ -27,92 +27,126 @@
 REGISTER_MAP_WITH_PROGRAMSTATE(DynamicTypeMap, const clang::ento::MemRegion *,
                                clang::ento::DynamicTypeInfo)
 
-/// A set factory of dynamic cast informations.
-REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicCastInfo)
+/// A set factory of dynamic cast informations as type informations.
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicTypeInfo)
 
-/// A map from symbols to cast informations.
-REGISTER_MAP_WITH_PROGRAMSTATE(DynamicCastMap, const clang::ento::MemRegion *,
+/// A map from symbols to failed cast informations.
+REGISTER_MAP_WITH_PROGRAMSTATE(FailedCastMap, const clang::ento::MemRegion *,
                                CastSet)
 
 namespace clang {
 namespace ento {
 
-DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) {
-  MR = MR->StripCasts();
+static const MemRegion *getSimplifiedRegion(const MemRegion *MR) {
+  return MR->StripCasts();
+}
+
+bool isDerivedFrom(QualType X, QualType Y) {
+  const CXXRecordDecl *XRD = X->getPointeeCXXRecordDecl();
+  const CXXRecordDecl *YRD = Y->getPointeeCXXRecordDecl();
+  return XRD == YRD || XRD->isDerivedFrom(YRD);
+}
+
+const DynamicTypeInfo *getDynamicTypeInfo(ProgramStateRef State,
+                                          const MemRegion *MR) {
+  MR = getSimplifiedRegion(MR);
 
   // Look up the dynamic type in the GDM.
   if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
-    return *DTI;
+    return DTI;
 
   // Otherwise, fall back to what we know about the region.
   if (const auto *TR = dyn_cast<TypedRegion>(MR))
-    return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
+    return new DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
 
-  if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
-    SymbolRef Sym = SR->getSymbol();
-    return DynamicTypeInfo(Sym->getType());
-  }
+  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+    return new DynamicTypeInfo(SR->getSymbol()->getType());
 
-  return {};
+  return nullptr;
 }
 
-const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
-                                             const MemRegion *MR) {
+const DynamicTypeInfo *getStoredDynamicTypeInfo(ProgramStateRef State,
+                                                const MemRegion *MR) {
+  if (!MR)
+    return nullptr;
+
+  MR = getSimplifiedRegion(MR);
   return State->get<DynamicTypeMap>(MR);
 }
 
-const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
-                                          const MemRegion *MR,
-                                          QualType CastFromTy,
-                                          QualType CastToTy) {
-  const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
+const DynamicTypeInfo *getFailedCastInfo(ProgramStateRef State,
+                                         const MemRegion *MR,
+                                         QualType CastToTy) {
+  if (!MR)
+    return nullptr;
+
+  MR = getSimplifiedRegion(MR);
+  const auto *Lookup = State->get<FailedCastMap>().lookup(MR);
   if (!Lookup)
     return nullptr;
 
-  for (const DynamicCastInfo &Cast : *Lookup)
-    if (Cast.equals(CastFromTy, CastToTy))
+  for (const DynamicTypeInfo &Cast : *Lookup) {
+    QualType FailedCastTy = Cast.getType();
+    if (FailedCastTy->getPointeeCXXRecordDecl() ==
+            CastToTy->getPointeeCXXRecordDecl() ||
+        isDerivedFrom(CastToTy, FailedCastTy)) {
       return &Cast;
+    }
+  }
 
   return nullptr;
 }
 
 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
-                                   DynamicTypeInfo NewTy) {
-  State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
+                                   const DynamicTypeInfo *NewTy) {
+  assert((NewTy->getType()->isAnyPointerType() ||
+          NewTy->getType()->isReferenceType()) &&
+         "DynamicTypeInfo should always be a pointer.");
+  MR = getSimplifiedRegion(MR);
+  State = State->set<DynamicTypeMap>(MR, *NewTy);
   assert(State);
   return State;
 }
 
 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
                                    QualType NewTy, bool CanBeSubClassed) {
-  return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
+  return setDynamicTypeInfo(State, MR,
+                            new DynamicTypeInfo(NewTy, CanBeSubClassed));
 }
 
 ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
                                           const MemRegion *MR,
-                                          QualType CastFromTy,
                                           QualType CastToTy,
+                                          const DynamicTypeInfo *CastInfo,
                                           bool CastSucceeds) {
   if (!MR)
     return State;
 
-  if (CastSucceeds) {
-    assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
-           "DynamicTypeInfo should always be a pointer.");
-    State = State->set<DynamicTypeMap>(MR, CastToTy);
-  }
-
-  DynamicCastInfo::CastResult ResultKind =
-      CastSucceeds ? DynamicCastInfo::CastResult::Success
-                   : DynamicCastInfo::CastResult::Failure;
+  MR = getSimplifiedRegion(MR);
 
-  CastSet::Factory &F = State->get_context<CastSet>();
-
-  const CastSet *TempSet = State->get<DynamicCastMap>(MR);
-  CastSet Set = TempSet ? *TempSet : F.getEmptySet();
+  if (CastSucceeds) {
+    // If there is no 'CastInfo' or the 'CastToTy' is a downcast store it.
+    // Downcast gives more precision what is the current most derived class.
+    if (!CastInfo || isDerivedFrom(CastToTy, CastInfo->getType())) {
+      State = setDynamicTypeInfo(State, MR, CastToTy);
+    }
+  } else {
+    CastSet::Factory &F = State->get_context<CastSet>();
+
+    const CastSet *TempSet = State->get<FailedCastMap>(MR);
+    CastSet Set = TempSet ? *TempSet : F.getEmptySet();
+
+    // If there is no 'CastInfo' or the 'CastToTy' is an upcast store it.
+    // Upcast gives more precision what is the largest set the class cannot be.
+    if (CastInfo && isDerivedFrom(CastInfo->getType(), CastToTy)) {
+      Set = F.add(Set, CastToTy);
+      Set = F.remove(Set, *CastInfo);
+    } else if (!CastInfo || !isDerivedFrom(CastToTy, CastInfo->getType())) {
+      Set = F.add(Set, CastToTy);
+    }
 
-  Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
-  State = State->set<DynamicCastMap>(MR, Set);
+    State = State->set<FailedCastMap>(MR, Set);
+  }
 
   assert(State);
   return State;
@@ -123,7 +157,7 @@
                            SymbolReaper &SR) {
   for (const auto &Elem : Map)
     if (!SR.isLiveRegion(Elem.first))
-      State = State->remove<DynamicCastMap>(Elem.first);
+      State = State->remove<FailedCastMap>(Elem.first);
 
   return State;
 }
@@ -133,7 +167,7 @@
 }
 
 ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
-  return removeDead(State, State->get<DynamicCastMap>(), SR);
+  return removeDead(State, State->get<FailedCastMap>(), SR);
 }
 
 static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State,
@@ -154,7 +188,7 @@
     const DynamicTypeInfo &DTI = I->second;
     Indent(Out, Space, IsDot)
         << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
-    if (!DTI.isValid()) {
+    if (DTI.getType().isNull()) {
       Out << "null";
     } else {
       Out << '\"' << DTI.getType()->getPointeeType().getAsString()
@@ -175,9 +209,9 @@
 static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
                                   const char *NL, unsigned int Space,
                                   bool IsDot) {
-  Indent(Out, Space, IsDot) << "\"dynamic_casts\": ";
+  Indent(Out, Space, IsDot) << "\"failed_casts\": ";
 
-  const DynamicCastMapTy &Map = State->get<DynamicCastMap>();
+  const FailedCastMapTy &Map = State->get<FailedCastMap>();
   if (Map.isEmpty()) {
     Out << "null," << NL;
     return;
@@ -185,7 +219,7 @@
 
   ++Space;
   Out << '[' << NL;
-  for (DynamicCastMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
+  for (FailedCastMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
     const MemRegion *MR = I->first;
     const CastSet &Set = I->second;
 
@@ -195,16 +229,14 @@
     } else {
       ++Space;
       Out << '[' << NL;
+      Indent(Out, Space, IsDot);
       for (CastSet::iterator SI = Set.begin(); SI != Set.end(); ++SI) {
-        Indent(Out, Space, IsDot)
-            << "{ \"from\": \"" << SI->from().getAsString() << "\", \"to\": \""
-            << SI->to().getAsString() << "\", \"kind\": \""
-            << (SI->succeeds() ? "success" : "fail") << "\" }";
+        Out << '\"' << SI->getType().getAsString() << '\"';
 
         if (std::next(SI) != Set.end())
-          Out << ',';
-        Out << NL;
+          Out << ", ";
       }
+      Out << NL;
       --Space;
       Indent(Out, Space, IsDot) << ']';
     }
Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -735,12 +735,12 @@
     return {};
 
   // Do we know anything about the type of 'this'?
-  DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R);
-  if (!DynType.isValid())
+  const DynamicTypeInfo *DynType = getDynamicTypeInfo(getState(), R);
+  if (!DynType)
     return {};
 
   // Is the type a C++ class? (This is mostly a defensive check.)
-  QualType RegionType = DynType.getType()->getPointeeType();
+  QualType RegionType = DynType->getType()->getPointeeType();
   assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer.");
 
   const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl();
@@ -769,7 +769,7 @@
   // Does the decl that we found have an implementation?
   const FunctionDecl *Definition;
   if (!Result->hasBody(Definition)) {
-    if (!DynType.canBeASubClass())
+    if (!DynType->canBeASubClass())
       return AnyFunctionCall::getRuntimeDefinition();
     return {};
   }
@@ -777,7 +777,7 @@
   // We found a definition. If we're not sure that this devirtualization is
   // actually what will happen at runtime, make sure to provide the region so
   // that ExprEngine can decide what to do with it.
-  if (DynType.canBeASubClass())
+  if (DynType->canBeASubClass())
     return RuntimeDefinition(Definition, R->StripCasts());
   return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr);
 }
@@ -1206,15 +1206,15 @@
       if (!Receiver)
         return {};
 
-      DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver);
-      if (!DTI.isValid()) {
+      const DynamicTypeInfo *DTI = getDynamicTypeInfo(getState(), Receiver);
+      if (!DTI) {
         assert(isa<AllocaRegion>(Receiver) &&
                "Unhandled untyped region class!");
         return {};
       }
 
-      QualType DynType = DTI.getType();
-      CanBeSubClassed = DTI.canBeASubClass();
+      QualType DynType = DTI->getType();
+      CanBeSubClassed = DTI->canBeASubClass();
       ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType.getCanonicalType());
 
       if (ReceiverT && CanBeSubClassed)
Index: clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -1909,10 +1909,10 @@
 const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State,
                                       const MemRegion *Reg) {
   auto TI = getDynamicTypeInfo(State, Reg);
-  if (!TI.isValid())
+  if (!TI)
     return nullptr;
 
-  auto Type = TI.getType();
+  auto Type = TI->getType();
   if (const auto *RefT = Type->getAs<ReferenceType>()) {
     Type = RefT->getPointeeType();
   }
Index: clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -224,7 +224,7 @@
         const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
         if (!RecReg)
           return;
-        DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg);
+        const DynamicTypeInfo *RecDynType = getDynamicTypeInfo(State, RecReg);
         C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType));
         break;
       }
@@ -351,10 +351,15 @@
       CastE->getType()->getAs<ObjCObjectPointerType>();
   if (!NewTy)
     return nullptr;
-  QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType();
+
+  QualType OldDTy;
+  if (const DynamicTypeInfo *DTI = getDynamicTypeInfo(C.getState(), ToR))
+    OldDTy = DTI->getType();
+
   if (OldDTy.isNull()) {
     return NewTy;
   }
+
   const ObjCObjectPointerType *OldTy =
     OldDTy->getAs<ObjCObjectPointerType>();
   if (!OldTy)
@@ -875,7 +880,7 @@
   // When there is an entry available for the return symbol in DynamicTypeMap,
   // the call was inlined, and the information in the DynamicTypeMap is should
   // be precise.
-  if (RetRegion && !getRawDynamicTypeInfo(State, RetRegion)) {
+  if (RetRegion && !getStoredDynamicTypeInfo(State, RetRegion)) {
     // TODO: we have duplicated information in DynamicTypeMap and
     // MostSpecializedTypeArgsMap. We should only store anything in the later if
     // the stored data differs from the one stored in the former.
Index: clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
@@ -93,13 +93,12 @@
   ProgramStateRef State = N->getState();
   ProgramStateRef StatePrev = N->getFirstPred()->getState();
 
-  DynamicTypeInfo TrackedType = getDynamicTypeInfo(State, Reg);
-  DynamicTypeInfo TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg);
-  if (!TrackedType.isValid())
+  const DynamicTypeInfo *TrackedType = getDynamicTypeInfo(State, Reg);
+  const DynamicTypeInfo *TrackedTypePrev = getDynamicTypeInfo(StatePrev, Reg);
+  if (!TrackedType)
     return nullptr;
 
-  if (TrackedTypePrev.isValid() &&
-      TrackedTypePrev.getType() == TrackedType.getType())
+  if (TrackedTypePrev && TrackedTypePrev->getType() == TrackedType->getType())
     return nullptr;
 
   // Retrieve the associated statement.
@@ -112,7 +111,7 @@
   SmallString<256> Buf;
   llvm::raw_svector_ostream OS(Buf);
   OS << "Type '";
-  QualType::print(TrackedType.getType().getTypePtr(), Qualifiers(), OS,
+  QualType::print(TrackedType->getType().getTypePtr(), Qualifiers(), OS,
                   LangOpts, llvm::Twine());
   OS << "' is inferred from ";
 
@@ -163,12 +162,11 @@
     return;
 
   ProgramStateRef State = C.getState();
-  DynamicTypeInfo DynTypeInfo = getDynamicTypeInfo(State, Region);
-
-  if (!DynTypeInfo.isValid())
+  const DynamicTypeInfo *DynTypeInfo = getDynamicTypeInfo(State, Region);
+  if (!DynTypeInfo)
     return;
 
-  QualType DynType = DynTypeInfo.getType();
+  QualType DynType = DynTypeInfo->getType();
   QualType StaticType = CE->getType();
 
   const auto *DynObjCType = DynType->getAs<ObjCObjectPointerType>();
@@ -193,7 +191,7 @@
   if (ASTCtxt.canAssignObjCInterfaces(StaticObjCType, DynObjCType))
     return;
 
-  if (DynTypeInfo.canBeASubClass() &&
+  if (DynTypeInfo->canBeASubClass() &&
       ASTCtxt.canAssignObjCInterfaces(DynObjCType, StaticObjCType))
     return;
 
Index: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -8,12 +8,6 @@
 //
 //  This defines CastValueChecker which models casts of custom RTTIs.
 //
-// TODO list:
-// - It only allows one succesful cast between two types however in the wild
-//   the object could be casted to multiple types.
-// - It needs to check the most likely type information from the dynamic type
-//   map to increase precision of dynamic casting.
-//
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/DeclTemplate.h"
@@ -92,21 +86,103 @@
 };
 } // namespace
 
-static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
-                             bool CastSucceeds) {
-  if (!CastInfo)
+// See whether the record of type \p X is equal to the record of type \p Y or   
+// one record is derived from the other record.
+static bool isOneEqualOrDerivedFromOther(QualType X, QualType Y) {
+  if (X->getPointeeCXXRecordDecl() == Y->getPointeeCXXRecordDecl())
+    return true;
+
+  return isDerivedFrom(X, Y) || isDerivedFrom(Y, X);
+}
+
+// Dynamic type: Denote 'r' the 'MemoryRegion' which we try to cast. We store
+//   the most derived record type information in the 'DynamicTypeMap' for the
+//   given 'r'. We store the record types which the given 'r' cannot be casted
+//   to in 'FailedCastMap'. Every 'MemoryRegion' is typeless from the checker's
+//   point of view, because it waits for a cast expression to denote the object
+//   with an appropriate type.
+//   Denote 'S(r)' a 'MemoryRegion' 'r' entry in 'DynamicTypeMap', and
+//   denote 'F(r)' a 'MemoryRegion' 'r' entry in 'FailedCastMap'.
+//
+// Record: For the given 'MemoryRegion' 'r' we obtain the records from the AST
+//   using the cast expression's and the object's static types and also the
+//   dynamically known types using 'S(r)' and 'F(r)'.
+//
+// Inheritance: for two given records 'X' and 'Y' let us call 'X' inherits from
+//   'Y' if there exists at least one directed path from 'X' to 'Y'.
+//   Denote it by 'X -> Y'.
+//
+// Related records: for two given records 'X' and 'Y' let us call them related
+//   if either X = Y, or there exists at least one directed path either from
+//   'X' to 'Y' or from 'Y' to 'X' in the inheritance.
+//   Denote it by 'X <-> Y'. ('X <-> Y' <=> 'X -> Y' ∧ 'X <- Y'.)
+//
+// Cast: for two given related records 'X' and 'Y' (X <-> Y) we define two
+//   types of casts, the downcast: 'X -> Y', and the upcast: 'X <- Y'.
+//
+// An 'X -> Y' downcast/upcast succeeds for an 'r' 'MemoryRegion' iff
+// - 'X <-> Y' and,
+// - 'Y' ∉ 'F(r)' and:
+//   - If ∄S(r): it succeeds as a first entry.
+//   - If ∃S(r): 'S(r) <-> Y'.
+//
+// Here the known static types are \p CastFromTy and \p CastToTy. The 'S(r)'
+// entry is \p SucceededCastInfo and the 'F(r)' entry is \p FailedCastInfo.
+static bool isSuccededCast(const DynamicTypeInfo *SucceededCastInfo,
+                           const DynamicTypeInfo *FailedCastInfo,
+                           QualType CastFromTy, QualType CastToTy) {
+  if (FailedCastInfo || !isOneEqualOrDerivedFromOther(CastFromTy, CastToTy))
     return false;
 
-  return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
+  if (!SucceededCastInfo)
+    return true;
+
+  return isOneEqualOrDerivedFromOther(SucceededCastInfo->getType(), CastToTy);
 }
 
-static const NoteTag *getNoteTag(CheckerContext &C,
-                                 const DynamicCastInfo *CastInfo,
-                                 QualType CastToTy, const Expr *Object,
-                                 bool CastSucceeds, bool IsKnownCast) {
+namespace {
+struct CastContext {
+  CastContext(ProgramStateRef State, const MemRegion *MR, QualType CastFromTy,
+              QualType CastToTy, bool Assumption, bool IsCheckedCast) {
+    const DynamicTypeInfo *SucceededCastInfo =
+        getStoredDynamicTypeInfo(State, MR);
+
+    const DynamicTypeInfo *FailedCastInfo =
+        getFailedCastInfo(State, MR, CastToTy);
+
+    // We assume that every checked cast succeeds.
+    bool IsAlwaysSucceeds =
+        IsCheckedCast || CastFromTy->getPointeeCXXRecordDecl() ==
+                             CastToTy->getPointeeCXXRecordDecl();
+
+    CastSucceeds =
+        IsAlwaysSucceeds ||
+        (Assumption && isSuccededCast(SucceededCastInfo, FailedCastInfo,
+                                      CastFromTy, CastToTy));
+
+    IsKnownCast = IsAlwaysSucceeds || SucceededCastInfo ||
+                  (!CastSucceeds && FailedCastInfo);
+
+    CastInfo = CastSucceeds ? SucceededCastInfo : FailedCastInfo;
+  }
+
+  bool IsKnownCast, CastSucceeds;
+  const DynamicTypeInfo *CastInfo;
+};
+} // namespace
+
+constexpr llvm::StringLiteral Vowels = "aeiou";
+
+static const NoteTag *getNoteTag(CheckerContext &C, const Expr *Object,
+                                 QualType CastToTy, CastContext &CastCtx) {
+  QualType KnownCastToTy;
+  if (CastCtx.CastInfo)
+    KnownCastToTy = CastCtx.CastInfo->getType();
+
   std::string CastToName =
-      CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
-               : CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
+      CastCtx.CastInfo && CastCtx.IsKnownCast
+          ? KnownCastToTy->getPointeeCXXRecordDecl()->getNameAsString()
+          : CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
   Object = Object->IgnoreParenImpCasts();
 
   return C.getNoteTag(
@@ -114,24 +190,25 @@
         SmallString<128> Msg;
         llvm::raw_svector_ostream Out(Msg);
 
-        if (!IsKnownCast)
+        if (!CastCtx.IsKnownCast)
           Out << "Assuming ";
 
         if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
           Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
         } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
-          Out << (IsKnownCast ? "Field '" : "field '")
+          Out << (CastCtx.IsKnownCast ? "Field '" : "field '")
               << ME->getMemberDecl()->getNameAsString() << '\'';
         } else {
-          Out << (IsKnownCast ? "The object" : "the object");
+          Out << (CastCtx.IsKnownCast ? "The object" : "the object");
         }
 
-        Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
-            << '\'';
+        Out << ' ' << (CastCtx.CastSucceeds ? "is " : "is not ")
+            << (Vowels.contains_lower(CastToName[0]) ? "an" : "a") << " '"
+            << CastToName << '\'';
 
         return Out.str();
       },
-      /*IsPrunable=*/true);
+      /*IsPrunable=*/!CastCtx.CastSucceeds);
 }
 
 //===----------------------------------------------------------------------===//
@@ -157,8 +234,10 @@
                               bool IsNonNullReturn,
                               bool IsCheckedCast = false) {
   ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
-  if (!State)
+  if (!State) {
+    C.generateSink(C.getState(), C.getPredecessor());
     return;
+  }
 
   const Expr *Object;
   QualType CastFromTy;
@@ -182,35 +261,19 @@
   }
 
   const MemRegion *MR = DV.getAsRegion();
-  const DynamicCastInfo *CastInfo =
-      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
-
-  // We assume that every checked cast succeeds.
-  bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
-  if (!CastSucceeds) {
-    if (CastInfo)
-      CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
-    else
-      CastSucceeds = IsNonNullReturn;
-  }
+  CastContext CastCtx(State, MR, CastFromTy, CastToTy,
+                      /*Assumption=*/IsNonNullReturn, IsCheckedCast);
 
-  // Check for infeasible casts.
-  if (isInfeasibleCast(CastInfo, CastSucceeds)) {
-    C.generateSink(State, C.getPredecessor());
-    return;
-  }
+  State = setDynamicTypeAndCastInfo(State, MR, CastToTy, CastCtx.CastInfo,
+                                    CastCtx.CastSucceeds);
 
-  // Store the type and the cast information.
-  bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
-  if (!IsKnownCast || IsCheckedCast)
-    State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
-                                      CastSucceeds);
+  SVal V = CastCtx.CastSucceeds
+               ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
+               : C.getSValBuilder().makeNull();
 
-  SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
-                        : C.getSValBuilder().makeNull();
   C.addTransition(
       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
-      getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
+      getNoteTag(C, Object, CastToTy, CastCtx));
 }
 
 static void addInstanceOfTransition(const CallEvent &Call,
@@ -220,6 +283,7 @@
   const FunctionDecl *FD = Call.getDecl()->getAsFunction();
   QualType CastFromTy = Call.parameters()[0]->getType();
   QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
+
   if (CastFromTy->isPointerType())
     CastToTy = C.getASTContext().getPointerType(CastToTy);
   else if (CastFromTy->isReferenceType())
@@ -228,31 +292,16 @@
     return;
 
   const MemRegion *MR = DV.getAsRegion();
-  const DynamicCastInfo *CastInfo =
-      getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
-
-  bool CastSucceeds;
-  if (CastInfo)
-    CastSucceeds = IsInstanceOf && CastInfo->succeeds();
-  else
-    CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
-
-  if (isInfeasibleCast(CastInfo, CastSucceeds)) {
-    C.generateSink(State, C.getPredecessor());
-    return;
-  }
+  CastContext CastCtx(State, MR, CastFromTy, CastToTy,
+                      /*Assumption=*/IsInstanceOf, /*IsCheckedCast=*/false);
 
-  // Store the type and the cast information.
-  bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
-  if (!IsKnownCast)
-    State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
-                                      IsInstanceOf);
+  State = setDynamicTypeAndCastInfo(State, MR, CastToTy, CastCtx.CastInfo,
+                                    CastCtx.CastSucceeds);
 
   C.addTransition(
       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
-                      C.getSValBuilder().makeTruthVal(CastSucceeds)),
-      getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
-                 IsKnownCast));
+                      C.getSValBuilder().makeTruthVal(CastCtx.CastSucceeds)),
+      getNoteTag(C, Call.getArgExpr(0), CastToTy, CastCtx));
 }
 
 //===----------------------------------------------------------------------===//
@@ -398,10 +447,10 @@
     // We only model casts from pointers to pointers or from references
     // to references. Other casts are most likely specialized and we
     // cannot model them.
-    QualType ParamT = Call.parameters()[0]->getType();
-    QualType ResultT = Call.getResultType();
-    if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
-        !(ParamT->isReferenceType() && ResultT->isReferenceType()))
+    QualType ParamTy = Call.parameters()[0]->getType();
+    QualType ResultTy = Call.getResultType();
+    if (!(ParamTy->isPointerType() && ResultTy->isPointerType()) &&
+        !(ParamTy->isReferenceType() && ResultTy->isReferenceType()))
       return false;
 
     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -18,32 +18,30 @@
 /// of a region in a given state along the analysis path.
 class DynamicTypeInfo {
 public:
-  DynamicTypeInfo() : DynTy(QualType()) {}
+  DynamicTypeInfo() : Ty(QualType()) {}
 
-  DynamicTypeInfo(QualType Ty, bool CanBeSub = true)
-      : DynTy(Ty), CanBeASubClass(CanBeSub) {}
+  DynamicTypeInfo(QualType Ty, bool CanBeASubClass = true)
+      : Ty(Ty), CanBeASubClass(CanBeASubClass) {}
 
   /// Returns false if the type information is precise (the type 'DynTy' is
   /// the only type in the lattice), true otherwise.
   bool canBeASubClass() const { return CanBeASubClass; }
 
-  /// Returns true if the dynamic type info is available.
-  bool isValid() const { return !DynTy.isNull(); }
-
   /// Returns the currently inferred upper bound on the runtime type.
-  QualType getType() const { return DynTy; }
+  QualType getType() const { return Ty; }
 
   bool operator==(const DynamicTypeInfo &RHS) const {
-    return DynTy == RHS.DynTy && CanBeASubClass == RHS.CanBeASubClass;
+    return Ty == RHS.Ty && CanBeASubClass == RHS.CanBeASubClass;
   }
+  bool operator<(const DynamicTypeInfo &RHS) const { return Ty < RHS.Ty; }
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
-    ID.Add(DynTy);
+    ID.Add(Ty);
     ID.AddBoolean(CanBeASubClass);
   }
 
 private:
-  QualType DynTy;
+  QualType Ty;
   bool CanBeASubClass;
 };
 
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
@@ -16,7 +16,6 @@
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPE_H
 
 #include "clang/AST/Type.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -29,33 +28,40 @@
 namespace clang {
 namespace ento {
 
+/// See whether the record of type \p X is derived from the record of type \p Y.
+bool isDerivedFrom(QualType X, QualType Y);
+
 /// Get dynamic type information for the region \p MR.
-DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR);
+const DynamicTypeInfo *getDynamicTypeInfo(ProgramStateRef State,
+                                          const MemRegion *MR);
 
-/// Get raw dynamic type information for the region \p MR.
-const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
-                                             const MemRegion *MR);
+/// Get the stored dynamic type information for the region \p MR.
+const DynamicTypeInfo *getStoredDynamicTypeInfo(ProgramStateRef State,
+                                                const MemRegion *MR);
 
-/// Get dynamic cast information from \p CastFromTy to \p CastToTy of \p MR.
-const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
-                                          const MemRegion *MR,
-                                          QualType CastFromTy,
-                                          QualType CastToTy);
+/// Get dynamic type information of the failed cast for the region \p MR.
+/// The cast failed whether the current casting to \p CastToTy has a record type
+/// which derives from a previously stored cast's record type on \p MR.
+const DynamicTypeInfo *getFailedCastInfo(ProgramStateRef State,
+                                         const MemRegion *MR,
+                                         QualType CastToTy);
 
 /// Set dynamic type information of the region; return the new state.
 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
-                                   DynamicTypeInfo NewTy);
+                                   const DynamicTypeInfo *NewTy);
 
 /// Set dynamic type information of the region; return the new state.
 ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
                                    QualType NewTy, bool CanBeSubClassed = true);
 
 /// Set dynamic type and cast information of the region; return the new state.
+/// It stores the largest set what is the record of the given type \p CastToTy
+/// cannot be, and what is the most-derived class which the record could be.
 ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
                                           const MemRegion *MR,
-                                          QualType CastFromTy,
                                           QualType CastToTy,
-                                          bool IsCastSucceeds);
+                                          const DynamicTypeInfo *CastInfo,
+                                          bool CastSucceeds);
 
 /// Removes the dead type informations from \p State.
 ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR);
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//===- DynamicCastInfo.h - Runtime cast information -------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
-#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
-
-#include "clang/AST/Type.h"
-
-namespace clang {
-namespace ento {
-
-class DynamicCastInfo {
-public:
-  enum CastResult { Success, Failure };
-
-  DynamicCastInfo(QualType from, QualType to, CastResult resultKind)
-      : From(from), To(to), ResultKind(resultKind) {}
-
-  QualType from() const { return From; }
-  QualType to() const { return To; }
-
-  bool equals(QualType from, QualType to) const {
-    return From == from && To == to;
-  }
-
-  bool succeeds() const { return ResultKind == CastResult::Success; }
-  bool fails() const { return ResultKind == CastResult::Failure; }
-
-  bool operator==(const DynamicCastInfo &RHS) const {
-    return From == RHS.From && To == RHS.To;
-  }
-  bool operator<(const DynamicCastInfo &RHS) const {
-    return From < RHS.From && To < RHS.To;
-  }
-
-  void Profile(llvm::FoldingSetNodeID &ID) const {
-    ID.Add(From);
-    ID.Add(To);
-    ID.AddInteger(ResultKind);
-  }
-
-private:
-  QualType From, To;
-  CastResult ResultKind;
-};
-
-} // namespace ento
-} // namespace clang
-
-#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to