[clang] [analyzer][NFC] Rework SVal kind representation (PR #71039)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 2 02:28:29 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balazs Benics (steakhal)

<details>
<summary>Changes</summary>

The goal of this patch is to refine how the `SVal` base and sub-kinds are represented by forming one unified enum describing the possible SVals. This means that the `unsigned SVal::Kind` and the attached bit-packing semantics would be replaced by a single unified enum. This is more conventional and leads to a better debugging experience by default. This eases the need of using debug pretty-printers, or the use of runtime functions doing the printing for us like we do today by calling `Val.dump()` whenever we inspect the values.

Previously, the first 2 bits of the `unsigned SVal::Kind` discriminated the following quartet: `UndefinedVal`, `UnknownVal`, `Loc`, or `NonLoc`. The rest of the upper bits represented the sub-kind, where the value represented the index among only the `Loc`s or `NonLoc`s, effectively attaching 2 meanings of the upper bits depending on the base-kind. We don't need to pack these bits, as we have plenty even if we would use just a plan-old `unsigned char`.

Consequently, in this patch, I propose to lay out all the (non-abstract) `SVal` kinds into a single enum, along with some metadata (`BEGIN_Loc`, `END_Loc`, `BEGIN_NonLoc`, `END_NonLoc`) artificial enum values, similar how we do with the `MemRegions`.

Note that in the unified `SVal::Kind` enum, to differentiate `nonloc::ConcreteInt` from `loc::ConcreteInt`, I had to prefix them with `Loc` and `NonLoc` to resolve this ambiguity.
This should not surface in general, because I'm replacing the `nonloc::Kind` enum items with `inline constexpr` global constants to mimic the original behavior - and offer nicer spelling to these enum values.

Some `SVal` constructors were not marked explicit, which I now mark as such to follow best practices, and marked others as `/*implicit*/` to clarify the intent.
During refactoring, I also found at least one function not marked `LLVM_ATTRIBUTE_RETURNS_NONNULL`, so I did that.

The `TypeRetrievingVisitor` visitor had some accidental dead code, namely: `VisitNonLocConcreteInt` and `VisitLocConcreteInt`.

Previously, the `SValVisitor` expected visit handlers of `VisitNonLocXXXXX(nonloc::XXXXX)` and `VisitLocXXXXX(loc::XXXXX)`, where I felt that envoding `NonLoc` and `Loc` in the name is not necessary as the type of the parameter would select the right overload anyways, so I simplified the naming of those visit functions.

The rest of the diff is a lot of times just formatting, because `getKind()` by nature, frequently appears in switches, which means that the whole switch gets automatically reformatted. I could probably undo the formatting, but I didn't want to deviate from the rule unless explicitly requested.

---

Patch is 40.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71039.diff


9 Files Affected:

- (modified) clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h (+5-5) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h (+25-32) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def (+18-20) 
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (+77-148) 
- (modified) clang/lib/StaticAnalyzer/Core/SValBuilder.cpp (+14-14) 
- (modified) clang/lib/StaticAnalyzer/Core/SVals.cpp (+42-45) 
- (modified) clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp (+2-2) 
- (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+36-37) 
- (modified) clang/lib/StaticAnalyzer/Core/Store.cpp (+1-1) 


``````````diff
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 3ae28c1dba3eb5a..43a70f596a4da28 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -65,7 +65,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
     return "undefined value";
   }
 
