Improve valeflow analysis with comparison operators (#1131)

* Improve valeflow analysis with comparison operators

* Use simple match

* Dont add 0 on comparisons

* Check reverse comparisons

* Use nullptr

* Remove duplicate code tests
This commit is contained in:
Paul Fultz II 2018-04-04 23:51:31 -05:00 committed by Daniel Marjamäki
parent 54de7b48c9
commit b871c85b67
2 changed files with 90 additions and 4 deletions

View File

@ -2354,7 +2354,10 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
const Scope * scope = symboldatabase->functionScopes[i];
std::set<unsigned> aliased;
for (Token* tok = const_cast<Token*>(scope->classStart); tok != scope->classEnd; tok = tok->next()) {
const Token *vartok, *numtok;
const Token * vartok = nullptr;
const Token * numtok = nullptr;
const Token * lowertok = nullptr;
const Token * uppertok = nullptr;
if (Token::Match(tok, "= & %var% ;"))
aliased.insert(tok->tokAt(2)->varId());
@ -2372,7 +2375,35 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
}
if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
vartok = vartok->astOperand1();
if (!vartok->isName() || !numtok->hasKnownIntValue())
if (!vartok->isName())
continue;
} else if (Token::simpleMatch(tok, ">")) {
if (!tok->astOperand1() || !tok->astOperand2())
continue;
if (tok->astOperand1()->hasKnownIntValue()) {
uppertok = tok->astOperand1();
vartok = tok->astOperand2();
} else {
lowertok = tok->astOperand2();
vartok = tok->astOperand1();
}
if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
vartok = vartok->astOperand1();
if (!vartok->isName())
continue;
} else if (Token::simpleMatch(tok, "<")) {
if (!tok->astOperand1() || !tok->astOperand2())
continue;
if (tok->astOperand1()->hasKnownIntValue()) {
lowertok = tok->astOperand1();
vartok = tok->astOperand2();
} else {
uppertok = tok->astOperand2();
vartok = tok->astOperand1();
}
if (vartok->str() == "=" && vartok->astOperand1() && vartok->astOperand2())
vartok = vartok->astOperand1();
if (!vartok->isName())
continue;
} else if (tok->str() == "!") {
vartok = tok->astOperand1();
@ -2390,6 +2421,13 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
continue;
}
if(numtok && !numtok->hasKnownIntValue())
continue;
if(lowertok && !lowertok->hasKnownIntValue())
continue;
if(uppertok && !uppertok->hasKnownIntValue())
continue;
const unsigned int varid = vartok->varId();
if (varid == 0U)
continue;
@ -2402,7 +2440,21 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
continue;
}
std::list<ValueFlow::Value> values;
values.push_back(ValueFlow::Value(tok, numtok ? numtok->values().front().intvalue : 0LL));
// TODO: We should add all known values
if(numtok) {
values.push_back(ValueFlow::Value(tok, numtok->values().front().intvalue));
} else if(lowertok) {
long long v = lowertok->values().front().intvalue;
values.push_back(ValueFlow::Value(tok, v+1));
} else if(uppertok) {
long long v = uppertok->values().front().intvalue;
values.push_back(ValueFlow::Value(tok, v-1));
} else {
values.push_back(ValueFlow::Value(tok, 0LL));
}
if (Token::Match(tok->astParent(), "%oror%|&&")) {
Token *parent = const_cast<Token*>(tok->astParent());
@ -2453,7 +2505,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, SymbolDatabase* symbol
// based on the comparison, should we check the if or while?
int codeblock = 0;
if (Token::Match(tok, "==|>=|<=|!"))
if (Token::Match(tok, "==|>=|<=|!|>|<"))
codeblock = 1;
else if (Token::Match(tok, "%name%|!="))
codeblock = 2;

View File

@ -1732,6 +1732,40 @@ private:
"}";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
code = "void f(int x) {\n"
" if (x > 123) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 124));
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
code = "void f(int x) {\n"
" if (x < 123) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 122));
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
// ----
code = "void f(int x) {\n"
" if (123 < x) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 124));
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
code = "void f(int x) {\n"
" if (123 > x) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 122));
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
// in else
code = "void f(int x) {\n"
" if (x == 123) {}\n"