diff options
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h')
-rw-r--r-- | contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h | 443 |
1 files changed, 135 insertions, 308 deletions
diff --git a/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 6199c8d8d179..c60528b7685f 100644 --- a/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -18,14 +18,16 @@ #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/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLForwardCompat.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include <cassert> #include <cstdint> +#include <optional> #include <utility> //==------------------------------------------------------------------------==// @@ -35,13 +37,11 @@ namespace clang { class CXXBaseSpecifier; -class DeclaratorDecl; class FunctionDecl; class LabelDecl; namespace ento { -class BasicValueFactory; class CompoundValData; class LazyCompoundValData; class MemRegion; @@ -49,105 +49,63 @@ 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) Loc##Id##Kind, +#define NONLOC_SVAL(Id, Parent) NonLoc##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(SValKind Kind, const void *Data = nullptr) + : Data(Data), Kind(Kind) {} - explicit SVal(const void *d, bool isLoc, unsigned ValKind) - : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} - - 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; /// Convert to the specified SVal type, asserting that this SVal is of /// the desired type. - template<typename T> - T castAs() const { - assert(T::isKind(*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 + /// Convert to the specified SVal type, returning std::nullopt if this SVal is /// not of the desired type. - template<typename T> - Optional<T> getAs() const { - if (!T::isKind(*this)) - return None; - return *static_cast<const T *>(this); + template <typename T> std::optional<T> getAs() const { + 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.AddPointer(Data); + ID.AddInteger(llvm::to_underlying(getKind())); } - bool operator==(const 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 operator!=(const SVal &R) const { - return !(*this == R); - } + bool isUnknown() const { return getKind() == UnknownValKind; } - bool isUnknown() const { - return getRawKind() == UnknownValKind; - } + bool isUndef() const { return getKind() == UndefinedValKind; } - bool isUndef() const { - return getRawKind() == UndefinedValKind; - } + bool isUnknownOrUndef() const { return isUnknown() || isUndef(); } - bool isUnknownOrUndef() const { - return getRawKind() <= UnknownValKind; - } - - bool isValid() const { - return getRawKind() > UnknownValKind; - } + bool isValid() const { return !isUnknownOrUndef(); } bool isConstant() const; @@ -155,9 +113,6 @@ public: bool isZeroConstant() const; - /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; - bool hasConjuredSymbol() const; - /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. /// Otherwise return 0. @@ -182,6 +137,11 @@ public: /// should continue to the base regions if the region is not symbolic. SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; + /// If this SVal is loc::ConcreteInt or nonloc::ConcreteInt, + /// return a pointer to APSInt which is held in it. + /// Otherwise, return nullptr. + const llvm::APSInt *getAsInteger() const; + const MemRegion *getAsRegion() const; /// printJson - Pretty-prints in JSON format. @@ -190,16 +150,11 @@ public: void dumpToStream(raw_ostream &OS) const; void dump() const; - SymExpr::symbol_iterator symbol_begin() const { - const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true); - if (SE) - return SE->symbol_begin(); - else - return SymExpr::symbol_iterator(); - } - - SymExpr::symbol_iterator symbol_end() const { - return SymExpr::symbol_end(); + llvm::iterator_range<SymExpr::symbol_iterator> symbols() const { + if (const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true)) + return SE->symbols(); + SymExpr::symbol_iterator end{}; + return llvm::make_range(end, end); } /// Try to get a reasonable type for the given value. @@ -221,16 +176,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) {} - -private: - friend class SVal; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == UndefinedValKind; - } + static bool classof(SVal V) { return V.getKind() == UndefinedValKind; } }; class DefinedOrUnknownSVal : public SVal { @@ -240,30 +203,18 @@ public: bool isUndef() const = delete; bool isValid() const = delete; -protected: - DefinedOrUnknownSVal() = default; - explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) - : SVal(d, isLoc, ValKind) {} - explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {} - -private: - friend class SVal; + static bool classof(SVal V) { return !V.isUndef(); } - static bool isKind(const SVal& V) { - return !V.isUndef(); - } +protected: + explicit DefinedOrUnknownSVal(SValKind Kind, const void *Data = nullptr) + : SVal(Kind, Data) {} }; class UnknownVal : public DefinedOrUnknownSVal { public: explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {} -private: - friend class SVal; - - static bool isKind(const SVal &V) { - return V.getBaseKind() == UnknownValKind; - } + static bool classof(SVal V) { return V.getKind() == UnknownValKind; } }; class DefinedSVal : public DefinedOrUnknownSVal { @@ -274,39 +225,24 @@ public: bool isUnknownOrUndef() const = delete; bool isValid() const = delete; -protected: - DefinedSVal() = default; - explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) - : DefinedOrUnknownSVal(d, isLoc, ValKind) {} - -private: - friend class SVal; + static bool classof(SVal V) { return !V.isUnknownOrUndef(); } - static bool isKind(const SVal& V) { - return !V.isUnknownOrUndef(); - } +protected: + explicit DefinedSVal(SValKind Kind, const void *Data) + : DefinedOrUnknownSVal(Kind, Data) {} }; /// Represents an SVal that is guaranteed to not be UnknownVal. class KnownSVal : public SVal { - friend class SVal; - - KnownSVal() = default; - - static bool isKind(const SVal &V) { - return !V.isUnknown(); - } - 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: - NonLoc() = default; - 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; @@ -316,19 +252,14 @@ public: T->isAnyComplexType() || T->isVectorType(); } -private: - friend class SVal; - - static bool isKind(const 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: - Loc() = default; - 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; @@ -338,11 +269,8 @@ public: T->isReferenceType() || T->isNullPtrType(); } -private: - friend class SVal; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == LocKind; + static bool classof(SVal V) { + return BEGIN_Loc <= V.getKind() && V.getKind() <= END_Loc; } }; @@ -356,11 +284,12 @@ 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 SymbolRef getSymbol() const { return (const SymExpr *) Data; } @@ -369,49 +298,17 @@ public: return !isa<SymbolData>(getSymbol()); } -private: - friend class SVal; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && - V.getSubKind() == SymbolValKind; - } - - static bool isKind(const 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); - } - - // Transfer functions for binary/unary operations on ConcreteInts. - SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, - const ConcreteInt& R) const; - - ConcreteInt evalComplement(SValBuilder &svalBuilder) const; + explicit ConcreteInt(const llvm::APSInt &V) : NonLoc(ConcreteIntKind, &V) {} - ConcreteInt evalMinus(SValBuilder &svalBuilder) const; + const llvm::APSInt &getValue() const { return *castDataAs<llvm::APSInt>(); } -private: - friend class SVal; - - ConcreteInt() = default; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && - V.getSubKind() == ConcreteIntKind; - } - - static bool isKind(const NonLoc& V) { - return V.getSubKind() == ConcreteIntKind; - } + static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; } }; class LocAsInteger : public NonLoc { @@ -421,102 +318,63 @@ 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)); + [[maybe_unused]] 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>(); - } - - Loc getPersistentLoc() const { - const std::pair<SVal, uintptr_t> *D = - static_cast<const std::pair<SVal, uintptr_t> *>(Data); - const SVal& V = D->first; - return V.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; - } - -private: - friend class SVal; - - LocAsInteger() = default; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && - V.getSubKind() == LocAsIntegerKind; + return castDataAs<std::pair<SVal, uintptr_t>>()->second; } - static bool isKind(const NonLoc& V) { - return V.getSubKind() == LocAsIntegerKind; - } + static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; } }; class CompoundVal : public NonLoc { friend class ento::SValBuilder; - explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + explicit CompoundVal(const CompoundValData *D) : NonLoc(CompoundValKind, D) { + assert(D); + } 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; -private: - friend class SVal; - - CompoundVal() = default; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; - } - - static bool isKind(const NonLoc& V) { - return V.getSubKind() == CompoundValKind; - } + static bool classof(SVal V) { return V.getKind() == CompoundValKind; } }; class LazyCompoundVal : public NonLoc { friend class ento::SValBuilder; explicit LazyCompoundVal(const LazyCompoundValData *D) - : NonLoc(LazyCompoundValKind, D) {} + : NonLoc(LazyCompoundValKind, D) { + assert(D); + } public: + LLVM_ATTRIBUTE_RETURNS_NONNULL const LazyCompoundValData *getCVData() const { - return static_cast<const LazyCompoundValData *>(Data); + return castDataAs<LazyCompoundValData>(); } + /// It might return null. const void *getStore() const; - const TypedValueRegion *getRegion() const; - -private: - friend class SVal; - - LazyCompoundVal() = default; - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && - V.getSubKind() == LazyCompoundValKind; - } + LLVM_ATTRIBUTE_RETURNS_NONNULL + const TypedValueRegion *getRegion() const; - static bool isKind(const NonLoc& V) { - return V.getSubKind() == LazyCompoundValKind; - } + static bool classof(SVal V) { return V.getKind() == LazyCompoundValKind; } }; /// Value representing pointer-to-member. @@ -554,21 +412,11 @@ public: iterator begin() const; iterator end() const; -private: - friend class SVal; + static bool classof(SVal V) { return V.getKind() == PointerToMemberKind; } - PointerToMember() = default; +private: explicit PointerToMember(const PTMDataType D) : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {} - - static bool isKind(const SVal& V) { - return V.getBaseKind() == NonLocKind && - V.getSubKind() == PointerToMemberKind; - } - - static bool isKind(const NonLoc& V) { - return V.getSubKind() == PointerToMemberKind; - } }; } // namespace nonloc @@ -585,36 +433,23 @@ public: assert(Label); } - const LabelDecl *getLabel() const { - return static_cast<const LabelDecl *>(Data); - } + const LabelDecl *getLabel() const { return castDataAs<LabelDecl>(); } -private: - friend class SVal; - - GotoLabel() = default; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; - } - - static bool isKind(const Loc& V) { - return V.getSubKind() == GotoLabelKind; - } + static bool classof(SVal V) { return V.getKind() == GotoLabelKind; } }; class MemRegionVal : public Loc { public: - explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) { + explicit MemRegionVal(const MemRegion *r) : Loc(MemRegionValKind, r) { assert(r); } /// Get the underlining region. - const MemRegion *getRegion() const { - return static_cast<const MemRegion *>(Data); - } + LLVM_ATTRIBUTE_RETURNS_NONNULL + const MemRegion *getRegion() const { return castDataAs<MemRegion>(); } /// Get the underlining region and strip casts. + LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion* stripCasts(bool StripBaseCasts = true) const; template <typename REGION> @@ -630,52 +465,44 @@ public: return getRegion() != R.getRegion(); } -private: - friend class SVal; - - MemRegionVal() = default; - - static bool isKind(const SVal& V) { - return V.getBaseKind() == LocKind && - V.getSubKind() == MemRegionValKind; - } - - static bool isKind(const Loc& V) { - return V.getSubKind() == MemRegionValKind; - } + static bool classof(SVal V) { return V.getKind() == MemRegionValKind; } }; class ConcreteInt : public Loc { public: - explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} - - const llvm::APSInt &getValue() const { - return *static_cast<const llvm::APSInt *>(Data); - } - - // Transfer functions for binary/unary operations on ConcreteInts. - SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, - const ConcreteInt& R) const; - -private: - friend class SVal; + explicit ConcreteInt(const llvm::APSInt &V) : Loc(ConcreteIntKind, &V) {} - ConcreteInt() = default; + const llvm::APSInt &getValue() const { return *castDataAs<llvm::APSInt>(); } - static bool isKind(const SVal& V) { - return V.getBaseKind() == LocKind && - V.getSubKind() == ConcreteIntKind; - } - - static bool isKind(const Loc& V) { - return V.getSubKind() == ConcreteIntKind; - } + static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; } }; } // namespace 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 std::optional<To> castFailed() { return std::optional<To>{}; } + static To doCast(const From &f) { + return *static_cast<const To *>(cast<::clang::ento::SVal>(&f)); + } + static std::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 |