Improve checking of size condition against empty to avoid FPs (#1213)

* Improve checking of size condition against empty to avoid FPs

* Add const and todo for reverse conditions
This commit is contained in:
Paul Fultz II 2018-05-11 03:22:06 -05:00 committed by Daniel Marjamäki
parent 1e7c1841f7
commit c520735009
2 changed files with 47 additions and 2 deletions

View File

@ -248,6 +248,24 @@ bool isDifferentKnownValues(const Token * const tok1, const Token * const tok2)
return tok1->hasKnownValue() && tok2->hasKnownValue() && tok1->values() != tok2->values(); return tok1->hasKnownValue() && tok2->hasKnownValue() && tok1->values() != tok2->values();
} }
static bool isZeroBoundCond(const Token * const cond)
{
if(cond == 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() == ">")
return false;
return false;
}
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure) bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure)
{ {
if (!cond1 || !cond2) if (!cond1 || !cond2)
@ -273,16 +291,17 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
if (isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), library, pure)) if (isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), library, pure))
return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1()); return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1());
} }
// TODO: Handle reverse conditions
if (Library::isContainerYield(cond1, Library::Container::EMPTY, "empty") && if (Library::isContainerYield(cond1, Library::Container::EMPTY, "empty") &&
Library::isContainerYield(cond2->astOperand1(), Library::Container::SIZE, "size") && Library::isContainerYield(cond2->astOperand1(), Library::Container::SIZE, "size") &&
cond1->astOperand1()->astOperand1()->varId() == cond2->astOperand1()->astOperand1()->astOperand1()->varId()) { cond1->astOperand1()->astOperand1()->varId() == cond2->astOperand1()->astOperand1()->astOperand1()->varId()) {
return !(cond2->str() == "==" && cond2->astOperand2()->getValue(0)); return !isZeroBoundCond(cond2);
} }
if (Library::isContainerYield(cond2, Library::Container::EMPTY, "empty") && if (Library::isContainerYield(cond2, Library::Container::EMPTY, "empty") &&
Library::isContainerYield(cond1->astOperand1(), Library::Container::SIZE, "size") && Library::isContainerYield(cond1->astOperand1(), Library::Container::SIZE, "size") &&
cond2->astOperand1()->astOperand1()->varId() == cond1->astOperand1()->astOperand1()->astOperand1()->varId()) { cond2->astOperand1()->astOperand1()->varId() == cond1->astOperand1()->astOperand1()->astOperand1()->varId()) {
return !(cond1->str() == "==" && cond1->astOperand2()->getValue(0)); return !isZeroBoundCond(cond1);
} }
} }

View File

@ -1851,6 +1851,12 @@ private:
check("void f1(const std::string &s) { if(s.size() > 42) if(s.empty()) {}} "); check("void f1(const std::string &s) { if(s.size() > 42) if(s.empty()) {}} ");
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str()); ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
check("void f1(const std::string &s) { if(s.size() > 0) if(s.empty()) {}} ");
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
check("void f1(const std::string &s) { if(s.size() < 0) if(s.empty()) {}} ");
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}} "); check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}} ");
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str()); ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
@ -1877,6 +1883,26 @@ private:
check("void f1(const std::string v[10]) { if(v[0].size() > 42) if(v[1].empty()) {}} "); check("void f1(const std::string v[10]) { if(v[0].size() > 42) if(v[1].empty()) {}} ");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f1(const std::string &s) { if(s.size() <= 1) if(s.empty()) {}} ");
ASSERT_EQUALS("", errout.str());
check("void f1(const std::string &s) { if(s.size() <= 2) if(s.empty()) {}} ");
ASSERT_EQUALS("", errout.str());
check("void f1(const std::string &s) { if(s.size() < 2) if(s.empty()) {}} ");
ASSERT_EQUALS("", errout.str());
check("void f1(const std::string &s) { if(s.size() >= 0) if(s.empty()) {}} ");
ASSERT_EQUALS("", 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());
// TODO: These are identical condition since size cannot be negative
check("void f1(const std::string &s) { if(s.size() < 1) if(s.empty()) {}} ");
ASSERT_EQUALS("", errout.str());
} }
void identicalInnerCondition() { void identicalInnerCondition() {