diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index a64f9071dc1..ca91679c17a 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1534,6 +1534,40 @@ void CheckUnusedVar::checkStructMemberUsage() if (bailout) continue; + // Bailout if struct is used in structured binding + for (const Variable *var : symbolDatabase->variableList()) { + if (!var || !Token::Match(var->typeStartToken(), "auto &|&&| [ %varid%", var->declarationId())) + continue; + + const Token *tok = var->nameToken()->linkAt(-1); + if (Token::Match(tok, "] %assign%")) + { + tok = tok->next()->astOperand2(); + const ValueType *valueType = tok->valueType(); + + if (valueType && valueType->typeScope == &scope) { + bailout = true; + break; + } + } + + if (Token::simpleMatch(tok, "] :")) { + tok = tok->next()->astOperand2(); + const ValueType *valueType = tok->valueType(); + + if (!valueType->containerTypeToken) + continue; + + const Type *type = valueType->containerTypeToken->type(); + if (type && type->classScope == &scope) { + bailout = true; + break; + } + } + } + if (bailout) + continue; + for (const Variable &var : scope.varlist) { // only warn for variables without side effects if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type())) diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 74941464ea8..e6507e7304b 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -74,6 +74,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(structmember27); // #13367 TEST_CASE(structmember_macro); TEST_CASE(classmember); + TEST_CASE(structmemberStructuredBinding); // #13107 TEST_CASE(localvar1); TEST_CASE(localvar2); @@ -2024,6 +2025,30 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void structmemberStructuredBinding() { // #13107 + checkStructMemberUsage("struct S { int a, b; };\n" + "void f(S &s) {\n" + " auto& [x, y] = s;\n" + " x = y;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int a, b; };\n" + "struct T { S s; };\n" + "void f(T &t) {\n" + " auto& [x, y] = t.s;\n" + " x = y;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int a, b; };\n" + "void f(std::vector &sv) {\n" + " for (auto& [x, y] : sv)\n" + " x = y;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + void functionVariableUsage_(const char* file, int line, const char code[], bool cpp = true) { // Tokenize.. SimpleTokenizer tokenizer(settings, *this);