Skip to content

Commit da3aa83

Browse files
committed
Fix danmar#7458 (FP unusedStructMember with struct in union)
1 parent 99523e1 commit da3aa83

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

lib/checkunusedvar.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,57 @@ void CheckUnusedVar::checkStructMemberUsage()
15991599
if (bailout)
16001600
continue;
16011601

1602+
// #7458 - if struct is declared inside union and any struct member is used,
1603+
// then don't warn about other struct members
1604+
bool structInUnionWithUsedMember = false;
1605+
if (scope.type == ScopeType::eStruct && scope.nestedIn && scope.nestedIn->type == ScopeType::eUnion) {
1606+
for (const Variable &unionVar : scope.varlist) {
1607+
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
1608+
if (tok->variable() == &unionVar && tok != unionVar.nameToken()) {
1609+
structInUnionWithUsedMember = true;
1610+
break;
1611+
}
1612+
}
1613+
if (structInUnionWithUsedMember)
1614+
break;
1615+
}
1616+
}
1617+
1618+
// #7458 - if this is a union and any member is used, don't warn about other members
1619+
bool unionWithUsedMember = false;
1620+
if (scope.type == ScopeType::eUnion) {
1621+
// Check if any direct member of the union is used
1622+
for (const Variable &unionVar : scope.varlist) {
1623+
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
1624+
if (tok->variable() == &unionVar && tok != unionVar.nameToken()) {
1625+
unionWithUsedMember = true;
1626+
break;
1627+
}
1628+
}
1629+
if (unionWithUsedMember)
1630+
break;
1631+
}
1632+
// Also check if any member of nested structs in this union is used
1633+
if (!unionWithUsedMember) {
1634+
for (const Scope *nestedScope : scope.nestedList) {
1635+
if (nestedScope->type == ScopeType::eStruct) {
1636+
for (const Variable &structVar : nestedScope->varlist) {
1637+
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
1638+
if (tok->variable() == &structVar && tok != structVar.nameToken()) {
1639+
unionWithUsedMember = true;
1640+
break;
1641+
}
1642+
}
1643+
if (unionWithUsedMember)
1644+
break;
1645+
}
1646+
if (unionWithUsedMember)
1647+
break;
1648+
}
1649+
}
1650+
}
1651+
}
1652+
16021653
for (const Variable &var : scope.varlist) {
16031654
// only warn for variables without side effects
16041655
if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type()))
@@ -1612,6 +1663,14 @@ void CheckUnusedVar::checkStructMemberUsage()
16121663
if (mTokenizer->isVarUsedInTemplate(var.declarationId()))
16131664
continue;
16141665

1666+
// Skip reporting unused members if this struct is in a union and any member is used
1667+
if (structInUnionWithUsedMember)
1668+
continue;
1669+
1670+
// Skip reporting unused members if this is a union and any member is used
1671+
if (unionWithUsedMember)
1672+
continue;
1673+
16151674
// Check if the struct member variable is used anywhere in the file
16161675
bool use = false;
16171676
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {

test/testunusedvar.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,20 @@ class TestUnusedVar : public TestFixture {
14091409
ASSERT_EQUALS("[test.cpp:3:9]: (style) union member 'abc::a' is never used. [unusedStructMember]\n"
14101410
"[test.cpp:4:9]: (style) union member 'abc::b' is never used. [unusedStructMember]\n"
14111411
"[test.cpp:5:9]: (style) union member 'abc::c' is never used. [unusedStructMember]\n", errout_str());
1412+
1413+
// #7458 - union with anonymous struct should not cause false positive
1414+
checkStructMemberUsage("union DoubleInt {\n"
1415+
" double asDouble;\n"
1416+
" uint64_t asInt;\n"
1417+
" struct {\n"
1418+
" uint32_t lo, hi;\n"
1419+
" } asIntel;\n"
1420+
"};\n"
1421+
"void f() {\n"
1422+
" union DoubleInt di;\n"
1423+
" di.asIntel.hi = 3;\n"
1424+
"}");
1425+
ASSERT_EQUALS("", errout_str());
14121426
}
14131427

14141428
void structmember2() {

0 commit comments

Comments
 (0)