Fix #10057 "statement without effect" / #4779 FN unusedScopedObject does not work for classes in different namespace (#4500)
* Partial fix for #10057 unused variable without assignment not detected * Add test for #9672 * Fix #4779 FN unusedScopedObject does not work for classes in different namespace * Merge * Fix #10057 "statement without effect" (unused variable without assignment) not detected * Format
This commit is contained in:
parent
dc03a50414
commit
2808fc615e
|
@ -2063,20 +2063,45 @@ void CheckOther::checkMisusedScopedObject()
|
|||
if (!mSettings->severity.isEnabled(Severity::style))
|
||||
return;
|
||||
|
||||
const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||
auto getConstructorTok = [](const Token* tok, std::string& typeStr) -> const Token* {
|
||||
if (!Token::Match(tok, "[;{}] %name%"))
|
||||
return nullptr;
|
||||
tok = tok->next();
|
||||
typeStr.clear();
|
||||
while (Token::Match(tok, "%name% ::")) {
|
||||
typeStr += tok->str();
|
||||
typeStr += "::";
|
||||
tok = tok->tokAt(2);
|
||||
}
|
||||
typeStr += tok->str();
|
||||
const Token* endTok = tok;
|
||||
if (Token::Match(endTok, "%name% <"))
|
||||
endTok = endTok->linkAt(1);
|
||||
if (Token::Match(endTok, "%name%|> (|{") && Token::Match(endTok->linkAt(1), ")|} ; !!}") &&
|
||||
!Token::simpleMatch(endTok->next()->astParent(), ";")) { // for loop condition
|
||||
return tok;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto isLibraryConstructor = [&](const Token* tok, const std::string& typeStr) -> bool {
|
||||
if (mSettings->library.getTypeCheck("unusedvar", typeStr) == Library::TypeCheck::check)
|
||||
return true;
|
||||
return mSettings->library.detectContainerOrIterator(tok);
|
||||
};
|
||||
|
||||
const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||
std::string typeStr;
|
||||
for (const Scope * scope : symbolDatabase->functionScopes) {
|
||||
for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
|
||||
if ((tok->next()->type() || tok->next()->isStandardType() || (tok->next()->function() && tok->next()->function()->isConstructor())) // TODO: The rhs of || should be removed; It is a workaround for a symboldatabase bug
|
||||
&& Token::Match(tok, "[;{}] %name% (|{")
|
||||
&& Token::Match(tok->linkAt(2), ")|} ; !!}")
|
||||
&& (!tok->next()->function() || // is not a function on this scope
|
||||
tok->next()->function()->isConstructor()) // or is function in this scope and it's a ctor
|
||||
&& !Token::simpleMatch(tok->tokAt(2)->astParent(), ";") // for loop condition
|
||||
&& tok->next()->str() != "void") {
|
||||
if (const Token* arg = tok->tokAt(2)->astOperand2()) {
|
||||
const Token* ctorTok = getConstructorTok(tok, typeStr);
|
||||
if (ctorTok && (((ctorTok->type() || ctorTok->isStandardType() || (ctorTok->function() && ctorTok->function()->isConstructor())) // TODO: The rhs of || should be removed; It is a workaround for a symboldatabase bug
|
||||
&& (!ctorTok->function() || ctorTok->function()->isConstructor()) // // is not a function on this scope or is function in this scope and it's a ctor
|
||||
&& ctorTok->str() != "void") || isLibraryConstructor(tok->next(), typeStr))) {
|
||||
if (const Token* arg = ctorTok->next()->astOperand2()) {
|
||||
if (!isConstStatement(arg, mTokenizer->isCPP()))
|
||||
continue;
|
||||
if (tok->strAt(2) == "(") {
|
||||
if (ctorTok->strAt(1) == "(") {
|
||||
if (arg->varId()) // TODO: check if this is a declaration
|
||||
continue;
|
||||
const Token* rml = nextAfterAstRightmostLeaf(arg);
|
||||
|
@ -2085,7 +2110,7 @@ void CheckOther::checkMisusedScopedObject()
|
|||
}
|
||||
}
|
||||
tok = tok->next();
|
||||
misusedScopeObjectError(tok, tok->str());
|
||||
misusedScopeObjectError(ctorTok, typeStr);
|
||||
tok = tok->next();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,6 +140,7 @@ private:
|
|||
TEST_CASE(testMisusedScopeObjectInConstructor);
|
||||
TEST_CASE(testMisusedScopeObjectNoCodeAfter);
|
||||
TEST_CASE(testMisusedScopeObjectStandardType);
|
||||
TEST_CASE(testMisusedScopeObjectNamespace);
|
||||
TEST_CASE(trac2071);
|
||||
TEST_CASE(trac2084);
|
||||
TEST_CASE(trac3693);
|
||||
|
@ -5088,6 +5089,30 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void testMisusedScopeObjectNamespace() {
|
||||
check("namespace M {\n" // #4479
|
||||
" namespace N {\n"
|
||||
" struct S {};\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"int f() {\n"
|
||||
" M::N::S();\n"
|
||||
" return 0;\n"
|
||||
"}\n", "test.cpp");
|
||||
ASSERT_EQUALS("[test.cpp:7]: (style) Instance of 'M::N::S' object is destroyed immediately.\n", errout.str());
|
||||
|
||||
check("void f() {\n" // #10057
|
||||
" std::string(\"abc\");\n"
|
||||
" std::string{ \"abc\" };\n"
|
||||
" std::pair<int, int>(1, 2);\n"
|
||||
" (void)0;\n"
|
||||
"}\n", "test.cpp");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (style) Instance of 'std::string' object is destroyed immediately.\n"
|
||||
"[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());
|
||||
}
|
||||
|
||||
void trac2084() {
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
|
|
Loading…
Reference in New Issue