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:
parent
acb0b9f07e
commit
fc135e1087
|
@ -779,6 +779,21 @@ bool isVariableChanged(const Token *start, const Token *end, const unsigned int
|
|||
if (isLikelyStreamRead(cpp, tok->previous()))
|
||||
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;
|
||||
while (ftok && !Token::Match(ftok, "[({[]"))
|
||||
ftok = ftok->astParent();
|
||||
|
|
|
@ -71,6 +71,7 @@ private:
|
|||
TEST_CASE(incorrectLogicOperator9);
|
||||
TEST_CASE(incorrectLogicOperator10); // enum
|
||||
TEST_CASE(incorrectLogicOperator11);
|
||||
TEST_CASE(incorrectLogicOperator12);
|
||||
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
|
||||
TEST_CASE(incorrectLogicOp_condSwapping);
|
||||
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());
|
||||
}
|
||||
|
||||
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() {
|
||||
check("void f(int x) {\n"
|
||||
" if (x > 5 && x != 1)\n"
|
||||
|
|
|
@ -3126,12 +3126,19 @@ private:
|
|||
ASSERT_EQUALS(true, values.size()==1U && values.front().isUninitValue());
|
||||
|
||||
code = "void f() {\n"
|
||||
" C *c;\n"
|
||||
" const C *c;\n"
|
||||
" if (c->x() == 4) {}\n"
|
||||
"}";
|
||||
values = tokenValues(code, "c .");
|
||||
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"
|
||||
" int **x;\n"
|
||||
" y += 10;\n"
|
||||
|
|
Loading…
Reference in New Issue