-  std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
+  std::string VisitMemRegionVal(loc::MemRegionVal V) {
     const MemRegion *R = V.getRegion();
     // Avoid the weird "pointer to pointee of ...".
     if (auto SR = dyn_cast<SymbolicRegion>(R)) {
@@ -76,7 +76,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
     return "pointer to " + Visit(R);
   }
 
-  std::string VisitLocConcreteInt(loc::ConcreteInt V) {
+  std::string VisitConcreteInt(loc::ConcreteInt V) {
     const llvm::APSInt &I = V.getValue();
     std::string Str;
     llvm::raw_string_ostream OS(Str);
@@ -84,11 +84,11 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
     return Str;
   }
 
-  std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+  std::string VisitSymbolVal(nonloc::SymbolVal V) {
     return Visit(V.getSymbol());
   }
 
-  std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
+  std::string VisitConcreteInt(nonloc::ConcreteInt V) {
     const llvm::APSInt &I = V.getValue();
     std::string Str;
     llvm::raw_string_ostream OS(Str);
@@ -97,7 +97,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
     return Str;
   }
 
-  std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
+  std::string VisitLazyCompoundVal(nonloc::LazyCompoundVal V) {
     return "lazily frozen compound value of " + Visit(V.getRegion());
   }
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
index fc83e26183b3e7d..f7bb37f6591671f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
@@ -14,9 +14,9 @@
 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
 
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 
 namespace clang {
 
@@ -25,49 +25,42 @@ namespace ento {
 /// SValVisitor - this class implements a simple visitor for SVal
 /// subclasses.
 template <typename ImplClass, typename RetTy = void> class SValVisitor {
-public:
-
-#define DISPATCH(NAME, CLASS) \
-  return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
+  ImplClass &derived() { return *static_cast<ImplClass *>(this); }
 
+public:
   RetTy Visit(SVal V) {
     // Dispatch to VisitFooVal for each FooVal.
-    // Take namespaces (loc:: and nonloc::) into account.
-    switch (V.getBaseKind()) {
-#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-    case SVal::LocKind:
-      switch (V.getSubKind()) {
-#define LOC_SVAL(Id, Parent) \
-      case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
+    switch (V.getKind()) {
+#define BASIC_SVAL(Id, Parent)                                                 \
+  case SVal::Id##Kind:                                                         \
+    return derived().Visit##Id(V.castAs<Id>());
+#define LOC_SVAL(Id, Parent)                                                   \
+  case SVal::Loc##Id##Kind:                                                    \
+    return derived().Visit##Id(V.castAs<loc::Id>());
+#define NONLOC_SVAL(Id, Parent)                                                \
+  case SVal::NonLoc##Id##Kind:                                                 \
+    return derived().Visit##Id(V.castAs<nonloc::Id>());
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-      }
-      llvm_unreachable("Unknown Loc sub-kind!");
-    case SVal::NonLocKind:
-      switch (V.getSubKind()) {
-#define NONLOC_SVAL(Id, Parent) \
-      case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-      }
-      llvm_unreachable("Unknown NonLoc sub-kind!");
     }
     llvm_unreachable("Unknown SVal kind!");
   }
 
-#define BASIC_SVAL(Id, Parent) \
-  RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
-#define ABSTRACT_SVAL(Id, Parent) \
-  BASIC_SVAL(Id, Parent)
-#define LOC_SVAL(Id, Parent) \
-  RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
-#define NONLOC_SVAL(Id, Parent) \
-  RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
+  // Dispatch to the more generic handler as a default implementation.
+#define BASIC_SVAL(Id, Parent)                                                 \
+  RetTy Visit##Id(Id V) { return derived().Visit##Parent(V.castAs<Id>()); }
+#define ABSTRACT_SVAL(Id, Parent) BASIC_SVAL(Id, Parent)
+#define LOC_SVAL(Id, Parent)                                                   \
+  RetTy Visit##Id(loc::Id V) {                                                 \
+    return derived().Visit##Parent(V.castAs<Parent>());                        \
+  }
+#define NONLOC_SVAL(Id, Parent)                                                \
+  RetTy Visit##Id(nonloc::Id V) {                                              \
+    return derived().Visit##Parent(V.castAs<Parent>());                        \
+  }
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
 
   // Base case, ignore it. :)
   RetTy VisitSVal(SVal V) { return RetTy(); }
-
-#undef DISPATCH
 };
 
 /// SymExprVisitor - this class implements a simple visitor for SymExpr
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
index eb05de6d9933342..36d2425d155a929 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
@@ -6,28 +6,24 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// The list of symbolic values (SVal kinds and sub-kinds) used in the Static
-// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is
+// The list of symbolic values (SVal kinds) used in the Static Analyzer.
+// The distinction between `loc::` and `nonloc::` SVal namespaces is
 // currently hardcoded, because it is too peculiar and explicit to be handled
 // uniformly. In order to use this information, users of this file must define
 // one or more of the following macros:
 //
-// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are
-// neither in loc:: nor in nonloc:: namespace; these classes occupy
-// their own base kind IdKind.
+// BASIC_SVAL(Id, Parent) - for specific SVal kinds, which are
+// neither in `loc::` nor in `nonloc::` namespace.
 //
 // ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are
-// neither in loc:: nor in nonloc:: namespace,
+// neither in `loc::` nor in `nonloc::` namespace,
 //
-// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also
-// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind
-// identifier IdKind, much like BASIC_SVALs.
+// LOC_SVAL(Id, Parent) - for values in `loc::` namespace.
 //
-// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind
-// loc::IdKind.
+// NONLOC_SVAL(Id, Parent) - for values in `nonloc::` namespace.
 //
-// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a
-// sub-kind nonloc::IdKind.
+// SVAL_RANGE(Id, First, Last) - for defining range of subtypes of
+// the abstract class `Id`.
 //
 //===----------------------------------------------------------------------===//
 
@@ -39,10 +35,6 @@
 #define ABSTRACT_SVAL(Id, Parent)
 #endif
 
-#ifndef ABSTRACT_SVAL_WITH_KIND
-#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent)
-#endif
-
 #ifndef LOC_SVAL
 #define LOC_SVAL(Id, Parent)
 #endif
@@ -51,24 +43,30 @@
 #define NONLOC_SVAL(Id, Parent)
 #endif
 
+#ifndef SVAL_RANGE
+#define SVAL_RANGE(Id, First, Last)
+#endif
+
 BASIC_SVAL(UndefinedVal, SVal)
 ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
   BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal)
   ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal)
-    ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal)
+    ABSTRACT_SVAL(Loc, DefinedSVal)
       LOC_SVAL(ConcreteInt, Loc)
       LOC_SVAL(GotoLabel, Loc)
       LOC_SVAL(MemRegionVal, Loc)
