diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 1d9136560..fe098d470 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1681,6 +1681,23 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, return true; return false; } + + if (indirect > 0) + { + // check for `*(ptr + 1) = new_value` case + parent = tok2->astParent(); + while (parent && parent->isArithmeticalOp() && parent->isBinaryOp()) { + parent = parent->astParent(); + } + if (Token::simpleMatch(parent, "*")) + { + if (parent->astParent() && parent->astParent()->isAssignmentOp() && + (parent->astParent()->astOperand1() == parent)) { + return true; + } + } + } + return false; } diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index b170ad977..441008b74 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1620,9 +1620,6 @@ bool CheckUnusedVar::isFunctionWithoutSideEffects(const Function& func, const To } // check if global variable is changed if (bodyVariable->isGlobal() || (pointersToGlobals.find(bodyVariable) != pointersToGlobals.end())) { - if (bodyVariable->isPointer() || bodyVariable->isArray()) { - return false; // TODO: Update astutils.cpp:1544 isVariableChanged() and remove this. Unhandled case: `*(global_arr + 1) = new_val` - } const int depth = 20; if (isVariableChanged(bodyToken, depth, mSettings, mTokenizer->isCPP())) { return false; diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index dd240c5b1..c485e3a6d 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -748,6 +748,23 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + functionVariableUsage( + "int x[] = {0, 1, 3};\n" + "int func() {\n" + " *(x) = 2;\n" + " return 1;\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + // pointer arithmetic on global array functionVariableUsage( "int x[] = {0, 1, 3};\n" "int func() {\n" @@ -764,6 +781,87 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + functionVariableUsage( + "int x[][] = {{0, 1}, {2, 3}};\n" + "int func() {\n" + " *((x + 1) + 1) = 4;\n" + " return 1;\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage( + "int x[] = {0, 1, 3};\n" + "int func() {\n" + " int local = *(x + 1);\n" + " (void) local;\n" + " return 1;\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str()); + + functionVariableUsage( + "int x[] = {0, 1, 3};\n" + "int func() {\n" + " int* local = x + 2;\n" + " (void) local;\n" + " return 1;\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str()); + + functionVariableUsage( + "int x[] = {0, 1, 3};\n" + "int func() {\n" + " int* local = x + 2;\n" + " return *local;\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage( + "int x[] = {0, 1, 3};\n" + "int func() {\n" + " return *(x + 1);\n" + "}\n" + "class C {\n" + "public:\n" + " C() : x(func()) {}\n" + " int x;\n" + "};\n" + "void f() {\n" + " C c;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + // changing local variable functionVariableUsage( "int func() {\n" @@ -1064,8 +1162,7 @@ private: "void f() {\n" " C c;\n" "}"); - // TODO: see TODO for global vars under CheckUnusedVar::isFunctionWithoutSideEffects() - TODO_ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str()); // global struct variable modification functionVariableUsage( @@ -1135,8 +1232,7 @@ private: "void f() {\n" " C c;\n" "}"); - // TODO: see TODO for global vars under CheckUnusedVar::isFunctionWithoutSideEffects() - TODO_ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str()); } // #5355 - False positive: Variable is not assigned a value.