Skip to content

Commit

Permalink
simple bailout for structured binding
Browse files Browse the repository at this point in the history
  • Loading branch information
ludviggunne committed Jan 5, 2025
1 parent 2179f04 commit 4793d2a
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 29 deletions.
38 changes: 15 additions & 23 deletions lib/checkunusedvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1534,34 +1534,29 @@ void CheckUnusedVar::checkStructMemberUsage()
if (bailout)
continue;

// Structured binding assigned to variable
std::vector<nonneg int> structBindUsage;
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
if (!Token::Match(tok, "] %assign% %var%"))
// Bailout if struct is used in structured binding
for (const Variable *var : symbolDatabase->variableList()) {
if (!var || !Token::simpleMatch(var->typeStartToken(), "auto"))
continue;

const Variable *const var = tok->tokAt(2)->variable();
if (!var || var->type()->classScope != &scope)
const Token *tok = var->nameToken()->previous();
if (!Token::simpleMatch(tok, "["))
continue;

const Token *const startBracket = tok->link();
if (!startBracket ||
(!Token::Match(startBracket->tokAt(-2), "auto &|&&") &&
!Token::simpleMatch(startBracket->previous(), "auto")))
tok = tok->link();
if (!Token::Match(tok, "] %assign%"))
continue;

std::size_t bindCount = 1;
const Token *comma = startBracket->astOperand2();
while (Token::simpleMatch(comma, ",")) {
++bindCount;
comma = comma->astOperand1();
}
tok = tok->next()->astOperand2();
const ValueType *valueType = tok->valueType();

auto end = scope.varlist.cbegin();
std::advance(end, bindCount);
for (auto it = scope.varlist.cbegin(); it != end; ++it)
structBindUsage.push_back(it->index());
if (valueType && valueType->typeScope == &scope) {
bailout = true;
break;
}
}
if (bailout)
continue;

for (const Variable &var : scope.varlist) {
// only warn for variables without side effects
Expand All @@ -1570,9 +1565,6 @@ void CheckUnusedVar::checkStructMemberUsage()
if (isInherited && !var.isPrivate())
continue;

if (std::find(structBindUsage.cbegin(), structBindUsage.cend(), var.index()) != structBindUsage.cend())
continue;

// Check if the struct member variable is used anywhere in the file
bool use = false;
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
Expand Down
13 changes: 7 additions & 6 deletions test/testunusedvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2036,13 +2036,14 @@ class TestUnusedVar : public TestFixture {
ASSERT_EQUALS("", errout_str());

checkStructMemberUsage("struct S { int a, b; };\n"
"S f() {\n"
" S s{};\n"
" auto& [x] = s;\n"
" x = 1;\n"
" return s;\n"
"struct T { S s; };\n"
"T f() {\n"
" T t{};\n"
" auto& [x, y] = t.s;\n"
" x = y = 1;\n"
" return t;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:1]: (style) struct member 'S::b' is never used.\n", errout_str());
ASSERT_EQUALS("", errout_str());
}

void functionVariableUsage_(const char* file, int line, const char code[], bool cpp = true) {
Expand Down

0 comments on commit 4793d2a

Please sign in to comment.