Fix issue 8369: False negative: Condition 'condition' is always true (#1325)

* Fix issue 8369: False negative: Condition 'condition' is always true

* Use simpleMatch

* Add iterator header

* Cleanup

* Remove unused variable
This commit is contained in:
Paul Fultz II 2018-08-10 11:05:23 -05:00 committed by Daniel Marjamäki
parent 576418e17d
commit 3947c23290
3 changed files with 67 additions and 0 deletions

View File

@ -92,6 +92,8 @@
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <limits>
#include <map>
#include <set>
@ -1829,6 +1831,22 @@ static bool valueFlowForward(Token * const startToken,
return false;
}
// Forward known values in the else branch
if(Token::simpleMatch(end, "} else {")) {
std::list<ValueFlow::Value> knownValues;
std::copy_if(values.begin(), values.end(), std::back_inserter(knownValues), std::mem_fn(&ValueFlow::Value::isKnown));
valueFlowForward(end->tokAt(2),
end->linkAt(2),
var,
varid,
knownValues,
constValue,
subFunction,
tokenlist,
errorLogger,
settings);
}
// Remove conditional values
std::list<ValueFlow::Value>::iterator it;
for (it = values.begin(); it != values.end();) {

View File

@ -2462,6 +2462,15 @@ private:
check("void f() { if(1) {} }");
ASSERT_EQUALS("", errout.str());
check("void f(int i) {\n"
" bool b = false;\n"
" if (i == 0) b = true;\n"
" else if (!b && i == 1) {}\n"
" if (b)\n"
" {}\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Condition '!b' is always true\n", errout.str());
}
void checkInvalidTestForOverflow() {

View File

@ -80,6 +80,7 @@ private:
TEST_CASE(valueFlowAfterCondition);
TEST_CASE(valueFlowForwardCompoundAssign);
TEST_CASE(valueFlowForwardCorrelatedVariables);
TEST_CASE(valueFlowForwardModifiedVariables);
TEST_CASE(valueFlowForwardFunction);
TEST_CASE(valueFlowForwardTernary);
TEST_CASE(valueFlowForwardLambda);
@ -107,6 +108,24 @@ private:
TEST_CASE(valueFlowContainerSize);
}
bool testValueOfXKnown(const char code[], unsigned int linenr, int value) {
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
if (tok->str() == "x" && tok->linenr() == linenr) {
for(const ValueFlow::Value& val:tok->values()) {
if(val.isKnown() && val.intvalue == value)
return true;
}
}
}
return false;
}
bool testValueOfX(const char code[], unsigned int linenr, int value) {
// Tokenize..
Tokenizer tokenizer(&settings, this);
@ -2135,6 +2154,27 @@ private:
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
}
void valueFlowForwardModifiedVariables() {
const char *code;
code = "void f(bool b) {\n"
" int x = 0;\n"
" if (b) x = 1;\n"
" else b = x;\n"
"}";
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 0));
code = "void f(int i) {\n"
" int x = 0;\n"
" if (i == 0) \n"
" x = 1;\n"
" else if (!x && i == 1) \n"
" int b = x;\n"
"}\n";
ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 0));
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 0));
}
void valueFlowForwardFunction() {
const char *code;