diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -22,32 +22,76 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/APSInt.h" #include using namespace clang; using namespace ento; namespace { -// This evaluator checks two SVals for equality. The first SVal is provided via -// the constructor, the second is the parameter of the overloaded () operator. -// It uses the in-built ConstraintManager to resolve the equlity to possible or -// not possible ProgramStates. -class ConstraintBasedEQEvaluator { - const DefinedOrUnknownSVal CompareValue; - const ProgramStateRef PS; - SValBuilder &SVB; - -public: - ConstraintBasedEQEvaluator(CheckerContext &C, - const DefinedOrUnknownSVal CompareValue) - : CompareValue(CompareValue), PS(C.getState()), SVB(C.getSValBuilder()) {} +class ValueMatchEvaluator { +protected: + CheckerContext &C; + SValBuilder &SVB = C.getSValBuilder(); + const ProgramStateRef PS = C.getState(); + ValueMatchEvaluator(CheckerContext &C) + : C(C), SVB(C.getSValBuilder()), PS(C.getState()) {} +}; - bool operator()(const llvm::APSInt &EnumDeclInitValue) { - DefinedOrUnknownSVal EnumDeclValue = SVB.makeIntVal(EnumDeclInitValue); - DefinedOrUnknownSVal ElemEqualsValueToCast = - SVB.evalEQ(PS, EnumDeclValue, CompareValue); +class RangeBasedValueMatchEvaluator : ValueMatchEvaluator { + llvm::APSInt Min, Max; - return static_cast(PS->assume(ElemEqualsValueToCast, true)); +public: + RangeBasedValueMatchEvaluator(CheckerContext &C, const llvm::APSInt &Min, + const llvm::APSInt &Max) + : ValueMatchEvaluator(C), Min(Min), Max(Max) {} + bool possiblyContains(const DefinedOrUnknownSVal &CompareValue) { + // Check if there is a possibility of CompareValue between the min and max + // values of the underlying type's range. + + // Build the ExplodedGraph to incrementally model valid assumptions. + ExplodedNode *Pred = C.getPredecessor(); + + auto CheckAssumption = + [this, &Pred]( + SVal Assumption) -> std::pair { + if (Assumption.isUndef()) + return {nullptr, nullptr}; + + const auto DefinedOrUnknownAssumption = + Assumption.castAs(); + const auto [TrueState, FalseState] = + C.getState()->assume(DefinedOrUnknownAssumption); + if (TrueState && !FalseState) { + Pred = C.addTransition(TrueState, Pred); + } else if (FalseState && !TrueState) { + Pred = C.addTransition(FalseState, Pred); + } + return {TrueState, FalseState}; + }; + + // Check lower bound, i.e.: CompareValue >= Min. + const SVal LowerBound = SVB.makeIntVal(Min); + const SVal CompareValueAtLeastMin = + SVB.evalBinOp(C.getState(), BinaryOperator::Opcode::BO_GE, CompareValue, + LowerBound, SVB.getConditionType()); + const auto [AtLeastMin, NotAtLeastMin] = + CheckAssumption(CompareValueAtLeastMin); + + // Check upper bound, i.e.: CompareValue <= Max. + const SVal UpperBound = SVB.makeIntVal(Max); + SVal CompareValueAtMostMax = + SVB.evalBinOp(C.getState(), BinaryOperator::Opcode::BO_LE, CompareValue, + UpperBound, SVB.getConditionType()); + const auto [AtMostMax, NotAtMostMax] = + CheckAssumption(CompareValueAtMostMax); + + const bool DefinitelyLowerThanMin = NotAtLeastMin && !AtLeastMin; + const bool DefinitelyHigherThanMax = NotAtMostMax && !AtMostMax; + const bool DefinitelyOutOfRange = + DefinitelyLowerThanMin || DefinitelyHigherThanMax; + const bool PossiblyInRange = !DefinitelyOutOfRange; + return PossiblyInRange; } }; @@ -64,17 +108,6 @@ public: void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; }; - -using EnumValueVector = llvm::SmallVector; - -// Collects all of the values an enum can represent (as SVals). -EnumValueVector getDeclValuesForEnum(const EnumDecl *ED) { - EnumValueVector DeclValues( - std::distance(ED->enumerator_begin(), ED->enumerator_end())); - llvm::transform(ED->enumerators(), DeclValues.begin(), - [](const EnumConstantDecl *D) { return D->getInitVal(); }); - return DeclValues; -} } // namespace void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const { @@ -128,10 +161,30 @@ // function to handle this. const EnumDecl *ED = T->castAs()->getDecl(); - EnumValueVector DeclValues = getDeclValuesForEnum(ED); - // Check if any of the enum values possibly match. - bool PossibleValueMatch = llvm::any_of( - DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast)); + const bool IsFixed = ED->isFixed(); + + bool PossibleValueMatch = false; + + if (IsFixed) { + QualType UnderlyingType = ED->getIntegerType(); + const unsigned Bitwidth = C.getASTContext().getIntWidth(UnderlyingType); + const bool isUnsigned = UnderlyingType->isUnsignedIntegerType(); + llvm::APSInt UnderlyingTypeMin = + llvm::APSInt::getMinValue(Bitwidth, isUnsigned); + llvm::APSInt UnderlyingTypeMax = + llvm::APSInt::getMaxValue(Bitwidth, isUnsigned); + + PossibleValueMatch = + RangeBasedValueMatchEvaluator(C, UnderlyingTypeMin, UnderlyingTypeMax) + .possiblyContains(*ValueToCast); + } else { + llvm::APSInt RepresentationMin, RepresentationMax; + ED->getValueRange(RepresentationMax, RepresentationMin); + + PossibleValueMatch = + RangeBasedValueMatchEvaluator(C, RepresentationMin, RepresentationMax) + .possiblyContains(*ValueToCast); + } // If there is no value that can possibly match any of the enum values, then // warn. diff --git a/clang/test/Analysis/enum-cast-out-of-range.c b/clang/test/Analysis/enum-cast-out-of-range.c --- a/clang/test/Analysis/enum-cast-out-of-range.c +++ b/clang/test/Analysis/enum-cast-out-of-range.c @@ -2,29 +2,58 @@ // RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \ // RUN: -verify %s -enum En_t { - En_0 = -4, - En_1, - En_2 = 1, - En_3, - En_4 = 4 +#define UINT_MAX (~0U) +#define INT_MAX (int)(UINT_MAX & (UINT_MAX >> 1)) +#define INT_MIN (int)(UINT_MAX & ~(UINT_MAX >> 1)) + +// Enum with enumeration values only non-negative and max value smaller than +// INT_MAX +// this allows a signed or unsigned underlying type as well, but the max value +// of this type is definitely smaller than INT_MAX. +enum Nonneg_t { + Small_nonneg_0 = 0, + Small_nonneg_1, // 1 + Small_nonneg_2 = 4 +}; + +// Enum with enumeration values close to 0 (so having small absolute value). +// this forces a signed representation. +enum Small_abs_t { + Small_abs_0 = -1, + Small_abs_1, // 0 + Small_abs_2 = 4 +}; + +// Enum with big enumeration values. +enum Big_abs_t { + Big_abs_0 = (long long)INT_MIN - 1, + Big_abs_1 = (long long)INT_MAX + 1 }; -void unscopedUnspecifiedCStyle(void) { - enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range}} - enum En_t NegVal1 = (enum En_t)(-4); // OK. - enum En_t NegVal2 = (enum En_t)(-3); // OK. - enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range}} - enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range}} - enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range}} - enum En_t PosVal1 = (enum En_t)(1); // OK. - enum En_t PosVal2 = (enum En_t)(2); // OK. - enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range}} - enum En_t PosVal3 = (enum En_t)(4); // OK. - enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range}} +void unscopedUnspecifiedNonnegEnumCStyle(void) { + // the underlying type may be unsigned + enum Nonneg_t NegVal = (enum Nonneg_t)(-1); // expected-warning {{not in the valid range}} + // enum Nonneg_t ZeroVal = (enum Nonneg_t)(0); // OK + // enum Nonneg_t NonMentionedVal = (enum Nonneg_t)(2); // OK as the underlying type should be able to represent [0..4] + // the underlying type is not wider than int + enum Nonneg_t BigVal = (enum Nonneg_t)((long long)INT_MAX + 1); //expected-warning {{not in the valid range}} +} + +void unscopedUnspecifiedSmallEnumCStyle(void) { + enum Small_abs_t NegVal = (enum Small_abs_t)(-1); // OK + enum Small_abs_t ZeroVal = (enum Small_abs_t)(0); // OK + enum Small_abs_t NonMentionedVal = (enum Small_abs_t)(2); // OK as the underlying type should be able to represent [-1..4] + // the underlying type is not wider than int + enum Small_abs_t BigVal = (enum Small_abs_t)((long long)INT_MAX + 1); //expected-warning {{not in the valid range}} +} + +void unscopedUnspecifiedBigEnumCStyle(void) { + enum Big_abs_t NegVal = (enum Big_abs_t)((long long)INT_MIN - 1); // OK + enum Big_abs_t ZeroVal = (enum Big_abs_t)(0); // OK + enum Big_abs_t BigVal = (enum Big_abs_t)((long long)INT_MAX + 1); // OK } -enum En_t unused; +enum Unused_t { Unused_enum_val } unused; void unusedExpr(void) { // Following line is not something that EnumCastOutOfRangeChecker should // evaluate. Checker should either ignore this line or process it without diff --git a/clang/test/Analysis/enum-cast-out-of-range.cpp b/clang/test/Analysis/enum-cast-out-of-range.cpp --- a/clang/test/Analysis/enum-cast-out-of-range.cpp +++ b/clang/test/Analysis/enum-cast-out-of-range.cpp @@ -2,199 +2,45 @@ // RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \ // RUN: -std=c++11 -verify %s -enum unscoped_unspecified_t { - unscoped_unspecified_0 = -4, - unscoped_unspecified_1, - unscoped_unspecified_2 = 1, - unscoped_unspecified_3, - unscoped_unspecified_4 = 4 -}; +#define UINT_MAX (~0U) +#define INT_MAX (int)(UINT_MAX & (UINT_MAX >> 1)) -enum unscoped_specified_t : int { - unscoped_specified_0 = -4, - unscoped_specified_1, - unscoped_specified_2 = 1, - unscoped_specified_3, - unscoped_specified_4 = 4 -}; +enum unscoped_specified_t : unsigned char; -enum class scoped_unspecified_t { - scoped_unspecified_0 = -4, - scoped_unspecified_1, - scoped_unspecified_2 = 1, - scoped_unspecified_3, - scoped_unspecified_4 = 4 -}; - -enum class scoped_specified_t : int { - scoped_specified_0 = -4, - scoped_specified_1, - scoped_specified_2 = 1, - scoped_specified_3, - scoped_specified_4 = 4 -}; - -struct S { - unscoped_unspecified_t E : 5; -}; - -void unscopedUnspecified() { - unscoped_unspecified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidNegativeValue1 = static_cast(-4); // OK. - unscoped_unspecified_t ValidNegativeValue2 = static_cast(-3); // OK. - unscoped_unspecified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidPositiveValue1 = static_cast(1); // OK. - unscoped_unspecified_t ValidPositiveValue2 = static_cast(2); // OK. - unscoped_unspecified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidPositiveValue3 = static_cast(4); // OK. - unscoped_unspecified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} +enum class scoped_specified_t : unsigned char; void unscopedSpecified() { - unscoped_specified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidNegativeValue1 = static_cast(-4); // OK. - unscoped_specified_t ValidNegativeValue2 = static_cast(-3); // OK. - unscoped_specified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidPositiveValue1 = static_cast(1); // OK. - unscoped_specified_t ValidPositiveValue2 = static_cast(2); // OK. - unscoped_specified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidPositiveValue3 = static_cast(4); // OK. - unscoped_specified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} + auto InvalidBeforeRangeBegin = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + auto Zero = static_cast(0); // OK. + auto VeryBigValueForEnum = static_cast(INT_MAX); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -void scopedUnspecified() { - scoped_unspecified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning{{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidNegativeValue1 = static_cast(-4); // OK. - scoped_unspecified_t ValidNegativeValue2 = static_cast(-3); // OK. - scoped_unspecified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidPositiveValue1 = static_cast(1); // OK. - scoped_unspecified_t ValidPositiveValue2 = static_cast(2); // OK. - scoped_unspecified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidPositiveValue3 = static_cast(4); // OK. - scoped_unspecified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + // Suppress unused warnings + [](...){}(InvalidBeforeRangeBegin,Zero,VeryBigValueForEnum); } void scopedSpecified() { - scoped_specified_t InvalidBeforeRangeBegin = static_cast(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidNegativeValue1 = static_cast(-4); // OK. - scoped_specified_t ValidNegativeValue2 = static_cast(-3); // OK. - scoped_specified_t InvalidInsideRange1 = static_cast(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t InvalidInsideRange2 = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t InvalidInsideRange3 = static_cast(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidPositiveValue1 = static_cast(1); // OK. - scoped_specified_t ValidPositiveValue2 = static_cast(2); // OK. - scoped_specified_t InvalidInsideRange4 = static_cast(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidPositiveValue3 = static_cast(4); // OK. - scoped_specified_t InvalidAfterRangeEnd = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + auto InvalidBeforeRangeBegin = static_cast(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + auto Zero = static_cast(0); // OK. + auto VeryBigValueForEnum = static_cast(INT_MAX); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + // + // Suppress unused warnings + [](...){}(InvalidBeforeRangeBegin,Zero,VeryBigValueForEnum); } -void unscopedUnspecifiedCStyle() { - unscoped_unspecified_t InvalidBeforeRangeBegin = (unscoped_unspecified_t)(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidNegativeValue1 = (unscoped_unspecified_t)(-4); // OK. - unscoped_unspecified_t ValidNegativeValue2 = (unscoped_unspecified_t)(-3); // OK. - unscoped_unspecified_t InvalidInsideRange1 = (unscoped_unspecified_t)(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t InvalidInsideRange2 = (unscoped_unspecified_t)(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t InvalidInsideRange3 = (unscoped_unspecified_t)(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidPositiveValue1 = (unscoped_unspecified_t)(1); // OK. - unscoped_unspecified_t ValidPositiveValue2 = (unscoped_unspecified_t)(2); // OK. - unscoped_unspecified_t InvalidInsideRange4 = (unscoped_unspecified_t)(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_unspecified_t ValidPositiveValue3 = (unscoped_unspecified_t)(4); // OK. - unscoped_unspecified_t InvalidAfterRangeEnd = (unscoped_unspecified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} +void undefinedInput(int input) { + auto unscoped = static_cast(input); // OK. + auto scoped = static_cast(input); // OK. -void unscopedSpecifiedCStyle() { - unscoped_specified_t InvalidBeforeRangeBegin = (unscoped_specified_t)(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidNegativeValue1 = (unscoped_specified_t)(-4); // OK. - unscoped_specified_t ValidNegativeValue2 = (unscoped_specified_t)(-3); // OK. - unscoped_specified_t InvalidInsideRange1 = (unscoped_specified_t)(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t InvalidInsideRange2 = (unscoped_specified_t)(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t InvalidInsideRange3 = (unscoped_specified_t)(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidPositiveValue1 = (unscoped_specified_t)(1); // OK. - unscoped_specified_t ValidPositiveValue2 = (unscoped_specified_t)(2); // OK. - unscoped_specified_t InvalidInsideRange4 = (unscoped_specified_t)(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - unscoped_specified_t ValidPositiveValue3 = (unscoped_specified_t)(4); // OK. - unscoped_specified_t InvalidAfterRangeEnd = (unscoped_specified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} - -void scopedUnspecifiedCStyle() { - scoped_unspecified_t InvalidBeforeRangeBegin = (scoped_unspecified_t)(-5); // expected-warning{{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidNegativeValue1 = (scoped_unspecified_t)(-4); // OK. - scoped_unspecified_t ValidNegativeValue2 = (scoped_unspecified_t)(-3); // OK. - scoped_unspecified_t InvalidInsideRange1 = (scoped_unspecified_t)(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t InvalidInsideRange2 = (scoped_unspecified_t)(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t InvalidInsideRange3 = (scoped_unspecified_t)(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidPositiveValue1 = (scoped_unspecified_t)(1); // OK. - scoped_unspecified_t ValidPositiveValue2 = (scoped_unspecified_t)(2); // OK. - scoped_unspecified_t InvalidInsideRange4 = (scoped_unspecified_t)(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_unspecified_t ValidPositiveValue3 = (scoped_unspecified_t)(4); // OK. - scoped_unspecified_t InvalidAfterRangeEnd = (scoped_unspecified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} - -void scopedSpecifiedCStyle() { - scoped_specified_t InvalidBeforeRangeBegin = (scoped_specified_t)(-5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidNegativeValue1 = (scoped_specified_t)(-4); // OK. - scoped_specified_t ValidNegativeValue2 = (scoped_specified_t)(-3); // OK. - scoped_specified_t InvalidInsideRange1 = (scoped_specified_t)(-2); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t InvalidInsideRange2 = (scoped_specified_t)(-1); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t InvalidInsideRange3 = (scoped_specified_t)(0); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidPositiveValue1 = (scoped_specified_t)(1); // OK. - scoped_specified_t ValidPositiveValue2 = (scoped_specified_t)(2); // OK. - scoped_specified_t InvalidInsideRange4 = (scoped_specified_t)(3); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} - scoped_specified_t ValidPositiveValue3 = (scoped_specified_t)(4); // OK. - scoped_specified_t InvalidAfterRangeEnd = (scoped_specified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} - -unscoped_unspecified_t unused; -void unusedExpr() { - // following line is not something that EnumCastOutOfRangeChecker should evaluate. checker should either ignore this line - // or process it without producing any warnings. However, compilation will (and should) still generate a warning having - // nothing to do with this checker. - unused; // expected-warning {{expression result unused}} -} - -void rangeConstrained1(int input) { - if (input > -5 && input < 5) - auto value = static_cast(input); // OK. Being conservative, this is a possibly good value. + // Suppress unused warnings + [](...){}(unscoped, scoped); } void rangeConstrained2(int input) { - if (input < -5) - auto value = static_cast(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} - -void rangeConstrained3(int input) { - if (input >= -2 && input <= -1) - auto value = static_cast(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} - -void rangeConstrained4(int input) { - if (input >= -2 && input <= 1) - auto value = static_cast(input); // OK. Possibly 1. -} - -void rangeConstrained5(int input) { - if (input >= 1 && input <= 2) - auto value = static_cast(input); // OK. Strict inner matching. -} - -void rangeConstrained6(int input) { - if (input >= 2 && input <= 4) - auto value = static_cast(input); // OK. The value is possibly 2 or 4, dont warn. -} - -void rangeConstrained7(int input) { - if (input >= 3 && input <= 3) - auto value = static_cast(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -} + if (input < 0) { + auto unscoped = static_cast(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + auto scoped = static_cast(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} -void enumBitFieldAssignment() { - S s; - s.E = static_cast(4); // OK. - s.E = static_cast(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} + // Suppress unused warnings + [](...){}(unscoped, scoped); + } }