diff --git a/Makefile b/Makefile index fbb27b23b..7c83f4c93 100644 --- a/Makefile +++ b/Makefile @@ -572,7 +572,7 @@ $(libcppdir)/token.o: lib/token.cpp lib/astutils.h lib/config.h lib/errortypes.h $(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/tokenize.o $(libcppdir)/tokenize.cpp -$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h +$(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/tokenlist.o $(libcppdir)/tokenlist.cpp $(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h @@ -605,7 +605,7 @@ test/test64bit.o: test/test64bit.cpp lib/check.h lib/check64bit.h lib/color.h li test/testassert.o: test/testassert.cpp lib/check.h lib/checkassert.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testassert.o test/testassert.cpp -test/testastutils.o: test/testastutils.cpp lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h +test/testastutils.o: test/testastutils.cpp lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testastutils.o test/testastutils.cpp test/testautovariables.o: test/testautovariables.cpp lib/check.h lib/checkautovariables.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h diff --git a/lib/astutils.cpp b/lib/astutils.cpp index bcfbc7bc5..e34aa9586 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1929,6 +1929,19 @@ bool isReturnScope(const Token* const endToken, const Library* library, const To return false; } +bool isWithinScope(const Token* tok, const Variable* var, Scope::ScopeType type) +{ + if (!tok || !var) + return false; + const Scope* scope = tok->scope(); + while (scope && scope != var->scope()) { + if (scope->type == type) + return true; + scope = scope->nestedIn; + } + return false; +} + bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings *settings, bool *inconclusive) { if (!tok) diff --git a/lib/astutils.h b/lib/astutils.h index f760cebd5..2107a4658 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -30,6 +30,7 @@ #include "config.h" #include "errortypes.h" +#include "symboldatabase.h" class Function; class Library; @@ -238,6 +239,11 @@ bool isReturnScope(const Token* const endToken, const Token** unknownFunc = nullptr, bool functionScope = false); +/** Is tok within a scope of the given type, nested within var's scope? */ +bool isWithinScope(const Token* tok, + const Variable* var, + Scope::ScopeType type); + /// Return the token to the function and the argument number const Token * getTokenArgumentFunction(const Token * tok, int& argn); Token* getTokenArgumentFunction(Token* tok, int& argn); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7b59a9aa9..c5d9e31b7 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -958,7 +958,7 @@ void CheckOther::checkVariableScope() bool reduce = true; bool used = false; // Don't warn about unused variables for (; tok && tok != var->scope()->bodyEnd; tok = tok->next()) { - if (tok->str() == "{" && tok->scope() != tok->previous()->scope() && !tok->isExpandedMacro() && tok->scope()->type != Scope::eLambda) { + if (tok->str() == "{" && tok->scope() != tok->previous()->scope() && !tok->isExpandedMacro() && !isWithinScope(tok, var, Scope::ScopeType::eLambda)) { if (used) { bool used2 = false; if (!checkInnerScope(tok, var, used2) || used2) { diff --git a/test/testother.cpp b/test/testother.cpp index 646c5cef4..f0be96323 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -97,6 +97,7 @@ private: TEST_CASE(varScope27); // #7733 - #if TEST_CASE(varScope28); // #10527 TEST_CASE(varScope29); // #10888 + TEST_CASE(varScope30); // #8541 TEST_CASE(oldStylePointerCast); TEST_CASE(invalidPointerCast); @@ -1347,6 +1348,22 @@ private: ASSERT_EQUALS("[test.cpp:2]: (style) The scope of the variable 's' can be reduced.\n", errout.str()); } + void varScope30() { // #8541 + check("bool f(std::vector& v, int i) {\n" + " int n = 0;\n" + " bool b = false;\n" + " std::for_each(v.begin(), v.end(), [&](int j) {\n" + " if (j == i) {\n" + " ++n;\n" + " if (n > 5)\n" + " b = true;\n" + " }\n" + " });\n" + " return b;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + #define checkOldStylePointerCast(code) checkOldStylePointerCast_(code, __FILE__, __LINE__) void checkOldStylePointerCast_(const char code[], const char* file, int line) { // Clear the error buffer..