diff --git a/lib/astutils.cpp b/lib/astutils.cpp index f16144310ac..8492591e3ca 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1810,21 +1810,36 @@ 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->astOperand1() == nullptr || cond->astOperand2() == nullptr) return false; - // Assume unsigned - // TODO: Handle reverse conditions - const bool isZero = cond->astOperand2()->getValue(0); - if (cond->str() == "==" || cond->str() == ">=") - return isZero; - if (cond->str() == "<=") - return true; - if (cond->str() == "<") - return !isZero; - if (cond->str() == ">") + + if ((reverse && !cond->astOperand1()->hasKnownIntValue()) || (!reverse && !cond->astOperand2()->hasKnownIntValue())) return false; + + // Assume unsigned + const bool isZero = reverse ? cond->astOperand1()->getKnownIntValue() == 0 : cond->astOperand2()->getKnownIntValue() == 0; + if (reverse) { + if (cond->str() == "==" || cond->str() == "<=") + return isZero; + if (cond->str() == ">=") + return true; + if (cond->str() == ">") + return !isZero; + if (cond->str() == "<") + return false; + } else { + if (cond->str() == "==" || cond->str() == ">=") + return isZero; + if (cond->str() == "<=") + return true; + if (cond->str() == "<") + return !isZero; + if (cond->str() == ">") + return false; + } + return false; } @@ -1888,7 +1903,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 +1913,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 +1937,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());