Skip to content

Commit cdc8cee

Browse files
authored
fix #13107: FP unusedStructMember with structured binding (#7177)
1 parent 46781df commit cdc8cee

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

lib/checkunusedvar.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,40 @@ void CheckUnusedVar::checkStructMemberUsage()
15341534
if (bailout)
15351535
continue;
15361536

1537+
// Bailout if struct is used in structured binding
1538+
for (const Variable *var : symbolDatabase->variableList()) {
1539+
if (!var || !Token::Match(var->typeStartToken(), "auto &|&&| [ %varid%", var->declarationId()))
1540+
continue;
1541+
1542+
const Token *tok = var->nameToken()->linkAt(-1);
1543+
if (Token::Match(tok, "] %assign%"))
1544+
{
1545+
tok = tok->next()->astOperand2();
1546+
const ValueType *valueType = tok->valueType();
1547+
1548+
if (valueType && valueType->typeScope == &scope) {
1549+
bailout = true;
1550+
break;
1551+
}
1552+
}
1553+
1554+
if (Token::simpleMatch(tok, "] :")) {
1555+
tok = tok->next()->astOperand2();
1556+
const ValueType *valueType = tok->valueType();
1557+
1558+
if (!valueType->containerTypeToken)
1559+
continue;
1560+
1561+
const Type *type = valueType->containerTypeToken->type();
1562+
if (type && type->classScope == &scope) {
1563+
bailout = true;
1564+
break;
1565+
}
1566+
}
1567+
}
1568+
if (bailout)
1569+
continue;
1570+
15371571
for (const Variable &var : scope.varlist) {
15381572
// only warn for variables without side effects
15391573
if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type()))

test/testunusedvar.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class TestUnusedVar : public TestFixture {
7474
TEST_CASE(structmember27); // #13367
7575
TEST_CASE(structmember_macro);
7676
TEST_CASE(classmember);
77+
TEST_CASE(structmemberStructuredBinding); // #13107
7778

7879
TEST_CASE(localvar1);
7980
TEST_CASE(localvar2);
@@ -2024,6 +2025,30 @@ class TestUnusedVar : public TestFixture {
20242025
ASSERT_EQUALS("", errout_str());
20252026
}
20262027

2028+
void structmemberStructuredBinding() { // #13107
2029+
checkStructMemberUsage("struct S { int a, b; };\n"
2030+
"void f(S &s) {\n"
2031+
" auto& [x, y] = s;\n"
2032+
" x = y;\n"
2033+
"}\n");
2034+
ASSERT_EQUALS("", errout_str());
2035+
2036+
checkStructMemberUsage("struct S { int a, b; };\n"
2037+
"struct T { S s; };\n"
2038+
"void f(T &t) {\n"
2039+
" auto& [x, y] = t.s;\n"
2040+
" x = y;\n"
2041+
"}\n");
2042+
ASSERT_EQUALS("", errout_str());
2043+
2044+
checkStructMemberUsage("struct S { int a, b; };\n"
2045+
"void f(std::vector<S> &sv) {\n"
2046+
" for (auto& [x, y] : sv)\n"
2047+
" x = y;\n"
2048+
"}\n");
2049+
ASSERT_EQUALS("", errout_str());
2050+
}
2051+
20272052
void functionVariableUsage_(const char* file, int line, const char code[], bool cpp = true) {
20282053
// Tokenize..
20292054
SimpleTokenizer tokenizer(settings, *this);

0 commit comments

Comments
 (0)