Skip to content

Commit ee8d5b9

Browse files
authored
checkunusedvar: handle array element change using pointer arithmetic (#3000)
1 parent 8dc8aa0 commit ee8d5b9

3 files changed

Lines changed: 117 additions & 7 deletions

File tree

lib/astutils.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,23 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings *settings,
16811681
return true;
16821682
return false;
16831683
}
1684+
1685+
if (indirect > 0)
1686+
{
1687+
// check for `*(ptr + 1) = new_value` case
1688+
parent = tok2->astParent();
1689+
while (parent && parent->isArithmeticalOp() && parent->isBinaryOp()) {
1690+
parent = parent->astParent();
1691+
}
1692+
if (Token::simpleMatch(parent, "*"))
1693+
{
1694+
if (parent->astParent() && parent->astParent()->isAssignmentOp() &&
1695+
(parent->astParent()->astOperand1() == parent)) {
1696+
return true;
1697+
}
1698+
}
1699+
}
1700+
16841701
return false;
16851702
}
16861703

lib/checkunusedvar.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,9 +1620,6 @@ bool CheckUnusedVar::isFunctionWithoutSideEffects(const Function& func, const To
16201620
}
16211621
// check if global variable is changed
16221622
if (bodyVariable->isGlobal() || (pointersToGlobals.find(bodyVariable) != pointersToGlobals.end())) {
1623-
if (bodyVariable->isPointer() || bodyVariable->isArray()) {
1624-
return false; // TODO: Update astutils.cpp:1544 isVariableChanged() and remove this. Unhandled case: `*(global_arr + 1) = new_val`
1625-
}
16261623
const int depth = 20;
16271624
if (isVariableChanged(bodyToken, depth, mSettings, mTokenizer->isCPP())) {
16281625
return false;

test/testunusedvar.cpp

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,23 @@ class TestUnusedVar : public TestFixture {
748748
"}");
749749
ASSERT_EQUALS("", errout.str());
750750

751+
functionVariableUsage(
752+
"int x[] = {0, 1, 3};\n"
753+
"int func() {\n"
754+
" *(x) = 2;\n"
755+
" return 1;\n"
756+
"}\n"
757+
"class C {\n"
758+
"public:\n"
759+
" C() : x(func()) {}\n"
760+
" int x;\n"
761+
"};\n"
762+
"void f() {\n"
763+
" C c;\n"
764+
"}");
765+
ASSERT_EQUALS("", errout.str());
766+
767+
// pointer arithmetic on global array
751768
functionVariableUsage(
752769
"int x[] = {0, 1, 3};\n"
753770
"int func() {\n"
@@ -764,6 +781,87 @@ class TestUnusedVar : public TestFixture {
764781
"}");
765782
ASSERT_EQUALS("", errout.str());
766783

784+
functionVariableUsage(
785+
"int x[][] = {{0, 1}, {2, 3}};\n"
786+
"int func() {\n"
787+
" *((x + 1) + 1) = 4;\n"
788+
" return 1;\n"
789+
"}\n"
790+
"class C {\n"
791+
"public:\n"
792+
" C() : x(func()) {}\n"
793+
" int x;\n"
794+
"};\n"
795+
"void f() {\n"
796+
" C c;\n"
797+
"}");
798+
ASSERT_EQUALS("", errout.str());
799+
800+
functionVariableUsage(
801+
"int x[] = {0, 1, 3};\n"
802+
"int func() {\n"
803+
" int local = *(x + 1);\n"
804+
" (void) local;\n"
805+
" return 1;\n"
806+
"}\n"
807+
"class C {\n"
808+
"public:\n"
809+
" C() : x(func()) {}\n"
810+
" int x;\n"
811+
"};\n"
812+
"void f() {\n"
813+
" C c;\n"
814+
"}");
815+
ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str());
816+
817+
functionVariableUsage(
818+
"int x[] = {0, 1, 3};\n"
819+
"int func() {\n"
820+
" int* local = x + 2;\n"
821+
" (void) local;\n"
822+
" return 1;\n"
823+
"}\n"
824+
"class C {\n"
825+
"public:\n"
826+
" C() : x(func()) {}\n"
827+
" int x;\n"
828+
"};\n"
829+
"void f() {\n"
830+
" C c;\n"
831+
"}");
832+
ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str());
833+
834+
functionVariableUsage(
835+
"int x[] = {0, 1, 3};\n"
836+
"int func() {\n"
837+
" int* local = x + 2;\n"
838+
" return *local;\n"
839+
"}\n"
840+
"class C {\n"
841+
"public:\n"
842+
" C() : x(func()) {}\n"
843+
" int x;\n"
844+
"};\n"
845+
"void f() {\n"
846+
" C c;\n"
847+
"}");
848+
ASSERT_EQUALS("", errout.str());
849+
850+
functionVariableUsage(
851+
"int x[] = {0, 1, 3};\n"
852+
"int func() {\n"
853+
" return *(x + 1);\n"
854+
"}\n"
855+
"class C {\n"
856+
"public:\n"
857+
" C() : x(func()) {}\n"
858+
" int x;\n"
859+
"};\n"
860+
"void f() {\n"
861+
" C c;\n"
862+
"}");
863+
ASSERT_EQUALS("", errout.str());
864+
767865
// changing local variable
768866
functionVariableUsage(
769867
"int func() {\n"
@@ -1064,8 +1162,7 @@ class TestUnusedVar : public TestFixture {
10641162
"void f() {\n"
10651163
" C c;\n"
10661164
"}");
1067-
// TODO: see TODO for global vars under CheckUnusedVar::isFunctionWithoutSideEffects()
1068-
TODO_ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", "", errout.str());
1165+
ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str());
10691166

10701167
// global struct variable modification
10711168
functionVariableUsage(
@@ -1135,8 +1232,7 @@ class TestUnusedVar : public TestFixture {
11351232
"void f() {\n"
11361233
" C c;\n"
11371234
"}");
1138-
// TODO: see TODO for global vars under CheckUnusedVar::isFunctionWithoutSideEffects()
1139-
TODO_ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", "", errout.str());
1235+
ASSERT_EQUALS("[test.cpp:13]: (style) Unused variable: c\n", errout.str());
11401236
}
11411237

11421238
// #5355 - False positive: Variable is not assigned a value.

0 commit comments

Comments
 (0)