[clang] de6ba97 - [analyzer][Casting] Support isa, cast, dyn_cast of SVals

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 14 04:43:21 PDT 2022


Author: Balazs Benics
Date: 2022-06-14T13:43:04+02:00
New Revision: de6ba9704d0b4fa047a030b5bf369e425b937198

URL: https://github.com/llvm/llvm-project/commit/de6ba9704d0b4fa047a030b5bf369e425b937198
DIFF: https://github.com/llvm/llvm-project/commit/de6ba9704d0b4fa047a030b5bf369e425b937198.diff

LOG: [analyzer][Casting] Support isa, cast, dyn_cast of SVals

This change specializes the LLVM RTTI mechanism for SVals.
After this change, we can use the well-known `isa`, `cast`, `dyn_cast`.

Examples:

  // SVal V = ...;
  // Loc MyLoc = ...;

  bool IsInteresting = isa<loc::MemRegionVal, loc::GotoLabel>(MyLoc);
  auto MRV = cast<loc::MemRegionVal>(MyLoc);
  Optional<loc::MemRegionVal> MaybeMRV = dyn_cast<loc::MemRegionVal>(V)

The current `SVal::getAs` and `castAs` member functions are redundant at
this point, but I believe that they are still handy.

The member function version is terse and reads left-to-right, which IMO
is a great plus. However, we should probably add a variadic `isa` member
function version to have the same casting API in both cases.

Thanks for the extensive TMP help @bzcheeseman!

Reviewed By: bzcheeseman

Differential Revision: https://reviews.llvm.org/D125709

Added: 
    

Modified: 
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
    clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 7c5f23b6d466a..c3750b2320c89 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -98,19 +98,12 @@ class SVal {
 
   /// Convert to the specified SVal type, asserting that this SVal is of
   /// the desired type.
-  template<typename T>
-  T castAs() const {
-    assert(T::classof(*this));
-    return *static_cast<const T *>(this);
-  }
+  template <typename T> T castAs() const { return llvm::cast<T>(*this); }
 
   /// Convert to the specified SVal type, returning None if this SVal is
   /// not of the desired type.
-  template<typename T>
-  Optional<T> getAs() const {
-    if (!T::classof(*this))
-      return None;
-    return *static_cast<const T *>(this);
+  template <typename T> Optional<T> getAs() const {
+    return llvm::dyn_cast<T>(*this);
   }
 
   unsigned getRawKind() const { return Kind; }
@@ -564,4 +557,28 @@ class ConcreteInt : public Loc {
 } // namespace ento
 } // namespace clang
 
+namespace llvm {
+template <typename To, typename From>
+struct CastInfo<
+    To, From,
+    std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>
+    : public CastIsPossible<To, ::clang::ento::SVal> {
+  using Self = CastInfo<
+      To, From,
+      std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>;
+  static bool isPossible(const From &V) {
+    return To::classof(*static_cast<const ::clang::ento::SVal *>(&V));
+  }
+  static Optional<To> castFailed() { return Optional<To>{}; }
+  static To doCast(const From &f) {
+    return *static_cast<const To *>(cast<::clang::ento::SVal>(&f));
+  }
+  static Optional<To> doCastIfPossible(const From &f) {
+    if (!Self::isPossible(f))
+      return Self::castFailed();
+    return doCast(f);
+  }
+};
+} // namespace llvm
+
 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H

diff  --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 2c210fb6cdb97..b143ef93282f9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -446,7 +446,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
 
   // FIXME: We really should allow ranges of valid theType values, and
   //   bifurcate the state appropriately.
-  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
+  Optional<nonloc::ConcreteInt> V = dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
   if (!V)
     return;
 
@@ -907,7 +907,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
 
   // Go ahead and assume the value is non-nil.
   SVal Val = State->getSVal(*ElementLoc);
-  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
+  return State->assume(cast<DefinedOrUnknownSVal>(Val), true);
 }
 
 /// Returns NULL state if the collection is known to contain elements


        


More information about the cfe-commits mailing list