Merge pull request #2791 from pfultz2/known-empty-container-constructor-modified

Fix issue 9869: False positive: knownEmptyContainer when passed to constructor
This commit is contained in:
Daniel Marjamäki 2020-09-10 07:37:21 +02:00 committed by GitHub
commit 43d643184e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 44 deletions

View File

@ -1386,31 +1386,33 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
return tok; return tok;
} }
static const Variable* getArgumentVar(const Token* tok, int argnr) static std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
{ {
std::vector<const Variable*> result;
if (!tok) if (!tok)
return nullptr; return result;
if (tok->function()) if (tok->function())
return tok->function()->getArgumentVar(argnr); return {tok->function()->getArgumentVar(argnr)};
if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) { if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) {
const bool constructor = tok->variable() && tok->variable()->nameToken() == tok;
const Type* type = Token::typeOf(tok); const Type* type = Token::typeOf(tok);
if (!type) if (!type)
return nullptr; return result;
const Scope* typeScope = type->classScope; const Scope* typeScope = type->classScope;
if (!typeScope) if (!typeScope)
return nullptr; return result;
const int argCount = numberOfArguments(tok); const int argCount = numberOfArguments(tok);
for (const Function &function : typeScope->functionList) { for (const Function &function : typeScope->functionList) {
if (function.isConstructor())
continue;
if (function.argCount() < argCount) if (function.argCount() < argCount)
continue; continue;
if (!Token::simpleMatch(function.token, "operator()")) if (constructor && !function.isConstructor())
continue; continue;
return function.getArgumentVar(argnr); if (!constructor && !Token::simpleMatch(function.token, "operator()"))
continue;
result.push_back(function.getArgumentVar(argnr));
} }
} }
return nullptr; return result;
} }
static bool isCPPCastKeyword(const Token* tok) static bool isCPPCastKeyword(const Token* tok)
@ -1444,26 +1446,6 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
parenTok = parenTok->link()->next(); parenTok = parenTok->link()->next();
const bool possiblyPassedByReference = (parenTok->next() == tok1 || Token::Match(tok1->previous(), ", %name% [,)}]")); const bool possiblyPassedByReference = (parenTok->next() == tok1 || Token::Match(tok1->previous(), ", %name% [,)}]"));
// Constructor call
if (tok->variable() && tok->variable()->nameToken() == tok) {
// Find constructor..
const int argCount = numberOfArguments(tok);
const Scope *typeScope = tok->variable()->typeScope();
if (typeScope) {
for (const Function &function : typeScope->functionList) {
if (!function.isConstructor() || function.argCount() < argCount)
continue;
const Variable *arg = function.getArgumentVar(argnr);
if (arg && arg->isReference() && !arg->isConst())
return true;
}
return false;
}
if (inconclusive)
*inconclusive = true;
return false;
}
if (!tok->function() && !tok->variable() && Token::Match(tok, "%name%")) { if (!tok->function() && !tok->variable() && Token::Match(tok, "%name%")) {
// Check if direction (in, out, inout) is specified in the library configuration and use that // Check if direction (in, out, inout) is specified in the library configuration and use that
if (!addressOf && settings) { if (!addressOf && settings) {
@ -1494,22 +1476,26 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
return true; return true;
} }
const Variable *arg = getArgumentVar(tok, argnr); std::vector<const Variable*> args = getArgumentVars(tok, argnr);
if (!arg) { bool conclusive = false;
if (inconclusive) for(const Variable *arg:args) {
*inconclusive = true; if (!arg)
return false; continue;
} conclusive = true;
if (addressOf || (indirect > 0 && arg->isPointer())) {
if (addressOf || (indirect > 0 && arg->isPointer())) { if (!arg->isConst())
if (!arg->isConst()) return true;
return true; // If const is applied to the pointer, then the value can still be modified
// If const is applied to the pointer, then the value can still be modified if (Token::simpleMatch(arg->typeEndToken(), "* const"))
if (Token::simpleMatch(arg->typeEndToken(), "* const")) return true;
}
if (!arg->isConst() && arg->isReference())
return true; return true;
} }
if (!conclusive && inconclusive) {
return !arg->isConst() && arg->isReference(); *inconclusive = true;
}
return false;
} }
bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, bool cpp, int depth) bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, bool cpp, int depth)

View File

@ -4701,6 +4701,18 @@ private:
"}\n", "}\n",
true); true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("struct A {\n"
" explicit A(std::vector<int>*);\n"
"};\n"
"A f() {\n"
" std::vector<int> v;\n"
" A a(&v);\n"
" for(auto&& x:v) {}\n"
" return a;\n"
"}\n",
true);
ASSERT_EQUALS("", errout.str());
} }
void checkMutexes() { void checkMutexes() {