diff --git a/lib/astutils.cpp b/lib/astutils.cpp index f16144310ac..839ee250b97 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1810,21 +1810,31 @@ bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Se return commutativeEquals; } -static bool isZeroBoundCond(const Token * const cond) +static bool isZeroBoundCond(const Token * const cond, bool reverse) { - if (cond == nullptr) + if (cond == nullptr || !cond->isBinaryOp()) return false; + + const Token* op = reverse ? cond->astOperand1() : cond->astOperand2(); + if (!op->hasKnownIntValue()) + return false; + // Assume unsigned - // TODO: Handle reverse conditions - const bool isZero = cond->astOperand2()->getValue(0); - if (cond->str() == "==" || cond->str() == ">=") + const bool isZero = op->getKnownIntValue() == 0; + std::string cmp = cond->str(); + if (reverse) { + if (cmp[0] == '>') + cmp[0] = '<'; + else if (cmp[0] == '<') + cmp[0] = '>'; + } + + if (cmp == "==" || cmp == ">=") return isZero; - if (cond->str() == "<=") + if (cmp == "<=") return true; - if (cond->str() == "<") + if (cmp == "<") return !isZero; - if (cond->str() == ">") - return false; return false; } @@ -1888,7 +1898,7 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c if (isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors)) return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1()); } - // TODO: Handle reverse conditions + if (Library::isContainerYield(cond1, Library::Container::Yield::EMPTY, "empty") && Library::isContainerYield(cond2->astOperand1(), Library::Container::Yield::SIZE, "size") && isSameExpression(true, @@ -1898,7 +1908,19 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c pure, followVar, errors)) { - return !isZeroBoundCond(cond2); + return !isZeroBoundCond(cond2, false); + } + + if (Library::isContainerYield(cond1, Library::Container::Yield::EMPTY, "empty") && + Library::isContainerYield(cond2->astOperand2(), Library::Container::Yield::SIZE, "size") && + isSameExpression(true, + cond1->astOperand1()->astOperand1(), + cond2->astOperand2()->astOperand1()->astOperand1(), + settings, + pure, + followVar, + errors)) { + return !isZeroBoundCond(cond2, true); } if (Library::isContainerYield(cond2, Library::Container::Yield::EMPTY, "empty") && @@ -1910,7 +1932,19 @@ bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const c pure, followVar, errors)) { - return !isZeroBoundCond(cond1); + return !isZeroBoundCond(cond1, false); + } + + if (Library::isContainerYield(cond2, Library::Container::Yield::EMPTY, "empty") && + Library::isContainerYield(cond1->astOperand2(), Library::Container::Yield::SIZE, "size") && + isSameExpression(true, + cond2->astOperand1()->astOperand1(), + cond1->astOperand2()->astOperand1()->astOperand1(), + settings, + pure, + followVar, + errors)) { + return !isZeroBoundCond(cond1, true); } } diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 29d63562fa3..421fa53e2bc 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -2674,6 +2674,12 @@ class TestCondition : public TestFixture { check("void f1(const std::string &s) { if(s.size() >= 0) if(s.empty()) {}} "); // CheckOther says: Unsigned expression 's.size()' can't be negative so it is unnecessary to test it. [unsignedPositive] ASSERT_EQUALS("", errout_str()); + check("void f1(const std::string &s) { if(42 < s.size()) if(s.empty()) {}}"); + ASSERT_EQUALS("[test.cpp:1:39] -> [test.cpp:1:61]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + + check("void f1(const std::string &s) { if(s.empty()) if(42 < s.size()) {}}"); + ASSERT_EQUALS("[test.cpp:1:43] -> [test.cpp:1:53]: (warning) Opposite inner 'if' condition leads to a dead code block. [oppositeInnerCondition]\n", errout_str()); + // TODO: These are identical condition since size cannot be negative check("void f1(const std::string &s) { if(s.size() <= 0) if(s.empty()) {}}"); ASSERT_EQUALS("", errout_str());