From 4c85ac0d7bb9749f1ac77c6969561724a4433594 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 12 Mar 2022 06:16:29 +0100 Subject: [PATCH] Fix #10852 FP unused struct member (inner struct in C code) (#3890) * Fix #10852 FP unused struct member (inner struct in C code) * Redundant findType() call, add test --- lib/symboldatabase.cpp | 24 +++++++++++++++++++++++- lib/symboldatabase.h | 2 +- test/testunusedvar.cpp | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 479069e64..97d849f10 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -5423,11 +5423,16 @@ const Scope *SymbolDatabase::findScopeByName(const std::string& name) const //--------------------------------------------------------------------------- -const Scope *Scope::findRecordInNestedList(const std::string & name) const +const Scope *Scope::findRecordInNestedList(const std::string & name, bool isC) const { for (const Scope* scope: nestedList) { if (scope->className == name && scope->type != eFunction) return scope; + if (isC) { + const Scope* nestedScope = scope->findRecordInNestedList(name, isC); + if (nestedScope) + return nestedScope; + } } const Type * nested_type = findType(name); @@ -5546,6 +5551,23 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc if (startTok->str() == startScope->className && startScope->isClassOrStruct() && startTok->strAt(1) != "::") return startScope->definedType; + if (mTokenizer->isC()) { + const Scope* scope = startScope; + while (scope) { + if (startTok->str() == scope->className && scope->isClassOrStruct()) + return scope->definedType; + const Scope* typeScope = scope->findRecordInNestedList(startTok->str(), /*isC*/ true); + if (typeScope) { + if (startTok->str() == typeScope->className && typeScope->isClassOrStruct()) { + if (const Type* type = typeScope->definedType) + return type; + } + } + scope = scope->nestedIn; + } + return nullptr; + } + const Scope* start_scope = startScope; // absolute path - directly start in global scope diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 3d0a4be89..34d639fcd 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1129,7 +1129,7 @@ public: */ const Function *findFunction(const Token *tok, bool requireConst=false) const; - const Scope *findRecordInNestedList(const std::string & name) const; + const Scope *findRecordInNestedList(const std::string & name, bool isC = false) const; Scope *findRecordInNestedList(const std::string & name) { return const_cast(const_cast(this)->findRecordInNestedList(name)); } diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 4ee0711b1..d937b9d88 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -66,7 +66,7 @@ private: TEST_CASE(structmember16); // #10485 TEST_CASE(structmember17); // #10591 TEST_CASE(structmember18); // #10684 - TEST_CASE(structmember19); // #10826, #10848 + TEST_CASE(structmember19); // #10826, #10848, #10852 TEST_CASE(localvar1); TEST_CASE(localvar2); @@ -1710,6 +1710,37 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:1]: (style) struct member 'A::i' is never used.\n", errout.str()); + + settings.enforcedLang = Settings::C; + checkStructMemberUsage("struct A {\n" // #10852 + " struct B {\n" + " int x;\n" + " } b;\n" + "} a;\n" + "void f() {\n" + " struct B* pb = &a.b;\n" + " pb->x = 1;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + checkStructMemberUsage("union U {\n" + " struct A {\n" + " struct B {\n" + " int x;\n" + " } b;\n" + " } a;\n" + " struct C {\n" + " short s[2];\n" + " } c;\n" + "} u;\n" + "void f() {\n" + " struct B* pb = &u.a.b;\n" + " pb->x = 1;\n" + " struct C* pc = &u.c;\n" + " pc->s[0] = 1;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + settings.enforcedLang = Settings::None; } void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") {