diff --git a/lib/astutils.cpp b/lib/astutils.cpp index a77e4a3dc..89845f086 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -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(); diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 8bca20f52..d8eb48a2d 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -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" diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 92482c2ba..91bbdfdb6 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -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"