diff --git a/lib/astutils.cpp b/lib/astutils.cpp index f8f662687..f141abd0c 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2809,6 +2809,11 @@ bool isVariableChanged(const Variable * var, const Settings *settings, bool cpp, return false; if (Token::Match(start, "; %varid% =", var->declarationId())) start = start->tokAt(2); + if (Token::simpleMatch(start, "=")) { + const Token* next = nextAfterAstRightmostLeafGeneric(start); + if (next) + start = next; + } return isExpressionChanged(var->nameToken(), start->next(), var->scope()->bodyEnd, settings, cpp, depth); } diff --git a/test/testastutils.cpp b/test/testastutils.cpp index fe31e4783..7046c2fc5 100644 --- a/test/testastutils.cpp +++ b/test/testastutils.cpp @@ -231,9 +231,12 @@ private: " if (b) { (int)((INTOF(8))result >> b); }\n" "}", "if", "}"); // #9235 - ASSERT_EQUALS(true, isVariableChanged("void f() {\n" - " int &a = a;\n" - "}\n", "= a", "}")); + ASSERT_EQUALS(false, + isVariableChanged("void f() {\n" + " int &a = a;\n" + "}\n", + "= a", + "}")); ASSERT_EQUALS(false, isVariableChanged("void f(const A& a) { a.f(); }", "{", "}")); ASSERT_EQUALS(true, diff --git a/test/testother.cpp b/test/testother.cpp index 4c807e298..681569327 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -2653,9 +2653,9 @@ private: check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const T& z = x;\n" //Make sure we find all assignments - " T& y = x\n" - " y.mutate();\n" //to avoid warnings that y can be const + " const T& z = x;\n" // Make sure we find all assignments + " T& y = x;\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" @@ -2667,29 +2667,29 @@ private: check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = x\n" - " y.mutate();\n" //to avoid warnings that y can be const + " U& y = x;\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " my::type& y = x\n" //we don't know if y is const or not - " y.mutate();\n" //to avoid warnings that y can be const + " my::type& y = x;\n" // we don't know if y is const or not + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U& y = static_cast(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " const U& y = static_cast(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = static_cast(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " U& y = static_cast(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" @@ -2698,129 +2698,127 @@ private: " const U& y = dynamic_cast(x)\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); - check( - "struct T : public U { void dostuff() const {}};\n" - "void a(T& x) {\n" - " x.dostuff();\n" - " const U& y = dynamic_cast(x)\n" - "}" - ); - ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U& y = dynamic_cast(x)\n" + " const U& y = dynamic_cast(x);\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = dynamic_cast(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " const U& y = dynamic_cast(x);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); + check("struct T : public U { void dostuff() const {}};\n" + "void a(T& x) {\n" + " x.dostuff();\n" + " U& y = dynamic_cast(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U& y = dynamic_cast(x)\n" + " const U& y = dynamic_cast(x);\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = dynamic_cast(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " U& y = dynamic_cast(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U* y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " U* y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U * y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " const U * y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); TODO_ASSERT_EQUALS("can be const", errout.str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U const * y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " U const * y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); TODO_ASSERT_EQUALS("can be const", errout.str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U * const y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " U * const y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U const * const * const * const y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " const U const * const * const * const y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); TODO_ASSERT_EQUALS("can be const", errout.str(), ""); //Currently taking the address is treated as a non-const operation when it should depend on what we do with it check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U const * const * * const y = dynamic_cast(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " const U const * const * * const y = dynamic_cast(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " my::fancy const * * const y = dynamic_cast const * * const>(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " my::fancy const * * const y = dynamic_cast const * * const>(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " my::fancy const * const * const y = dynamic_cast const * const * const>(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " my::fancy const * const * const y = dynamic_cast const * const * const>(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U& y = (const U&)(x)\n" + " const U& y = (const U&)(x);\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = (U&)(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " U& y = (U&)(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " const U& y = (typename const U&)(x)\n" + " const U& y = (typename const U&)(x);\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U& y = (typename U&)(x)\n" - " y.mutate();\n" //to avoid warnings that y can be const + " U& y = (typename U&)(x);\n" + " y.mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" - " U* y = (U*)(&x)\n" - " y->mutate();\n" //to avoid warnings that y can be const + " U* y = (U*)(&x);\n" + " y->mutate();\n" // to avoid warnings that y can be const "}"); ASSERT_EQUALS("[test.cpp:4]: (style) C-style pointer casting\n", errout.str()); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index a62de94e0..66ad966b7 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6224,6 +6224,19 @@ private: " int* a[] = { &x };\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #11992 + valueFlowUninit("void foo(const int &x) {\n" + " if(x==42) {;}\n" + "}\n" + "void test(void) {\n" + " int t;\n" + " int &p = t;\n" + " int &s = p;\n" + " int &q = s;\n" + " foo(q);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: q\n", errout.str()); } void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value