diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 28bd714e0..da847a439 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -140,7 +140,7 @@ void CheckLeakAutoVar::check() const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; - if (scope->hasInlineFunction()) + if (scope->hasInlineOrLambdaFunction()) continue; // Empty variable info diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 5878dee10..bdbfc04e3 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -2177,7 +2177,7 @@ void CheckMemoryLeakInFunction::check() const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; - if (!scope->hasInlineFunction()) + if (!scope->hasInlineOrLambdaFunction()) checkScope(scope->classStart->next(), "", 0, scope->functionOf != nullptr, 1); } @@ -2197,7 +2197,7 @@ void CheckMemoryLeakInFunction::check() if (var->isPointer() && var->type() && !var->typeScope()) continue; - if (var->scope()->hasInlineFunction()) + if (var->scope()->hasInlineOrLambdaFunction()) continue; unsigned int sz = _tokenizer->sizeOfType(var->typeStartToken()); diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 1e66435fc..d9ab8b367 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1136,6 +1136,11 @@ void CheckUnusedVar::checkFunctionVariableUsage() for (std::size_t i = 0; i < functions; ++i) { const Scope * scope = symbolDatabase->functionScopes[i]; + // Bailout when there are lambdas or inline functions + // TODO: Handle lambdas and inline functions properly + if (scope->hasInlineOrLambdaFunction()) + continue; + // varId, usage {read, write, modified} Variables variables; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 7f209ef1e..0570f61a4 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3493,13 +3493,16 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty return nullptr; } -bool Scope::hasInlineFunction() const +bool Scope::hasInlineOrLambdaFunction() const { for (std::list::const_iterator it = nestedList.begin(); it != nestedList.end(); ++it) { const Scope *s = *it; // Inline function if (s->type == Scope::eUnconditional && Token::Match(s->classStart->previous(), ") {")) return true; + // Lambda function + if (s->type == Scope::eLambda) + return true; } return false; } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index b2744d2ba..2b88e2fc7 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -899,7 +899,7 @@ public: } // Is there lambda/inline function(s) in this scope? - bool hasInlineFunction() const; + bool hasInlineOrLambdaFunction() const; /** * @brief find a function diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 47eb96855..7d90d85fe 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -168,6 +168,8 @@ private: TEST_CASE(crash1); TEST_CASE(crash2); TEST_CASE(usingNamespace); // #4585 + + TEST_CASE(lambdaFunction); // #5078 } void checkStructMemberUsage(const char code[]) { @@ -3192,38 +3194,6 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - functionVariableUsage("void foo() {\n" - " int i = -1;\n" - " int a[] = {1,2,3};\n" - " FOREACH_X (int x, a) {\n" - " i = x;\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'i' is assigned a value that is never used.\n", errout.str()); - - functionVariableUsage("void foo() {\n" - " int i = -1;\n" - " int a[] = {1,2,3};\n" - " X (int x, a) {\n" - " if (i==x) return x;\n" - " i = x;\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:6]: (style) Variable 'i' is assigned a value that is never used.\n", errout.str()); - - // #4956 - assignment in for_each - functionVariableUsage("void f(std::vector ints) {\n" - " int x = 0;\n" - " std::for_each(ints.begin(), ints.end(), [&x](int i){ dostuff(x); x = i; });\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - functionVariableUsage("void f(std::vector ints) {\n" - " int x = 0;\n" - " std::for_each(ints.begin(), ints.end(), [&x](int i){ x += i; });\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); - // #5154 - MSVC 'for each' functionVariableUsage("void f() {\n" " std::map ints;\n" @@ -3969,6 +3939,38 @@ private: "}"); // #4585 ASSERT_EQUALS("", errout.str()); } + + void lambdaFunction() { + // #7026 + functionVariableUsage("void f() {\n" + " bool first = true;\n" + "\n" + " auto do_something = [&first]() {\n" + " if (first) {\n" + " first = false;\n" + " } else {\n" + " dostuff();\n" + " }\n" + " };\n" + " do_something();\n" + " do_something();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + + // #4956 - assignment in for_each + functionVariableUsage("void f(std::vector ints) {\n" + " int x = 0;\n" + " std::for_each(ints.begin(), ints.end(), [&x](int i){ dostuff(x); x = i; });\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("void f(std::vector ints) {\n" + " int x = 0;\n" + " 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()); + } }; REGISTER_TEST(TestUnusedVar)