diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 086836f35..6764a94dc 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1445,7 +1445,7 @@ void CheckUnusedVar::checkStructMemberUsage() continue; // Bail out if some data is casted to struct.. - const std::string castPattern("( struct| " + scope.className + " * ) & %name% ["); + const std::string castPattern("( struct| " + scope.className + " * ) &| %name%"); if (Token::findmatch(scope.bodyEnd, castPattern.c_str())) continue; @@ -1465,13 +1465,9 @@ void CheckUnusedVar::checkStructMemberUsage() if (bailout) continue; - // Try to prevent false positives when struct members are not used directly. - if (Token::findmatch(scope.bodyEnd, (scope.className + " %type%| *").c_str())) - continue; - for (const Variable &var : scope.varlist) { - // declaring a POD member variable? - if (!var.typeStartToken()->isStandardType() && !var.isPointer()) + // only warn for variables without side effects + if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type())) continue; // Check if the struct member variable is used anywhere in the file diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 79bfc6037..03a990c76 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -66,6 +66,7 @@ private: TEST_CASE(structmember16); // #10485 TEST_CASE(structmember17); // #10591 TEST_CASE(structmember18); // #10684 + TEST_CASE(structmember19); // #10826 TEST_CASE(localvar1); TEST_CASE(localvar2); @@ -1405,7 +1406,7 @@ private: "{\n" " ab->a = 0;\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) struct member 'AB::b' is never used.\n", errout.str()); checkStructMemberUsage("struct AB\n" "{\n" @@ -1417,7 +1418,7 @@ private: "{\n" " ab->a = 0;\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) struct member 'AB::b' is never used.\n", errout.str()); } void structmember8() { @@ -1626,6 +1627,32 @@ private: ASSERT_EQUALS("", errout.str()); } + void structmember19() { // #10826 + checkStructMemberUsage("class C {};\n" + "struct S {\n" + " char* p;\n" + " std::string str;\n" + " C c;\n" + "};\n" + "void f(S* s) {}\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) struct member 'S::p' is never used.\n" + "[test.cpp:4]: (style) struct member 'S::str' is never used.\n" + "[test.cpp:5]: (style) struct member 'S::c' is never used.\n", + errout.str()); + + checkStructMemberUsage("class C {};\n" + "struct S {\n" + " char* p;\n" + " std::string str;\n" + " C c;\n" + "};\n" + "void f(S& s) {}\n"); + ASSERT_EQUALS("[test.cpp:3]: (style) struct member 'S::p' is never used.\n" + "[test.cpp:4]: (style) struct member 'S::str' is never used.\n" + "[test.cpp:5]: (style) struct member 'S::c' is never used.\n", + errout.str()); + } + void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") { // Clear the error buffer.. errout.str("");