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
18 changes: 16 additions & 2 deletions lib/astutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,22 @@ const Token* getParentMember(const Token * tok)
return tok;
}

const Token* getParentLifetime(const Token* tok)
{
if (!tok)
return tok;
const Variable* var = tok->variable();
// TODO: Call getLifetimeVariable for deeper analysis
if (!var)
return tok;
if (var->isLocal() || var->isArgument())
return tok;
const Token* parent = getParentMember(tok);
if (parent != tok)
return getParentLifetime(parent);
return tok;
}

bool astIsLHS(const Token* tok)
{
if (!tok)
Expand Down Expand Up @@ -448,8 +464,6 @@ bool isAliasOf(const Token *tok, nonneg int varid)
{
if (tok->varId() == varid)
return false;
if (tok->varId() == 0)
return false;
for (const ValueFlow::Value &val : tok->values()) {
if (!val.isLocalLifetimeValue())
continue;
Expand Down
2 changes: 2 additions & 0 deletions lib/astutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ const Token* astParentSkipParens(const Token* tok);

const Token* getParentMember(const Token * tok);

const Token* getParentLifetime(const Token* tok);

bool astIsLHS(const Token* tok);
bool astIsRHS(const Token* tok);

Expand Down
16 changes: 0 additions & 16 deletions lib/checkautovariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,22 +432,6 @@ static bool isDeadScope(const Token * tok, const Scope * scope)
return false;
}

static const Token * getParentLifetime(const Token *tok)
{
if (!tok)
return tok;
const Variable * var = tok->variable();
// TODO: Call getLifetimeVariable for deeper analysis
if (!var)
return tok;
if (var->isLocal())
return tok;
const Token * parent = getParentMember(tok);
if (parent != tok)
return getParentLifetime(parent);
return tok;
}

static int getPointerDepth(const Token *tok)
{
if (!tok)
Expand Down
18 changes: 15 additions & 3 deletions lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "token.h"
#include "tokenize.h"
#include "utils.h"
#include "valueflow.h"

#include <algorithm> // find_if()
#include <list>
Expand Down Expand Up @@ -1363,9 +1364,20 @@ void CheckOther::checkConstVariable()
continue;
if (isVariableChanged(var, mSettings, mTokenizer->isCPP()))
continue;
if (Function::returnsReference(function) &&
Token::findmatch(var->nameToken(), "return %varid% ;|[|.", scope->bodyEnd, var->declarationId()))
continue;
if (Function::returnsReference(function)) {
std::vector<const Token*> returns = Function::findReturns(function);
if (std::any_of(returns.begin(), returns.end(), [&](const Token* retTok) {
if (retTok->varId() == var->declarationId())
return true;
while (Token::simpleMatch(retTok, "."))
retTok = retTok->astOperand2();
const Variable* retVar = getLifetimeVariable(getParentLifetime(retTok));
if (!retVar)
return false;
return retVar->declarationId() == var->declarationId();
}))
continue;
}
// Skip if address is taken
if (Token::findmatch(var->nameToken(), "& %varid%", scope->bodyEnd, var->declarationId()))
continue;
Expand Down
26 changes: 26 additions & 0 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,32 @@ bool Function::returnsReference(const Function* function, bool unknown)
return false;
}

std::vector<const Token*> Function::findReturns(const Function* f)
{
std::vector<const Token*> result;
if (!f)
return result;
const Scope* scope = f->functionScope;
if (!scope)
return result;
for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
if (tok->str() == "{" && tok->scope() &&
(tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
tok = tok->link();
continue;
}
if (Token::simpleMatch(tok->astParent(), "return")) {
result.push_back(tok);
}
// Skip lambda functions since the scope may not be set correctly
const Token* lambdaEndToken = findLambdaEndToken(tok);
if (lambdaEndToken) {
tok = lambdaEndToken;
}
}
return result;
}

const Token * Function::constructorMemberInitialization() const
{
if (!isConstructor() || !functionScope || !functionScope->bodyStart)
Expand Down
2 changes: 2 additions & 0 deletions lib/symboldatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,8 @@ class CPPCHECKLIB Function {

static bool returnsReference(const Function* function, bool unknown = false);

static std::vector<const Token*> findReturns(const Function* f);

const Token* returnDefEnd() const {
if (this->hasTrailingReturnType()) {
return Token::findmatch(retDef, "{|;");
Expand Down
44 changes: 18 additions & 26 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2718,30 +2718,6 @@ static void valueFlowForward(Token* startToken,
}
}

static std::vector<const Token*> findReturns(const Function* f)
{
std::vector<const Token*> result;
const Scope* scope = f->functionScope;
if (!scope)
return result;
for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
if (tok->str() == "{" && tok->scope() &&
(tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
tok = tok->link();
continue;
}
if (Token::simpleMatch(tok->astParent(), "return")) {
result.push_back(tok);
}
// Skip lambda functions since the scope may not be set correctly
const Token* lambdaEndToken = findLambdaEndToken(tok);
if (lambdaEndToken) {
tok = lambdaEndToken;
}
}
return result;
}

static int getArgumentPos(const Variable *var, const Function *f)
{
auto arg_it = std::find_if(f->argumentList.begin(), f->argumentList.end(), [&](const Variable &v) {
Expand Down Expand Up @@ -2850,6 +2826,16 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, ValueFlow::Value:
return {{tok, true, std::move(errorPath)}};
if (vartok)
return getLifetimeTokens(vartok, std::move(errorPath), depth - 1);
} else if (Token::simpleMatch(var->nameToken()->astParent(), ":") &&
var->nameToken()->astParent()->astParent() &&
Token::simpleMatch(var->nameToken()->astParent()->astParent()->previous(), "for (")) {
errorPath.emplace_back(var->nameToken(), "Assigned to reference.");
const Token* vartok = var->nameToken();
if (vartok == tok)
return {{tok, true, std::move(errorPath)}};
const Token* contok = var->nameToken()->astParent()->astOperand2();
if (contok)
return getLifetimeTokens(contok, std::move(errorPath), depth - 1);
} else {
return std::vector<LifetimeToken> {};
}
Expand All @@ -2860,7 +2846,7 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, ValueFlow::Value:
if (!Function::returnsReference(f))
return {{tok, std::move(errorPath)}};
std::vector<LifetimeToken> result;
std::vector<const Token*> returns = findReturns(f);
std::vector<const Token*> returns = Function::findReturns(f);
for (const Token* returnTok : returns) {
if (returnTok == tok)
continue;
Expand Down Expand Up @@ -2947,6 +2933,12 @@ const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPat
return nullptr;
}

const Variable* getLifetimeVariable(const Token* tok)
{
ValueFlow::Value::ErrorPath errorPath;
return getLifetimeVariable(tok, errorPath, nullptr);
}

static bool isNotLifetimeValue(const ValueFlow::Value& val)
{
return !val.isLifetimeValue();
Expand Down Expand Up @@ -3394,7 +3386,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
const Function *f = tok->function();
if (Function::returnsReference(f))
return;
std::vector<const Token*> returns = findReturns(f);
std::vector<const Token*> returns = Function::findReturns(f);
const bool inconclusive = returns.size() > 1;
for (const Token* returnTok : returns) {
if (returnTok == tok)
Expand Down
2 changes: 2 additions & 0 deletions lib/valueflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, ValueFlow::Value:

const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf = nullptr);

const Variable* getLifetimeVariable(const Token* tok);

bool isLifetimeBorrowed(const Token *tok, const Settings *settings);

std::string lifetimeType(const Token *tok, const ValueFlow::Value *val);
Expand Down
18 changes: 18 additions & 0 deletions test/testother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,24 @@ class TestOther : public TestFixture {
"}\n");
ASSERT_EQUALS("", errout.str());

check("int* f(std::list<int>& x, unsigned int y) {\n"
" for (int& m : x) {\n"
" if (m == y)\n"
" return &m;\n"
" }\n"
" return nullptr;\n"
"}\n");
ASSERT_EQUALS("", errout.str());

check("int& f(std::list<int>& x, int& y) {\n"
" for (int& m : x) {\n"
" if (m == y)\n"
" return m;\n"
" }\n"
" return y;\n"
"}\n");
ASSERT_EQUALS("", errout.str());

check("void e();\n"
"void g(void);\n"
"void h(void);\n"
Expand Down