-    ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal)
+      SVAL_RANGE(Loc, ConcreteInt, MemRegionVal)
+    ABSTRACT_SVAL(NonLoc, DefinedSVal)
       NONLOC_SVAL(CompoundVal, NonLoc)
       NONLOC_SVAL(ConcreteInt, NonLoc)
       NONLOC_SVAL(LazyCompoundVal, NonLoc)
       NONLOC_SVAL(LocAsInteger, NonLoc)
       NONLOC_SVAL(SymbolVal, NonLoc)
       NONLOC_SVAL(PointerToMember, NonLoc)
+      SVAL_RANGE(NonLoc, CompoundVal, PointerToMember)
 
+#undef SVAL_RANGE
 #undef NONLOC_SVAL
 #undef LOC_SVAL
-#undef ABSTRACT_SVAL_WITH_KIND
 #undef ABSTRACT_SVAL
 #undef BASIC_SVAL
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 00cce21151a7073..78239d4060c47d0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -18,6 +18,7 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/PointerUnion.h"
@@ -47,50 +48,30 @@ class PointerToMemberData;
 class SValBuilder;
 class TypedValueRegion;
 
-namespace nonloc {
-
-/// Sub-kinds for NonLoc values.
-enum Kind {
-#define NONLOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
-} // namespace nonloc
-
-namespace loc {
-
-/// Sub-kinds for Loc values.
-enum Kind {
-#define LOC_SVAL(Id, Parent) Id ## Kind,
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
-};
-
-} // namespace loc
-
 /// SVal - This represents a symbolic expression, which can be either
 ///  an L-value or an R-value.
 ///
 class SVal {
 public:
-  enum BaseKind {
-    // The enumerators must be representable using 2 bits.
-#define BASIC_SVAL(Id, Parent) Id ## Kind,
-#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
+  enum SValKind : unsigned char {
+#define BASIC_SVAL(Id, Parent) Id##Kind,
+#define LOC_SVAL(Id, Parent) Parent##Id##Kind,
+#define NONLOC_SVAL(Id, Parent) Parent##Id##Kind,
+#define SVAL_RANGE(Id, First, Last)                                            \
+  BEGIN_##Id = Id##First##Kind, END_##Id = Id##Last##Kind,
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
   };
-  enum { BaseBits = 2, BaseMask = 0b11 };
 
 protected:
   const void *Data = nullptr;
+  SValKind Kind = UndefinedValKind;
 
-  /// The lowest 2 bits are a BaseKind (0 -- 3).
-  ///  The higher bits are an unsigned "kind" value.
-  unsigned Kind = 0;
-
-  explicit SVal(const void *d, bool isLoc, unsigned ValKind)
-      : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+  explicit SVal(SValKind Kind, const void *Data = nullptr)
+      : Data(Data), Kind(Kind) {}
 
-  explicit SVal(BaseKind k, const void *D = nullptr) : Data(D), Kind(k) {}
+  template <typename T> const T *castDataAs() const {
+    return static_cast<const T *>(Data);
+  }
 
 public:
   explicit SVal() = default;
@@ -105,38 +86,25 @@ class SVal {
     return llvm::dyn_cast<T>(*this);
   }
 
-  unsigned getRawKind() const { return Kind; }
-  BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
-  unsigned getSubKind() const { return Kind >> BaseBits; }
+  SValKind getKind() const { return Kind; }
 
   // This method is required for using SVal in a FoldingSetNode.  It
   // extracts a unique signature for this SVal object.
   void Profile(llvm::FoldingSetNodeID &ID) const {
-    ID.AddInteger((unsigned) getRawKind());
+    ID.AddInteger((unsigned)getKind());
     ID.AddPointer(Data);
   }
 
-  bool operator==(SVal R) const {
-    return getRawKind() == R.getRawKind() && Data == R.Data;
-  }
-
+  bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
   bool operator!=(SVal R) const { return !(*this == R); }
 
-  bool isUnknown() const {
-    return getRawKind() == UnknownValKind;
-  }
+  bool isUnknown() const { return getKind() == UnknownValKind; }
 
-  bool isUndef() const {
-    return getRawKind() == UndefinedValKind;
-  }
+  bool isUndef() const { return getKind() == UndefinedValKind; }
 
-  bool isUnknownOrUndef() const {
-    return getRawKind() <= UnknownValKind;
-  }
+  bool isUnknownOrUndef() const { return isUnknown() || isUndef(); }
 
-  bool isValid() const {
-    return getRawKind() > UnknownValKind;
-  }
+  bool isValid() const { return !isUnknownOrUndef(); }
 
   bool isConstant() const;
 
@@ -207,10 +175,24 @@ inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
   return os;
 }
 
+namespace nonloc {
+/// Sub-kinds for NonLoc values.
+#define NONLOC_SVAL(Id, Parent)                                                \
+  inline constexpr auto Id##Kind = SVal::SValKind::NonLoc##Id##Kind;
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+} // namespace nonloc
+
+namespace loc {
+/// Sub-kinds for Loc values.
+#define LOC_SVAL(Id, Parent)                                                   \
+  inline constexpr auto Id##Kind = SVal::SValKind::Loc##Id##Kind;
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+} // namespace loc
+
 class UndefinedVal : public SVal {
 public:
   UndefinedVal() : SVal(UndefinedValKind) {}
-  static bool classof(SVal V) { return V.getBaseKind() == UndefinedValKind; }
+  static bool classof(SVal V) { return V.getKind() == UndefinedValKind; }
 };
 
 class DefinedOrUnknownSVal : public SVal {
@@ -223,16 +205,15 @@ class DefinedOrUnknownSVal : public SVal {
   static bool classof(SVal V) { return !V.isUndef(); }
 
 protected:
-  explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
-      : SVal(d, isLoc, ValKind) {}
-  explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {}
+  explicit DefinedOrUnknownSVal(SValKind Kind, const void *Data = nullptr)
+      : SVal(Kind, Data) {}
 };
 
 class UnknownVal : public DefinedOrUnknownSVal {
 public:
   explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
 
-  static bool classof(SVal V) { return V.getBaseKind() == UnknownValKind; }
+  static bool classof(SVal V) { return V.getKind() == UnknownValKind; }
 };
 
 class DefinedSVal : public DefinedOrUnknownSVal {
@@ -246,22 +227,21 @@ class DefinedSVal : public DefinedOrUnknownSVal {
   static bool classof(SVal V) { return !V.isUnknownOrUndef(); }
 
 protected:
-  explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
-      : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+  explicit DefinedSVal(SValKind Kind, const void *Data)
+      : DefinedOrUnknownSVal(Kind, Data) {}
 };
 
 /// Represents an SVal that is guaranteed to not be UnknownVal.
 class KnownSVal : public SVal {
 public:
-  KnownSVal(const DefinedSVal &V) : SVal(V) {}
-  KnownSVal(const UndefinedVal &V) : SVal(V) {}
+  /*implicit*/ KnownSVal(DefinedSVal V) : SVal(V) {}
+  /*implicit*/ KnownSVal(UndefinedVal V) : SVal(V) {}
   static bool classof(SVal V) { return !V.isUnknown(); }
 };
 
 class NonLoc : public DefinedSVal {
 protected:
-  explicit NonLoc(unsigned SubKind, const void *d)
-      : DefinedSVal(d, false, SubKind) {}
+  NonLoc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
 
 public:
   void dumpToStream(raw_ostream &Out) const;
@@ -271,13 +251,14 @@ class NonLoc : public DefinedSVal {
            T->isAnyComplexType() || T->isVectorType();
   }
 
-  static bool classof(SVal V) { return V.getBaseKind() == NonLocKind; }
+  static bool classof(SVal V) {
+    return BEGIN_NonLoc <= V.getKind() && V.getKind() <= END_NonLoc;
+  }
 };
 
 class Loc : public DefinedSVal {
 protected:
-  explicit Loc(unsigned SubKind, const void *D)
-      : DefinedSVal(const_cast<void *>(D), true, SubKind) {}
+  Loc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
 
 public:
   void dumpToStream(raw_ostream &Out) const;
@@ -287,7 +268,9 @@ class Loc : public DefinedSVal {
            T->isReferenceType() || T->isNullPtrType();
   }
 
-  static bool classof(SVal V) { return V.getBaseKind() == LocKind; }
+  static bool classof(SVal V) {
+    return BEGIN_Loc <= V.getKind() && V.getKind() <= END_Loc;
+  }
 };
 
 //==------------------------------------------------------------------------==//
@@ -300,9 +283,9 @@ namespace nonloc {
 class SymbolVal : public NonLoc {
 public:
   SymbolVal() = delete;
-  SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {
-    assert(sym);
-    assert(!Loc::isLocType(sym->getType()));
+  explicit SymbolVal(SymbolRef Sym) : NonLoc(SymbolValKind, Sym) {
+    assert(Sym);
+    assert(!Loc::isLocType(Sym->getType()));
   }
 
   LLVM_ATTRIBUTE_RETURNS_NONNULL
@@ -314,27 +297,17 @@ class SymbolVal : public NonLoc {
     return !isa<SymbolData>(getSymbol());
   }
 
-  static bool classof(SVal V) {
-    return V.getBaseKind() == NonLocKind && V.getSubKind() == SymbolValKind;
-  }
-
-  static bool classof(NonLoc V) { return V.getSubKind() == SymbolValKind; }
+  static bool classof(SVal V) { return V.getKind() == SymbolValKind; }
 };
 
 /// Value representing integer constant.
 class ConcreteInt : public NonLoc {
 public:
-  explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
-
-  const llvm::APSInt& getValue() const {
-    return *static_cast<const llvm::APSInt *>(Data);
-  }
+  explicit ConcreteInt(const llvm::APSInt &V) : NonLoc(ConcreteIntKind, &V) {}
 
-  static bool classof(SVal V) {
-    return V.getBaseKind() == NonLocKind && V.getSubKind() == ConcreteIntKind;
-  }
+  const llvm::APSInt &getValue() const { return *castDataAs<llvm::APSInt>(); }
 
-  static bool classof(NonLoc V) { return V.getSubKind() == ConcreteIntKind; }
+  static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; }
 };
 
 class LocAsInteger : public NonLoc {
@@ -344,29 +317,20 @@ class LocAsInteger : public NonLoc {
       : NonLoc(LocAsIntegerKind, &data) {
     // We do not need to represent loc::ConcreteInt as LocAsInteger,
     // as it'd collapse into a nonloc::ConcreteInt instead.
-    assert(data.first.getBaseKind() == LocKind &&
-           (data.first.getSubKind() == loc::MemRegionValKind ||
-            data.first.getSubKind() == loc::GotoLabelKind));
+    SValKind K = data.first.getKind();
+    assert(K == loc::MemRegionValKind || K == loc::GotoLabelKind);
   }
 
 public:
   Loc getLoc() const {
-    const std::pair<SVal, uintptr_t> *D =
-      static_cast<const std::pair<SVal, uintptr_t> *>(Data);
-    return D->first.castAs<Loc>();
+    return castDataAs<std::pair<SVal, uintptr_t>>()->first.castAs<Loc>();
   }
 
   unsigned getNumBits() const {
-    const std::pair<SVal, uintptr_t> *D =
-      static_cast<const std::pair<SVal, uintptr_t> *>(Data);
-    return D->second;
+    return castDataAs<std::pair<SVal, uintptr_t>>()->second;
   }
 
-  static bool classof(SVal V) {
-    return V.getBaseKind() == NonLocKind && V.getSubKind() == LocAsIntegerKind;
-  }
-
-  static bool classof(NonLoc V) { return V.getSubKind() == LocAsIntegerKind; }
+  static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; }
 };
 
 class CompoundVal : public NonLoc {
@@ -379,19 +343,14 @@ class CompoundVal : public NonLoc {
 public:
   LLVM_ATTRIBUTE_RETURNS_NONNULL
   const CompoundValData* getValue() const {
-    return static_cast<const CompoundValData *>(Data);
+    return castDataAs<CompoundValData>();
   }
 
   using iterator = llvm::ImmutableList<SVal>::iterator;
-
   iterator begin() const;
   iterator end() const;
 
-  static bool classof(SVal V) {
-    return V.getBaseKind() == NonLocKind ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/71039


More information about the cfe-commits mailing list