Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions lib/astutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ std::vector<Token*> astFlatten(Token* tok, const char* op)
return result;
}

nonneg int astCount(const Token* tok, const char* op, int depth)
{
--depth;
if (!tok || depth < 0)
return 0;
if (tok->str() == op)
return astCount(tok->astOperand1(), op, depth) + astCount(tok->astOperand2(), op, depth);
else
return 1;
}

bool astHasToken(const Token* root, const Token * tok)
{
if (!root)
Expand Down Expand Up @@ -2583,7 +2594,24 @@ bool isExpressionChanged(const Token* expr, const Token* start, const Token* end
return result;
}

int numberOfArguments(const Token *start)
const Token* getArgumentStart(const Token* ftok)
{
const Token* tok = ftok;
if (Token::Match(tok, "%name% (|{"))
tok = ftok->next();
if (!Token::Match(tok, "(|{|["))
return nullptr;
const Token* startTok = tok->astOperand2();
if (!startTok && tok->next() != tok->link())
startTok = tok->astOperand1();
return startTok;
}

int numberOfArguments(const Token* ftok) {
return astCount(getArgumentStart(ftok), ",");
}

int numberOfArgumentsWithoutAst(const Token* start)
{
int arguments=0;
const Token* const openBracket = start->next();
Expand All @@ -2597,17 +2625,8 @@ int numberOfArguments(const Token *start)
return arguments;
}

std::vector<const Token *> getArguments(const Token *ftok)
{
const Token* tok = ftok;
if (Token::Match(tok, "%name% (|{"))
tok = ftok->next();
if (!Token::Match(tok, "(|{|["))
return std::vector<const Token *> {};
const Token *startTok = tok->astOperand2();
if (!startTok && tok->next() != tok->link())
startTok = tok->astOperand1();
return astFlatten(startTok, ",");
std::vector<const Token*> getArguments(const Token* ftok) {
return astFlatten(getArgumentStart(ftok), ",");
}

int getArgumentPos(const Variable* var, const Function* f)
Expand Down
9 changes: 8 additions & 1 deletion lib/astutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ const Token* findExpression(const Token* start, const nonneg int exprid);
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
std::vector<Token*> astFlatten(Token* tok, const char* op);

nonneg int astCount(const Token* tok, const char* op, int depth = 100);

bool astHasToken(const Token* root, const Token * tok);

bool astHasVar(const Token * tok, nonneg int varid);
Expand Down Expand Up @@ -310,11 +312,16 @@ bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive = nullptr)

bool isAliased(const Variable *var);

const Token* getArgumentStart(const Token* ftok);

/** Determines the number of arguments - if token is a function call or macro
* @param start token which is supposed to be the function/macro name.
* \return Number of arguments
*/
int numberOfArguments(const Token *start);
int numberOfArguments(const Token* ftok);

/// Get number of arguments without using AST
int numberOfArgumentsWithoutAst(const Token* start);

/**
* Get arguments (AST)
Expand Down
2 changes: 1 addition & 1 deletion lib/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ bool Library::isNotLibraryFunction(const Token *ftok) const

bool Library::matchArguments(const Token *ftok, const std::string &functionName) const
{
const int callargs = numberOfArguments(ftok);
const int callargs = numberOfArgumentsWithoutAst(ftok);
const std::unordered_map<std::string, Function>::const_iterator it = functions.find(functionName);
if (it == functions.cend())
return (callargs == 0);
Expand Down
8 changes: 8 additions & 0 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7172,6 +7172,14 @@ MathLib::bigint ValueType::typeSize(const cppcheck::Platform &platform, bool p)
return 0;
}

bool ValueType::isTypeEqual(const ValueType* that) const
{
auto tie = [](const ValueType* vt) {
return std::tie(vt->type, vt->container, vt->pointer, vt->typeScope, vt->smartPointer);
};
return tie(this) == tie(that);
}

std::string ValueType::str() const
{
std::string ret;
Expand Down
3 changes: 3 additions & 0 deletions lib/symboldatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,9 @@ class CPPCHECKLIB ValueType {

MathLib::bigint typeSize(const cppcheck::Platform &platform, bool p=false) const;

/// Check if type is the same ignoring const and references
bool isTypeEqual(const ValueType* that) const;

std::string str() const;
std::string dump() const;
};
Expand Down
72 changes: 54 additions & 18 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,22 +311,37 @@ static std::vector<ValueType> getParentValueTypes(const Token* tok,
} else if (Token::Match(tok->astParent(), "(|{|,")) {
int argn = -1;
const Token* ftok = getTokenArgumentFunction(tok, argn);
if (ftok && ftok->function()) {
std::vector<ValueType> result;
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
const Token* nameTok = nullptr;
for (const Variable* var : getArgumentVars(ftok, argn)) {
if (!var)
continue;
if (!var->valueType())
continue;
nameTok = var->nameToken();
result.push_back(*var->valueType());
}
if (result.size() == 1 && nameTok && parent) {
*parent = nameTok;
const Token* typeTok = nullptr;
if (ftok && argn >= 0) {
if (ftok->function()) {
std::vector<ValueType> result;
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
const Token* nameTok = nullptr;
for (const Variable* var : getArgumentVars(ftok, argn)) {
if (!var)
continue;
if (!var->valueType())
continue;
nameTok = var->nameToken();
result.push_back(*var->valueType());
}
if (result.size() == 1 && nameTok && parent) {
*parent = nameTok;
}
return result;
} else if (const Type* t = Token::typeOf(ftok, &typeTok)) {
if (astIsPointer(typeTok))
return {*typeTok->valueType()};
const Scope* scope = t->classScope;
// Check for aggregate constructors
if (scope && scope->numConstructors == 0 && t->derivedFrom.empty() &&
(t->isClassType() || t->isStructType()) && numberOfArguments(ftok) < scope->varlist.size()) {
assert(argn < scope->varlist.size());
auto it = std::next(scope->varlist.begin(), argn);
if (it->valueType())
return {*it->valueType()};
}
}
return result;
}
}
if (settings && Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
Expand Down Expand Up @@ -3293,6 +3308,14 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
return LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1),
!(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "[")));
}
} else if (Token::simpleMatch(tok, "{") && getArgumentStart(tok) &&
!Token::simpleMatch(getArgumentStart(tok), ",") && getArgumentStart(tok)->valueType()) {
const Token* vartok = getArgumentStart(tok);
auto vts = getParentValueTypes(tok);
for (const ValueType& vt : vts) {
if (vt.isTypeEqual(vartok->valueType()))
return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1);
}
}
return {{tok, std::move(errorPath)}};
}
Expand Down Expand Up @@ -4216,7 +4239,15 @@ static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, Error
}

for (const ValueType& vt : vts) {
if (vt.container && vt.type == ValueType::CONTAINER) {
if (vt.pointer > 0) {
std::vector<const Token*> args = getArguments(tok);
LifetimeStore::forEach(args,
"Passed to initializer list.",
ValueFlow::Value::LifetimeKind::SubObject,
[&](const LifetimeStore& ls) {
ls.byVal(tok, tokenlist, errorLogger, settings);
});
} else if (vt.container && vt.type == ValueType::CONTAINER) {
std::vector<const Token*> args = getArguments(tok);
if (args.size() == 1 && vt.container->view && astIsContainerOwned(args.front())) {
LifetimeStore{args.front(), "Passed to container view.", ValueFlow::Value::LifetimeKind::SubObject}
Expand All @@ -4238,7 +4269,12 @@ static void valueFlowLifetimeConstructor(Token* tok, TokenList* tokenlist, Error
});
}
} else {
valueFlowLifetimeClassConstructor(tok, Token::typeOf(tok->previous()), tokenlist, errorLogger, settings);
const Type* t = nullptr;
if (vt.typeScope && vt.typeScope->definedType)
t = vt.typeScope->definedType;
else
t = Token::typeOf(tok->previous());
valueFlowLifetimeClassConstructor(tok, t, tokenlist, errorLogger, settings);
}
}
}
Expand Down Expand Up @@ -4544,7 +4580,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase*, ErrorLogger
valueFlowForwardLifetime(parent->tokAt(2), tokenlist, errorLogger, settings);
}
// Check constructors
else if (Token::Match(tok, "=|return|%type%|%var% {") && !isScope(tok->next())) {
else if (Token::Match(tok, "=|return|%name%|{|,|> {") && !isScope(tok->next())) {
valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings);
}
// Check function calls
Expand Down
10 changes: 10 additions & 0 deletions test/testautovariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3561,6 +3561,16 @@ class TestAutoVariables : public TestFixture {
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());

// #11057
check("struct S {\n"
" int& r;\n"
"};\n"
"void f(int i) {\n"
" const S a[] = { { i } };\n"
" for (const auto& s : a) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}

void danglingLifetimeBorrowedMembers()
Expand Down
14 changes: 14 additions & 0 deletions test/testvalueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6571,6 +6571,20 @@ class TestValueFlow : public TestFixture {
code = "void f(const char * const x) { !!system(x); }\n";
valueOfTok(code, "x");

code = "struct struct1 {\n"
" int i1;\n"
" int i2;\n"
"};\n"
"struct struct2 {\n"
" char c1;\n"
" struct1 is1;\n"
" char c2[4];\n"
"};\n"
"void f() {\n"
" struct2 a = { 1, 2, 3, {4,5,6,7} }; \n"
"}\n";
valueOfTok(code, "a");

code = "void setDeltas(int life, int age, int multiplier) {\n"
" int dx = 0;\n"
" int dy = 0;\n"
Expand Down