Check if member function modifies the variable (#1350)

* Check if member function modifies the variable

* Check for const pointer

* Add test for const condition

* Add more null checking

* Add todo assert for FN
This commit is contained in:
Paul Fultz II 2018-08-27 04:09:09 -05:00 committed by Daniel Marjamäki
parent acb0b9f07e
commit fc135e1087
3 changed files with 68 additions and 1 deletions

View File

@ -779,6 +779,21 @@ bool isVariableChanged(const Token *start, const Token *end, const unsigned int
if (isLikelyStreamRead(cpp, tok->previous())) if (isLikelyStreamRead(cpp, tok->previous()))
return true; return true;
// Member function call
if(Token::Match(tok, "%name% . %name% (")) {
const Variable * var = tok->variable();
bool isConst = var && var->isConst();
if(!isConst && var) {
const ValueType * valueType = var->valueType();
isConst = (valueType && valueType->pointer == 1 && valueType->constness == 1);
}
const Token *ftok = tok->tokAt(2);
const Function * fun = ftok->function();
if(!isConst && (!fun || !fun->isConst()))
return true;
}
const Token *ftok = tok; const Token *ftok = tok;
while (ftok && !Token::Match(ftok, "[({[]")) while (ftok && !Token::Match(ftok, "[({[]"))
ftok = ftok->astParent(); ftok = ftok->astParent();

View File

@ -71,6 +71,7 @@ private:
TEST_CASE(incorrectLogicOperator9); TEST_CASE(incorrectLogicOperator9);
TEST_CASE(incorrectLogicOperator10); // enum TEST_CASE(incorrectLogicOperator10); // enum
TEST_CASE(incorrectLogicOperator11); TEST_CASE(incorrectLogicOperator11);
TEST_CASE(incorrectLogicOperator12);
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError); TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
TEST_CASE(incorrectLogicOp_condSwapping); TEST_CASE(incorrectLogicOp_condSwapping);
TEST_CASE(testBug5895); TEST_CASE(testBug5895);
@ -1233,6 +1234,50 @@ private:
ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i == n && i < n.\n", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (warning) Logical conjunction always evaluates to false: i == n && i < n.\n", errout.str());
} }
void incorrectLogicOperator12() { // #8696
check("struct A {\n"
" void f() const;\n"
"};\n"
"void foo(A a) {\n"
" A x = a;\n"
" A y = a;\n"
" y.f();\n"
" if (a > x && a < y)\n"
" return;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:8]: (warning) Logical conjunction always evaluates to false: a > x && a < y.\n", errout.str());
check("struct A {\n"
" void f();\n"
"};\n"
"void foo(A a) {\n"
" A x = a;\n"
" A y = a;\n"
" y.f();\n"
" if (a > x && a < y)\n"
" return;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("void foo(A a) {\n"
" A x = a;\n"
" A y = a;\n"
" y.f();\n"
" if (a > x && a < y)\n"
" return;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("void foo(A a) {\n"
" const A x = a;\n"
" const A y = a;\n"
" y.f();\n"
" if (a > x && a < y)\n"
" return;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (warning) Logical conjunction always evaluates to false: a > x && a < y.\n", errout.str());
}
void secondAlwaysTrueFalseWhenFirstTrueError() { void secondAlwaysTrueFalseWhenFirstTrueError() {
check("void f(int x) {\n" check("void f(int x) {\n"
" if (x > 5 && x != 1)\n" " if (x > 5 && x != 1)\n"

View File

@ -3126,12 +3126,19 @@ private:
ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue()); ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue());
code = "void f() {\n" code = "void f() {\n"
" C *c;\n" " const C *c;\n"
" if (c->x() == 4) {}\n" " if (c->x() == 4) {}\n"
"}"; "}";
values = tokenValues(code, "c ."); values = tokenValues(code, "c .");
ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue()); ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue());
code = "void f() {\n"
" C *c;\n"
" if (c->x() == 4) {}\n"
"}";
values = tokenValues(code, "c .");
TODO_ASSERT_EQUALS(true, false, values.size()==1U && values.front().isUninitValue());
code = "void f() {\n" code = "void f() {\n"
" int **x;\n" " int **x;\n"
" y += 10;\n" " y += 10;\n"