diff --git a/cfg/cppcheck-cfg.rng b/cfg/cppcheck-cfg.rng index 1f7b37de2..df57b95af 100644 --- a/cfg/cppcheck-cfg.rng +++ b/cfg/cppcheck-cfg.rng @@ -551,6 +551,9 @@ + + + diff --git a/cfg/std.cfg b/cfg/std.cfg index 2dc34f5fe..86dede187 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -8664,16 +8664,16 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init - std::insert_iterator - std::lock_guard - std::unique_lock - std::shared_lock std::fstream std::wfstream std::ofstream std::wofstream std::basic_fstream std::basic_ofstream + std::insert_iterator + std::lock_guard + std::unique_lock + std::shared_lock std::pair std::exception std::logic_error diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 43cc9a06e..ac09970f5 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2077,7 +2077,7 @@ void CheckOther::checkMisusedScopedObject() const Token* endTok = tok; if (Token::Match(endTok, "%name% <")) endTok = endTok->linkAt(1); - if (Token::Match(endTok, "%name%|> (|{") && Token::Match(endTok->linkAt(1), ")|} ; !!}") && + if (Token::Match(endTok, "%name%|> (|{") && Token::Match(endTok->linkAt(1), ")|} ;") && !Token::simpleMatch(endTok->next()->astParent(), ";")) { // for loop condition return tok; } @@ -2085,7 +2085,8 @@ void CheckOther::checkMisusedScopedObject() }; auto isLibraryConstructor = [&](const Token* tok, const std::string& typeStr) -> bool { - if (mSettings->library.getTypeCheck("unusedvar", typeStr) == Library::TypeCheck::check) + const Library::TypeCheck typeCheck = mSettings->library.getTypeCheck("unusedvar", typeStr); + if (typeCheck == Library::TypeCheck::check || typeCheck == Library::TypeCheck::checkFiniteLifetime) return true; return mSettings->library.detectContainerOrIterator(tok); }; diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 6c8562d6f..7340dd5c3 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1268,6 +1268,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() case Library::TypeCheck::check: break; case Library::TypeCheck::suppress: + case Library::TypeCheck::checkFiniteLifetime: continue; } } @@ -1365,6 +1366,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() case Library::TypeCheck::check: break; case Library::TypeCheck::suppress: + case Library::TypeCheck::checkFiniteLifetime: error = false; } } diff --git a/lib/library.cpp b/lib/library.cpp index 1ab7e34f9..35b6618be 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -553,6 +553,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) mTypeChecks[std::pair(checkName, typeName)] = TypeCheck::check; else if (checkTypeName == "suppress") mTypeChecks[std::pair(checkName, typeName)] = TypeCheck::suppress; + else if (checkTypeName == "checkFiniteLifetime") + mTypeChecks[std::pair(checkName, typeName)] = TypeCheck::checkFiniteLifetime; } } } diff --git a/lib/library.h b/lib/library.h index 1e9ad3325..333c1d453 100644 --- a/lib/library.h +++ b/lib/library.h @@ -554,7 +554,11 @@ public: static bool isContainerYield(const Token * const cond, Library::Container::Yield y, const std::string& fallback=emptyString); /** Suppress/check a type */ - enum class TypeCheck { def, check, suppress }; + enum class TypeCheck { def, + check, + suppress, + checkFiniteLifetime, // (unusedvar) object has side effects, but immediate destruction is wrong + }; TypeCheck getTypeCheck(std::string check, std::string typeName) const; private: diff --git a/test/testother.cpp b/test/testother.cpp index 98f6b6b9f..68922a7e0 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -138,7 +138,6 @@ private: TEST_CASE(testMisusedScopeObjectDoesNotPickPureC); TEST_CASE(testMisusedScopeObjectDoesNotPickNestedClass); TEST_CASE(testMisusedScopeObjectInConstructor); - TEST_CASE(testMisusedScopeObjectNoCodeAfter); TEST_CASE(testMisusedScopeObjectStandardType); TEST_CASE(testMisusedScopeObjectNamespace); TEST_CASE(trac2071); @@ -5044,14 +5043,6 @@ private: ASSERT_EQUALS("[test.cpp:4]: (style) Instance of 'Foo' object is destroyed immediately.\n", errout.str()); } - void testMisusedScopeObjectNoCodeAfter() { - check("class Foo {};\n" - "void f() {\n" - " Foo();\n" // No code after class => don't warn - "}", "test.cpp"); - ASSERT_EQUALS("", errout.str()); - } - void testMisusedScopeObjectStandardType() { check("int g();\n" "void f(int i) {\n" @@ -5111,6 +5102,15 @@ private: "[test.cpp:3]: (style) Instance of 'std::string' object is destroyed immediately.\n" "[test.cpp:4]: (style) Instance of 'std::pair' object is destroyed immediately.\n", errout.str()); + + check("struct S {\n" // #10083 + " void f() {\n" + " std::lock_guard(m);\n" + " }\n" + " std::mutex m;\n" + "}\n", "test.cpp"); + ASSERT_EQUALS("[test.cpp:3]: (style) Instance of 'std::lock_guard' object is destroyed immediately.\n", + errout.str()); } void trac2084() {