Refactor valueFlowTerminatingCondition to handle inner conditions and complex conditions (#3060)
This commit is contained in:
parent
d05acf3c41
commit
f1cc3ada86
|
@ -507,14 +507,12 @@ void CheckCondition::multiCondition()
|
||||||
break;
|
break;
|
||||||
tok2 = tok2->tokAt(4);
|
tok2 = tok2->tokAt(4);
|
||||||
|
|
||||||
if (tok2->astOperand2() &&
|
if (tok2->astOperand2()) {
|
||||||
!cond1->hasKnownIntValue() &&
|
|
||||||
!tok2->astOperand2()->hasKnownIntValue()) {
|
|
||||||
ErrorPath errorPath;
|
ErrorPath errorPath;
|
||||||
if (isOverlappingCond(cond1, tok2->astOperand2(), true))
|
if (isOverlappingCond(cond1, tok2->astOperand2(), true))
|
||||||
overlappingElseIfConditionError(tok2, cond1->linenr());
|
overlappingElseIfConditionError(tok2->astOperand2(), cond1->linenr());
|
||||||
else if (isOppositeCond(true, mTokenizer->isCPP(), cond1, tok2->astOperand2(), mSettings->library, true, true, &errorPath))
|
else if (isOppositeCond(true, mTokenizer->isCPP(), cond1, tok2->astOperand2(), mSettings->library, true, true, &errorPath))
|
||||||
oppositeElseIfConditionError(cond1, tok2, errorPath);
|
oppositeElseIfConditionError(cond1, tok2->astOperand2(), errorPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1427,37 +1427,6 @@ static void valueFlowRightShift(TokenList *tokenList, const Settings* settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Settings *settings)
|
|
||||||
{
|
|
||||||
for (const Scope &scope : symboldatabase->scopeList) {
|
|
||||||
if (scope.type != Scope::eIf)
|
|
||||||
continue;
|
|
||||||
Token *tok = const_cast<Token *>(scope.classDef);
|
|
||||||
if (!Token::simpleMatch(tok, "if ("))
|
|
||||||
continue;
|
|
||||||
const Token *cond1 = tok->next()->astOperand2();
|
|
||||||
if (!cond1 || !cond1->isComparisonOp())
|
|
||||||
continue;
|
|
||||||
const bool cpp = symboldatabase->isCPP();
|
|
||||||
Token *tok2 = tok->linkAt(1);
|
|
||||||
while (Token::simpleMatch(tok2, ") {")) {
|
|
||||||
tok2 = tok2->linkAt(1);
|
|
||||||
if (!Token::simpleMatch(tok2, "} else { if ("))
|
|
||||||
break;
|
|
||||||
Token *ifOpenBraceTok = tok2->tokAt(4);
|
|
||||||
Token *cond2 = ifOpenBraceTok->astOperand2();
|
|
||||||
if (!cond2 || !cond2->isComparisonOp())
|
|
||||||
continue;
|
|
||||||
if (isOppositeCond(true, cpp, cond1, cond2, settings->library, true, true)) {
|
|
||||||
ValueFlow::Value value(1);
|
|
||||||
value.setKnown();
|
|
||||||
setTokenValue(cond2, value, settings);
|
|
||||||
}
|
|
||||||
tok2 = ifOpenBraceTok->link();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void valueFlowEnumValue(SymbolDatabase * symboldatabase, const Settings * settings)
|
static void valueFlowEnumValue(SymbolDatabase * symboldatabase, const Settings * settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -3756,7 +3725,19 @@ static const Token* findIncompleteVar(const Token* start, const Token* end)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowTerminatingCondition(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
ValueFlow::Value makeConditionValue(long long val, const Token* condTok, bool assume)
|
||||||
|
{
|
||||||
|
ValueFlow::Value v(val);
|
||||||
|
v.setKnown();
|
||||||
|
v.condition = condTok;
|
||||||
|
if (assume)
|
||||||
|
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
|
||||||
|
else
|
||||||
|
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
static void valueFlowConditionExpressions(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (const Scope * scope : symboldatabase->functionScopes) {
|
for (const Scope * scope : symboldatabase->functionScopes) {
|
||||||
if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
|
if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) {
|
||||||
|
@ -3773,28 +3754,58 @@ static void valueFlowTerminatingCondition(TokenList *tokenlist, SymbolDatabase*
|
||||||
// Skip known values
|
// Skip known values
|
||||||
if (tok->next()->hasKnownValue())
|
if (tok->next()->hasKnownValue())
|
||||||
continue;
|
continue;
|
||||||
const Token * parenTok = tok->next();
|
Token * parenTok = tok->next();
|
||||||
if (!Token::simpleMatch(parenTok->link(), ") {"))
|
if (!Token::simpleMatch(parenTok->link(), ") {"))
|
||||||
continue;
|
continue;
|
||||||
const Token * blockTok = parenTok->link()->tokAt(1);
|
Token * blockTok = parenTok->link()->tokAt(1);
|
||||||
// Check if the block terminates early
|
|
||||||
if (!isEscapeScope(blockTok, tokenlist))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const Token* condTok = parenTok->astOperand2();
|
const Token* condTok = parenTok->astOperand2();
|
||||||
ValueFlow::Value v1(0);
|
|
||||||
v1.setKnown();
|
|
||||||
v1.condition = condTok;
|
|
||||||
v1.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
|
|
||||||
ExpressionAnalyzer a1(condTok, v1, tokenlist);
|
|
||||||
valueFlowGenericForward(blockTok->link()->next(), scope->bodyEnd, a1, settings);
|
|
||||||
|
|
||||||
ValueFlow::Value v2(1);
|
Token* startTok = blockTok;
|
||||||
v2.setKnown();
|
// Inner condition
|
||||||
v2.condition = condTok;
|
{
|
||||||
v2.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
|
std::vector<const Token*> conds = {condTok};
|
||||||
OppositeExpressionAnalyzer a2(true, condTok, v2, tokenlist);
|
if (Token::simpleMatch(condTok, "&&")) {
|
||||||
valueFlowGenericForward(blockTok->link()->next(), scope->bodyEnd, a2, settings);
|
std::vector<const Token*> args = astFlatten(condTok, "&&");
|
||||||
|
conds.insert(conds.end(), args.begin(), args.end());
|
||||||
|
}
|
||||||
|
for(const Token* condTok2:conds) {
|
||||||
|
ExpressionAnalyzer a1(condTok2, makeConditionValue(1, condTok2, true), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok, startTok->link(), a1, settings);
|
||||||
|
|
||||||
|
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(0, condTok2, true), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok, startTok->link(), a2, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const Token*> conds = {condTok};
|
||||||
|
if (Token::simpleMatch(condTok, "||")) {
|
||||||
|
std::vector<const Token*> args = astFlatten(condTok, "||");
|
||||||
|
conds.insert(conds.end(), args.begin(), args.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check else block
|
||||||
|
if (Token::simpleMatch(startTok->link(), "} else {")) {
|
||||||
|
startTok = startTok->link()->tokAt(2);
|
||||||
|
for(const Token* condTok2:conds) {
|
||||||
|
ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok, startTok->link(), a1, settings);
|
||||||
|
|
||||||
|
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok, startTok->link(), a2, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the block terminates early
|
||||||
|
if (isEscapeScope(blockTok, tokenlist)) {
|
||||||
|
for(const Token* condTok2:conds) {
|
||||||
|
ExpressionAnalyzer a1(condTok2, makeConditionValue(0, condTok2, false), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a1, settings);
|
||||||
|
|
||||||
|
OppositeExpressionAnalyzer a2(true, condTok2, makeConditionValue(1, condTok2, false), tokenlist);
|
||||||
|
valueFlowGenericForward(startTok->link()->next(), scope->bodyEnd, a2, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6624,6 +6635,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowLifetime(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowBitAnd(tokenlist);
|
valueFlowBitAnd(tokenlist);
|
||||||
valueFlowSameExpressions(tokenlist);
|
valueFlowSameExpressions(tokenlist);
|
||||||
|
valueFlowConditionExpressions(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowFwdAnalysis(tokenlist, settings);
|
valueFlowFwdAnalysis(tokenlist, settings);
|
||||||
|
|
||||||
std::size_t values = 0;
|
std::size_t values = 0;
|
||||||
|
@ -6633,8 +6645,6 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
||||||
valueFlowPointerAliasDeref(tokenlist);
|
valueFlowPointerAliasDeref(tokenlist);
|
||||||
valueFlowArrayBool(tokenlist);
|
valueFlowArrayBool(tokenlist);
|
||||||
valueFlowRightShift(tokenlist, settings);
|
valueFlowRightShift(tokenlist, settings);
|
||||||
valueFlowOppositeCondition(symboldatabase, settings);
|
|
||||||
valueFlowTerminatingCondition(tokenlist, symboldatabase, errorLogger, settings);
|
|
||||||
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowAfterMove(tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||||
valueFlowInferCondition(tokenlist, settings);
|
valueFlowInferCondition(tokenlist, settings);
|
||||||
|
|
|
@ -533,27 +533,27 @@ private:
|
||||||
" if (a) { b = 1; }\n"
|
" if (a) { b = 1; }\n"
|
||||||
" else { if (a) { b = 2; } }\n"
|
" else { if (a) { b = 2; } }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Condition 'a' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Expression is always false because 'else if' condition matches previous condition at line 2.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a, int &b) {\n"
|
check("void f(int a, int &b) {\n"
|
||||||
" if (a) { b = 1; }\n"
|
" if (a) { b = 1; }\n"
|
||||||
" else { if (a) { b = 2; } }\n"
|
" else { if (a) { b = 2; } }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (style) Condition 'a' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (style) Expression is always false because 'else if' condition matches previous condition at line 2.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a, int &b) {\n"
|
check("void f(int a, int &b) {\n"
|
||||||
" if (a == 1) { b = 1; }\n"
|
" if (a == 1) { b = 1; }\n"
|
||||||
" else { if (a == 2) { b = 2; }\n"
|
" else { if (a == 2) { b = 2; }\n"
|
||||||
" else { if (a == 1) { b = 3; } } }\n"
|
" else { if (a == 1) { b = 3; } } }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (style) Condition 'a==1' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (style) Expression is always false because 'else if' condition matches previous condition at line 2.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a, int &b) {\n"
|
check("void f(int a, int &b) {\n"
|
||||||
" if (a == 1) { b = 1; }\n"
|
" if (a == 1) { b = 1; }\n"
|
||||||
" else { if (a == 2) { b = 2; }\n"
|
" else { if (a == 2) { b = 2; }\n"
|
||||||
" else { if (a == 2) { b = 3; } } }\n"
|
" else { if (a == 2) { b = 3; } } }\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (style) Condition 'a==2' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (style) Expression is always false because 'else if' condition matches previous condition at line 3.\n", errout.str());
|
||||||
|
|
||||||
check("void f(int a, int &b) {\n"
|
check("void f(int a, int &b) {\n"
|
||||||
" if (a++) { b = 1; }\n"
|
" if (a++) { b = 1; }\n"
|
||||||
|
@ -721,9 +721,9 @@ private:
|
||||||
" if (x) {}\n"
|
" if (x) {}\n"
|
||||||
" else if (!x) {}\n"
|
" else if (!x) {}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("test.cpp:3:style:Condition '!x' is always true\n"
|
ASSERT_EQUALS("test.cpp:3:style:Expression is always true because 'else if' condition is opposite to previous condition at line 2.\n"
|
||||||
"test.cpp:2:note:condition 'x'\n"
|
"test.cpp:2:note:first condition\n"
|
||||||
"test.cpp:3:note:Condition '!x' is always true\n", errout.str());
|
"test.cpp:3:note:else if condition is opposite to first condition\n", errout.str());
|
||||||
|
|
||||||
check("void f(int x) {\n"
|
check("void f(int x) {\n"
|
||||||
" int y = x;\n"
|
" int y = x;\n"
|
||||||
|
|
|
@ -1670,7 +1670,7 @@ private:
|
||||||
"( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; "
|
"( ( int ( * * ( * ) ( char * , char * , int , int ) ) ( ) ) global [ 6 ] ) ( \"assoc\" , \"eggdrop\" , 106 , 0 ) ; "
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:3]: (debug) valueflow.cpp:1319:valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable global\n", errout.str());
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:3]: (debug) valueflow.cpp:1319:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable global\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplifyTypedef68() { // ticket #2355
|
void simplifyTypedef68() { // ticket #2355
|
||||||
|
@ -1877,7 +1877,7 @@ private:
|
||||||
" B * b = new B;\n"
|
" B * b = new B;\n"
|
||||||
" b->f = new A::F * [ 10 ];\n"
|
" b->f = new A::F * [ 10 ];\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:12]: (debug) valueflow.cpp:1319:valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable idx\n", errout.str());
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:12]: (debug) valueflow.cpp:1319:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable idx\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplifyTypedef83() { // ticket #2620
|
void simplifyTypedef83() { // ticket #2620
|
||||||
|
|
|
@ -2743,7 +2743,7 @@ private:
|
||||||
check("::y(){x}");
|
check("::y(){x}");
|
||||||
|
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:1]: (debug) Executable scope 'y' with unknown function.\n"
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:1]: (debug) Executable scope 'y' with unknown function.\n"
|
||||||
"[test.cpp:1]: (debug) valueflow.cpp:1321:valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable x\n", errout.str());
|
"[test.cpp:1]: (debug) valueflow.cpp:1321:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void symboldatabase20() {
|
void symboldatabase20() {
|
||||||
|
|
|
@ -122,7 +122,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(valueFlowUninit);
|
TEST_CASE(valueFlowUninit);
|
||||||
|
|
||||||
TEST_CASE(valueFlowTerminatingCond);
|
TEST_CASE(valueFlowConditionExpressions);
|
||||||
|
|
||||||
TEST_CASE(valueFlowContainerSize);
|
TEST_CASE(valueFlowContainerSize);
|
||||||
|
|
||||||
|
@ -1266,7 +1266,7 @@ private:
|
||||||
" if (x == 123) {}\n"
|
" if (x == 123) {}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable y\n",
|
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable y\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1383,7 +1383,7 @@ private:
|
||||||
" y = ((x<0) ? x : ((x==2)?3:4));\n"
|
" y = ((x<0) ? x : ((x==2)?3:4));\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable y\n",
|
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable y\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
bailout("int f(int x) {\n"
|
bailout("int f(int x) {\n"
|
||||||
|
@ -1448,7 +1448,7 @@ private:
|
||||||
" if (x == 123) {}\n"
|
" if (x == 123) {}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable b\n",
|
"[test.cpp:2]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable b\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
code = "void f(int x, bool abc) {\n"
|
code = "void f(int x, bool abc) {\n"
|
||||||
|
@ -1497,7 +1497,7 @@ private:
|
||||||
" };\n"
|
" };\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a\n",
|
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
bailout("void f(int x, int y) {\n"
|
bailout("void f(int x, int y) {\n"
|
||||||
|
@ -1507,7 +1507,7 @@ private:
|
||||||
" };\n"
|
" };\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a\n",
|
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1519,7 +1519,7 @@ private:
|
||||||
" M;\n"
|
" M;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a\n"
|
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n"
|
||||||
"[test.cpp:4]: (debug) valueflow.cpp:1260:(valueFlow) bailout: variable 'x', condition is defined in macro\n",
|
"[test.cpp:4]: (debug) valueflow.cpp:1260:(valueFlow) bailout: variable 'x', condition is defined in macro\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
|
@ -1529,7 +1529,7 @@ private:
|
||||||
" FREE(x);\n"
|
" FREE(x);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a\n"
|
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n"
|
||||||
"[test.cpp:4]: (debug) valueflow.cpp:1260:(valueFlow) bailout: variable 'x', condition is defined in macro\n",
|
"[test.cpp:4]: (debug) valueflow.cpp:1260:(valueFlow) bailout: variable 'x', condition is defined in macro\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
}
|
}
|
||||||
|
@ -1543,7 +1543,7 @@ private:
|
||||||
" if (x==123){}\n"
|
" if (x==123){}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
ASSERT_EQUALS_WITHOUT_LINENUMBERS(
|
||||||
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowTerminatingCondition bailout: Skipping function due to incomplete variable a\n",
|
"[test.cpp:3]: (debug) valueflow.cpp::valueFlowConditionExpressions bailout: Skipping function due to incomplete variable a\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
// #5721 - FP
|
// #5721 - FP
|
||||||
|
@ -4202,7 +4202,7 @@ private:
|
||||||
ASSERT_EQUALS(0, values.size());
|
ASSERT_EQUALS(0, values.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowTerminatingCond() {
|
void valueFlowConditionExpressions() {
|
||||||
const char* code;
|
const char* code;
|
||||||
|
|
||||||
// opposite condition
|
// opposite condition
|
||||||
|
@ -4272,6 +4272,60 @@ private:
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS(false, valueOfTok(code, "!=").intvalue == 1);
|
ASSERT_EQUALS(false, valueOfTok(code, "!=").intvalue == 1);
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b || i == j) return;\n"
|
||||||
|
" if(i != j) {}\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, valueOfTok(code, "!=").intvalue == 1);
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b && i == j) return;\n"
|
||||||
|
" if(i != j) {}\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, tokenValues(code, "!=").empty());
|
||||||
|
|
||||||
|
code = "void f(int i, int j) {\n"
|
||||||
|
" if (i == j) {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, valueOfTok(code, "!=").intvalue == 0);
|
||||||
|
|
||||||
|
code = "void f(int i, int j) {\n"
|
||||||
|
" if (i == j) {} else {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, valueOfTok(code, "!=").intvalue == 1);
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b && i == j) {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, valueOfTok(code, "!=").intvalue == 0);
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b || i == j) {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, tokenValues(code, "!=").empty());
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b || i == j) {} else {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, valueOfTok(code, "!=").intvalue == 1);
|
||||||
|
|
||||||
|
code = "void f(bool b, int i, int j) {\n"
|
||||||
|
" if (b && i == j) {} else {\n"
|
||||||
|
" if (i != j) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, tokenValues(code, "!=").empty());
|
||||||
|
|
||||||
code = "void foo()\n" // #8924
|
code = "void foo()\n" // #8924
|
||||||
"{\n"
|
"{\n"
|
||||||
" if ( this->FileIndex >= 0 )\n"
|
" if ( this->FileIndex >= 0 )\n"
|
||||||
|
|
Loading…
Reference in New Issue