forked from OSchip/llvm-project
[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
This commit is contained in:
parent
6bf2791814
commit
de6ba9704d
|
@ -98,19 +98,12 @@ public:
|
||||||
|
|
||||||
/// Convert to the specified SVal type, asserting that this SVal is of
|
/// Convert to the specified SVal type, asserting that this SVal is of
|
||||||
/// the desired type.
|
/// the desired type.
|
||||||
template<typename T>
|
template <typename T> T castAs() const { return llvm::cast<T>(*this); }
|
||||||
T castAs() const {
|
|
||||||
assert(T::classof(*this));
|
|
||||||
return *static_cast<const T *>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert to the specified SVal type, returning None if this SVal is
|
/// Convert to the specified SVal type, returning None if this SVal is
|
||||||
/// not of the desired type.
|
/// not of the desired type.
|
||||||
template<typename T>
|
template <typename T> Optional<T> getAs() const {
|
||||||
Optional<T> getAs() const {
|
return llvm::dyn_cast<T>(*this);
|
||||||
if (!T::classof(*this))
|
|
||||||
return None;
|
|
||||||
return *static_cast<const T *>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getRawKind() const { return Kind; }
|
unsigned getRawKind() const { return Kind; }
|
||||||
|
@ -564,4 +557,28 @@ public:
|
||||||
} // namespace ento
|
} // namespace ento
|
||||||
} // namespace clang
|
} // 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
|
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
|
||||||
|
|
|
@ -446,7 +446,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
|
||||||
|
|
||||||
// FIXME: We really should allow ranges of valid theType values, and
|
// FIXME: We really should allow ranges of valid theType values, and
|
||||||
// bifurcate the state appropriately.
|
// bifurcate the state appropriately.
|
||||||
Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
|
Optional<nonloc::ConcreteInt> V = dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
|
||||||
if (!V)
|
if (!V)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -907,7 +907,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
|
||||||
|
|
||||||
// Go ahead and assume the value is non-nil.
|
// Go ahead and assume the value is non-nil.
|
||||||
SVal Val = State->getSVal(*ElementLoc);
|
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
|
/// Returns NULL state if the collection is known to contain elements
|
||||||
|
|
Loading…
Reference in New Issue