From 5fecde1ddafd9052d40294a5873eb1dbe55e7e0e Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:28:46 +0200 Subject: [PATCH] Partial fix for #8433 FN unusedVariable not detected when there is lambda (regression) (#6685) --- lib/checkunusedvar.cpp | 11 +++++++++-- lib/symboldatabase.cpp | 14 ++++++++++---- lib/symboldatabase.h | 2 +- test/testunusedvar.cpp | 7 +++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index d7290dc2578..f22987b77b1 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1183,8 +1183,8 @@ void CheckUnusedVar::checkFunctionVariableUsage() for (const Scope * scope : symbolDatabase->functionScopes) { // Bailout when there are lambdas or inline functions // TODO: Handle lambdas and inline functions properly - if (scope->hasInlineOrLambdaFunction()) - continue; + const Token* lambdaOrInlineStart{}; + const bool hasLambdaOrInline = scope->hasInlineOrLambdaFunction(&lambdaOrInlineStart); for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { if (findLambdaEndToken(tok)) @@ -1264,6 +1264,13 @@ void CheckUnusedVar::checkFunctionVariableUsage() const Variable *op1Var = op1tok ? op1tok->variable() : nullptr; if (!op1Var && Token::Match(tok, "(|{") && tok->previous() && tok->previous()->variable()) op1Var = tok->previous()->variable(); + if (hasLambdaOrInline) { + if (!op1Var || !lambdaOrInlineStart) + continue; + if (precedes(op1Var->nameToken(), lambdaOrInlineStart)) + continue; + } + std::string bailoutTypeName; if (op1Var) { if (op1Var->isReference() && op1Var->nameToken() != tok->astOperand1()) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f7393267ae6..df00fb60513 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -5514,16 +5514,22 @@ static bool hasEmptyCaptureList(const Token* tok) { return Token::simpleMatch(listTok, "[ ]"); } -bool Scope::hasInlineOrLambdaFunction() const +bool Scope::hasInlineOrLambdaFunction(const Token** tokStart) const { return std::any_of(nestedList.begin(), nestedList.end(), [&](const Scope* s) { // Inline function - if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {")) + if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {")) { + if (tokStart) + *tokStart = nullptr; // bailout for e.g. loop-like macros return true; + } // Lambda function - if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart)) + if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart)) { + if (tokStart) + *tokStart = s->bodyStart; return true; - if (s->hasInlineOrLambdaFunction()) + } + if (s->hasInlineOrLambdaFunction(tokStart)) return true; return false; }); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index f481034c609..170e2765536 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1120,7 +1120,7 @@ class CPPCHECKLIB Scope { } // Is there lambda/inline function(s) in this scope? - bool hasInlineOrLambdaFunction() const; + bool hasInlineOrLambdaFunction(const Token** tokStart = nullptr) const; /** * @brief find a function diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index e5d0b6ad99f..3d57b789c02 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -6980,6 +6980,13 @@ class TestUnusedVar : public TestFixture { " std::for_each(ints.begin(), ints.end(), [&x](int i){ x += i; });\n" "}"); TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x' is assigned a value that is never used.\n", "", errout_str()); + + functionVariableUsage("int f(const std::vector& v) {\n" + " auto it = std::find_if(v.begin(), v.end(), [&](int i) { return i > 0 && i < 7; });\n" + " std::unordered_map> exprs;\n" + " return *it;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: exprs\n", errout_str()); } void namespaces() { // #7557