diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -1213,13 +1213,21 @@ } RangeSet VisitSymExpr(SymbolRef Sym) { - // If we got to this function, the actual type of the symbolic + if (Optional RS = getRangeForNegatedSym(Sym)) + return *RS; + // If we've reached this line, the actual type of the symbolic // expression is not supported for advanced inference. // In this case, we simply backoff to the default "let's simply // infer the range from the expression's type". return infer(Sym->getType()); } + RangeSet VisitUnarySymExpr(const UnarySymExpr *USE) { + if (Optional RS = getRangeForNegatedUnarySym(USE)) + return *RS; + return infer(USE->getType()); + } + RangeSet VisitSymIntExpr(const SymIntExpr *Sym) { return VisitBinaryOperator(Sym); } @@ -1228,14 +1236,25 @@ return VisitBinaryOperator(Sym); } - RangeSet VisitSymSymExpr(const SymSymExpr *Sym) { + RangeSet VisitSymSymExpr(const SymSymExpr *SSE) { return intersect( RangeFactory, + // If Sym is a difference of symbols A - B, then maybe we have range + // set stored for B - A. + // + // If we have range set stored for both A - B and B - A then + // calculate the effective range set by intersecting the range set + // for A - B and the negated range set of B - A. + getRangeForNegatedSymSym(SSE), + // If Sym is a comparison expression (except <=>), + // find any other comparisons with the same operands. + // See function description. + getRangeForComparisonSymbol(SSE), // If Sym is (dis)equality, we might have some information // on that in our equality classes data structure. - getRangeForEqualities(Sym), + getRangeForEqualities(SSE), // And we should always check what we can get from the operands. - VisitBinaryOperator(Sym)); + VisitBinaryOperator(SSE)); } private: @@ -1264,25 +1283,13 @@ } RangeSet infer(SymbolRef Sym) { - return intersect( - RangeFactory, - // Of course, we should take the constraint directly associated with - // this symbol into consideration. - getConstraint(State, Sym), - // If Sym is a difference of symbols A - B, then maybe we have range - // set stored for B - A. - // - // If we have range set stored for both A - B and B - A then - // calculate the effective range set by intersecting the range set - // for A - B and the negated range set of B - A. - getRangeForNegatedSub(Sym), - // If Sym is a comparison expression (except <=>), - // find any other comparisons with the same operands. - // See function description. - getRangeForComparisonSymbol(Sym), - // Apart from the Sym itself, we can infer quite a lot if we look - // into subexpressions of Sym. - Visit(Sym)); + return intersect(RangeFactory, + // Of course, we should take the constraint directly + // associated with this symbol into consideration. + getConstraint(State, Sym), + // Apart from the Sym itself, we can infer quite a lot if + // we look into subexpressions of Sym. + Visit(Sym)); } RangeSet infer(EquivalenceClass Class) { @@ -1443,38 +1450,53 @@ return RangeFactory.deletePoint(Domain, IntType.getZeroValue()); } - Optional getRangeForNegatedSub(SymbolRef Sym) { + template + Optional getRangeForNegatedExpr(ProduceNegatedSymFunc F, + QualType T) { // Do not negate if the type cannot be meaningfully negated. - if (!Sym->getType()->isUnsignedIntegerOrEnumerationType() && - !Sym->getType()->isSignedIntegerOrEnumerationType()) + if (!T->isUnsignedIntegerOrEnumerationType() && + !T->isSignedIntegerOrEnumerationType()) return llvm::None; - const RangeSet *NegatedRange = nullptr; - SymbolManager &SymMgr = State->getSymbolManager(); - if (const auto *USE = dyn_cast(Sym)) { - if (USE->getOpcode() == UO_Minus) { - // Just get the operand when we negate a symbol that is already negated. - // -(-a) == a - NegatedRange = getConstraint(State, USE->getOperand()); - } - } else if (const SymSymExpr *SSE = dyn_cast(Sym)) { - if (SSE->getOpcode() == BO_Sub) { - QualType T = Sym->getType(); - SymbolRef NegatedSym = - SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, SSE->getLHS(), T); - NegatedRange = getConstraint(State, NegatedSym); - } - } else { - SymbolRef NegatedSym = - SymMgr.getUnarySymExpr(Sym, UO_Minus, Sym->getType()); - NegatedRange = getConstraint(State, NegatedSym); - } + if (SymbolRef NegatedSym = F()) + if (const RangeSet *NegatedRange = getConstraint(State, NegatedSym)) + return RangeFactory.negate(*NegatedRange); - if (NegatedRange) - return RangeFactory.negate(*NegatedRange); return llvm::None; } + Optional getRangeForNegatedUnarySym(const UnarySymExpr *USE) { + // Just get the operand when we negate a symbol that is already negated. + // -(-a) == a + return getRangeForNegatedExpr( + [USE]() -> SymbolRef { + if (USE->getOpcode() == UO_Minus) + return USE->getOperand(); + return nullptr; + }, + USE->getType()); + } + + Optional getRangeForNegatedSymSym(const SymSymExpr *SSE) { + return getRangeForNegatedExpr( + [SSE, State = this->State]() -> SymbolRef { + if (SSE->getOpcode() == BO_Sub) + return State->getSymbolManager().getSymSymExpr( + SSE->getRHS(), BO_Sub, SSE->getLHS(), SSE->getType()); + return nullptr; + }, + SSE->getType()); + } + + Optional getRangeForNegatedSym(SymbolRef Sym) { + return getRangeForNegatedExpr( + [Sym, State = this->State]() { + return State->getSymbolManager().getUnarySymExpr(Sym, UO_Minus, + Sym->getType()); + }, + Sym->getType()); + } + // Returns ranges only for binary comparison operators (except <=>) // when left and right operands are symbolic values. // Finds any other comparisons with the same operands. @@ -1485,11 +1507,7 @@ // It covers all possible combinations (see CmpOpTable description). // Note that `x` and `y` can also stand for subexpressions, // not only for actual symbols. - Optional getRangeForComparisonSymbol(SymbolRef Sym) { - const auto *SSE = dyn_cast(Sym); - if (!SSE) - return llvm::None; - + Optional getRangeForComparisonSymbol(const SymSymExpr *SSE) { const BinaryOperatorKind CurrentOP = SSE->getOpcode(); // We currently do not support <=> (C++20).