Fix issue 9869: False positive: knownEmptyContainer when passed to constructor

This commit is contained in:
Paul 2020-09-09 22:23:42 -05:00
parent 48a6852a4a
commit 5033fb4418
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;
}
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)
return nullptr;
return result;
if (tok->function())
return tok->function()->getArgumentVar(argnr);
return {tok->function()->getArgumentVar(argnr)};
if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) {
const bool constructor = tok->variable() && tok->variable()->nameToken() == tok;
const Type* type = Token::typeOf(tok);
if (!type)
return nullptr;
return result;
const Scope* typeScope = type->classScope;
if (!typeScope)
return nullptr;
return result;
const int argCount = numberOfArguments(tok);
for (const Function &function : typeScope->functionList) {
if (function.isConstructor())
continue;
if (function.argCount() < argCount)
continue;
if (!Token::simpleMatch(function.token, "operator()"))
if (constructor && !function.isConstructor())
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)
@ -1444,26 +1446,6 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
parenTok = parenTok->link()->next();
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%")) {
// Check if direction (in, out, inout) is specified in the library configuration and use that
if (!addressOf && settings) {
@ -1494,22 +1476,26 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
return true;
}
const Variable *arg = getArgumentVar(tok, argnr);
if (!arg) {
if (inconclusive)
*inconclusive = true;
return false;
}
if (addressOf || (indirect > 0 && arg->isPointer())) {
if (!arg->isConst())
return true;
// If const is applied to the pointer, then the value can still be modified
if (Token::simpleMatch(arg->typeEndToken(), "* const"))
std::vector<const Variable*> args = getArgumentVars(tok, argnr);
bool conclusive = false;
for(const Variable *arg:args) {
if (!arg)
continue;
conclusive = true;
if (addressOf || (indirect > 0 && arg->isPointer())) {
if (!arg->isConst())
return true;
// If const is applied to the pointer, then the value can still be modified
if (Token::simpleMatch(arg->typeEndToken(), "* const"))
return true;
}
if (!arg->isConst() && arg->isReference())
return true;
}
return !arg->isConst() && arg->isReference();
if (!conclusive && inconclusive) {
*inconclusive = true;
}
return false;
}
bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, bool cpp, int depth)

View File

@ -4701,6 +4701,18 @@ private:
"}\n",
true);
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() {