Skip to content

Commit ee93d30

Browse files
committed
ValueFlow: improved valueflow for loops that assign variable and then break
1 parent dc9b1f0 commit ee93d30

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

lib/valueflow.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,9 +820,34 @@ static bool valueFlowForward(Token * const startToken,
820820
++number_of_if;
821821
tok2 = end;
822822
} else {
823-
if (settings->debugwarnings)
824-
bailout(tokenlist, errorLogger, tok2, "variable " + var->name() + " is assigned in conditional code");
825-
return false;
823+
bool bail = true;
824+
825+
// loop that conditionally set variable and then break => either loop condition is
826+
// redundant or the variable can be unchanged after the loop.
827+
bool loopCondition = false;
828+
if (Token::simpleMatch(tok2, "while (") && Token::Match(tok2->next()->astOperand2(), "%op%"))
829+
loopCondition = true;
830+
else if (Token::simpleMatch(tok2, "for (") &&
831+
Token::simpleMatch(tok2->next()->astOperand2(), ";") &&
832+
Token::simpleMatch(tok2->next()->astOperand2()->astOperand2(), ";") &&
833+
Token::Match(tok2->next()->astOperand2()->astOperand2()->astOperand1(), "%op%"))
834+
loopCondition = true;
835+
if (loopCondition) {
836+
const Token *tok3 = Token::findmatch(start, "%varid%", end, varid);
837+
if (Token::Match(tok3, "%varid% =", varid) &&
838+
tok3->scope()->classEnd &&
839+
Token::Match(tok3->scope()->classEnd->tokAt(-3), "[;}] break ;") &&
840+
!Token::findmatch(tok3->next(), "%varid%", end, varid)) {
841+
bail = false;
842+
tok2 = end;
843+
}
844+
}
845+
846+
if (bail) {
847+
if (settings->debugwarnings)
848+
bailout(tokenlist, errorLogger, tok2, "variable " + var->name() + " is assigned in conditional code");
849+
return false;
850+
}
826851
}
827852
}
828853
}

test/testnullpointer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ class TestNullPointer : public TestFixture {
10991099
"\n"
11001100
" *p = 0;\n"
11011101
"}");
1102-
TODO_ASSERT_EQUALS("[test.cpp:11]: (error) Possible null pointer dereference: p\n", "", errout.str());
1102+
ASSERT_EQUALS("[test.cpp:11]: (error) Possible null pointer dereference: p\n", errout.str());
11031103
}
11041104

11051105
void nullpointer7() {

test/testvalueflow.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,43 @@ class TestValueFlow : public TestFixture {
871871
" }\n"
872872
"}";
873873
ASSERT_EQUALS(false, testValueOfX(code, 8U, 34));
874+
875+
// while/for
876+
code = "void f(const int *buf) {\n"
877+
" int x = 0;\n"
878+
" for (int i = 0; i < 10; i++) {\n"
879+
" if (buf[i] == 123) {\n"
880+
" x = i;\n"
881+
" break;\n"
882+
" }\n"
883+
" }\n"
884+
" a = x;\n" // <- x can be 0
885+
"}\n";
886+
ASSERT_EQUALS(true, testValueOfX(code, 9U, 0)); // x can be 0 at line 9
887+
888+
code = "void f(const int *buf) {\n"
889+
" int x = 0;\n"
890+
" for (int i = 0; i < 10; i++) {\n"
891+
" if (buf[i] == 123) {\n"
892+
" x = i;\n"
893+
" ;\n" // <- no break
894+
" }\n"
895+
" }\n"
896+
" a = x;\n" // <- x cant be 0
897+
"}\n";
898+
ASSERT_EQUALS(false, testValueOfX(code, 9U, 0)); // x cant be 0 at line 9
899+
900+
code = "void f(const int *buf) {\n"
901+
" int x = 0;\n"
902+
" while (++i < 10) {\n"
903+
" if (buf[i] == 123) {\n"
904+
" x = i;\n"
905+
" break;\n"
906+
" }\n"
907+
" }\n"
908+
" a = x;\n" // <- x can be 0
909+
"}\n";
910+
ASSERT_EQUALS(true, testValueOfX(code, 9U, 0)); // x can be 0 at line 9
874911
}
875912

876913
void valueFlowAfterCondition() {

0 commit comments

Comments
 (0)