diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 568f0e009..bd1fc07ff 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1210,20 +1210,36 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() // Set Token::variable pointer for array member variable // Since it doesn't point at a fixed location it doesn't have varid - if (tok->variable() != nullptr && - (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER)) && - Token::Match(tok, "%name% [|.")) { - - Token *tok2 = tok->next(); - // Locate "]" - while (tok2 && tok2->str() == "[") - tok2 = tok2->link()->next(); - - Token *membertok = nullptr; - if (Token::Match(tok2, ". %name%")) - membertok = tok2->next(); - else if (Token::Match(tok2, ") . %name%") && tok->strAt(-1) == "(") - membertok = tok2->tokAt(2); + const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER)); + const bool isArrayAccess = isVar && Token::simpleMatch(tok->astParent(), "["); + const bool isDirectAccess = isVar && !isArrayAccess && Token::simpleMatch(tok->astParent(), "."); + const bool isDerefAccess = isVar && !isDirectAccess && Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astParent()->astParent(), "."); + if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) { + Token* membertok{}; + if (isArrayAccess) { + membertok = const_cast(tok->astParent()); + while (Token::simpleMatch(membertok, "[")) + membertok = membertok->astParent(); + if (membertok) + membertok = membertok->astOperand2(); + } + else if (isDirectAccess) { + membertok = const_cast(tok->astParent()->astOperand2()); + if (membertok == tok) { + Token* gptok = const_cast(tok->astParent()->astParent()); + if (Token::simpleMatch(gptok, ".")) // chained access + membertok = gptok->astOperand2(); + else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), ".")) + membertok = gptok->astParent()->astOperand2(); + } + } + else { // isDerefAccess + membertok = const_cast(tok->astParent()); + while (Token::simpleMatch(membertok, "*")) + membertok = membertok->astParent(); + if (membertok) + membertok = membertok->astOperand2(); + } if (membertok) { const Variable *var = tok->variable(); diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index db4cafbad..8b12b73cd 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -1629,8 +1629,8 @@ private: ASSERT_EQUALS("", errout.str()); } - void structmember19() { // #10826 - checkStructMemberUsage("class C {};\n" + void structmember19() { + checkStructMemberUsage("class C {};\n" // #10826 "struct S {\n" " char* p;\n" " std::string str;\n" @@ -1653,6 +1653,54 @@ private: "[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("struct S {\n" + " struct T {\n" + " int i;\n" + " } t[2];\n" + "};\n" + "S s[1];\n" + "int f() {\n" + " return s[0].t[1].i;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "struct T { S s; };\n" + "int f(const T** tp) {\n" + " return tp[0]->s.a;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "int f(const S* sp) {\n" + " return (*sp).a; \n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "int f(const S** spp) {\n" + " return spp[0]->a;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "int f(const S** spp) {\n" + " return spp[0][0].a;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "int f(const S* sp) {\n" + " return sp[0].a;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("struct S { int a; };\n" + "int f(const S* sp) {\n" + " return sp->a;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") {