Skip to content

Commit

Permalink
Partial fix for #8433 FN unusedVariable not detected when there is la…
Browse files Browse the repository at this point in the history
…mbda (regression) (#6685)
  • Loading branch information
chrchr-github authored Aug 12, 2024
1 parent c3fc22a commit 5fecde1
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 7 deletions.
11 changes: 9 additions & 2 deletions lib/checkunusedvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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())
Expand Down
14 changes: 10 additions & 4 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand Down
2 changes: 1 addition & 1 deletion lib/symboldatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions test/testunusedvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>& v) {\n"
" auto it = std::find_if(v.begin(), v.end(), [&](int i) { return i > 0 && i < 7; });\n"
" std::unordered_map<std::string, std::vector<int*>> exprs;\n"
" return *it;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: exprs\n", errout_str());
}

void namespaces() { // #7557
Expand Down

0 comments on commit 5fecde1

Please sign in to comment.