ValueFlow: some interface and namespace cleanups (#4746)

This commit is contained in:
Oliver Stöneberg 2023-01-28 10:20:47 +01:00 committed by GitHub
parent 464fbe8d53
commit afd13ea11d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 163 additions and 179 deletions

View File

@ -879,7 +879,7 @@ bool extractForLoopValues(const Token *forToken,
const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2(); const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2();
if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%")) if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%"))
return false; return false;
std::vector<MathLib::bigint> minInitValue = getMinValue(makeIntegralInferModel(), initExpr->astOperand2()->values()); std::vector<MathLib::bigint> minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values());
*varid = initExpr->astOperand1()->varId(); *varid = initExpr->astOperand1()->varId();
*knownInitValue = initExpr->astOperand2()->hasKnownIntValue(); *knownInitValue = initExpr->astOperand2()->hasKnownIntValue();
*initValue = minInitValue.empty() ? 0 : minInitValue.front(); *initValue = minInitValue.empty() ? 0 : minInitValue.front();
@ -1289,10 +1289,10 @@ const Token* followReferences(const Token* tok, ErrorPath* errors)
static bool isSameLifetime(const Token * const tok1, const Token * const tok2) static bool isSameLifetime(const Token * const tok1, const Token * const tok2)
{ {
ValueFlow::Value v1 = getLifetimeObjValue(tok1); ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1);
if (!v1.isLifetimeValue()) if (!v1.isLifetimeValue())
return false; return false;
ValueFlow::Value v2 = getLifetimeObjValue(tok2); ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2);
if (!v2.isLifetimeValue()) if (!v2.isLifetimeValue())
return false; return false;
return v1.tokvalue == v2.tokvalue; return v1.tokvalue == v2.tokvalue;

View File

@ -518,7 +518,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
for (const Token *tok = start; tok && tok != end; tok = tok->next()) { for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
// Return reference from function // Return reference from function
if (returnRef && Token::simpleMatch(tok->astParent(), "return")) { if (returnRef && Token::simpleMatch(tok->astParent(), "return")) {
for (const LifetimeToken& lt : getLifetimeTokens(tok, true)) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok, true)) {
if (!printInconclusive && lt.inconclusive) if (!printInconclusive && lt.inconclusive)
continue; continue;
const Variable* var = lt.token->variable(); const Variable* var = lt.token->variable();
@ -537,14 +537,14 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
tok->variable()->declarationId() == tok->varId() && tok->variable()->isStatic() && tok->variable()->declarationId() == tok->varId() && tok->variable()->isStatic() &&
!tok->variable()->isArgument()) { !tok->variable()->isArgument()) {
ErrorPath errorPath; ErrorPath errorPath;
const Variable *var = getLifetimeVariable(tok, errorPath); const Variable *var = ValueFlow::getLifetimeVariable(tok, errorPath);
if (var && isInScope(var->nameToken(), tok->scope())) { if (var && isInScope(var->nameToken(), tok->scope())) {
errorDanglingReference(tok, var, errorPath); errorDanglingReference(tok, var, errorPath);
continue; continue;
} }
// Reference to temporary // Reference to temporary
} else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) { } else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) {
for (const LifetimeToken& lt : getLifetimeTokens(getParentLifetime(tok))) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(getParentLifetime(tok))) {
if (!printInconclusive && lt.inconclusive) if (!printInconclusive && lt.inconclusive)
continue; continue;
const Token * tokvalue = lt.token; const Token * tokvalue = lt.token;
@ -565,13 +565,13 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
const Token* parent = getParentLifetime(mTokenizer->isCPP(), val.tokvalue, &mSettings->library); const Token* parent = getParentLifetime(mTokenizer->isCPP(), val.tokvalue, &mSettings->library);
if (!exprs.insert(parent).second) if (!exprs.insert(parent).second)
continue; continue;
for (const LifetimeToken& lt : getLifetimeTokens(parent, escape || isAssignedToNonLocal(tok))) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(parent, escape || isAssignedToNonLocal(tok))) {
const Token * tokvalue = lt.token; const Token * tokvalue = lt.token;
if (val.isLocalLifetimeValue()) { if (val.isLocalLifetimeValue()) {
if (escape) { if (escape) {
if (getPointerDepth(tok) < getPointerDepth(tokvalue)) if (getPointerDepth(tok) < getPointerDepth(tokvalue))
continue; continue;
if (!isLifetimeBorrowed(tok, mSettings)) if (!ValueFlow::isLifetimeBorrowed(tok, mSettings))
continue; continue;
if (tokvalue->exprId() == tok->exprId() && !(tok->variable() && tok->variable()->isArray()) && if (tokvalue->exprId() == tok->exprId() && !(tok->variable() && tok->variable()->isArray()) &&
!astIsContainerView(tok->astParent())) !astIsContainerView(tok->astParent()))
@ -604,7 +604,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
} else if (tok->variable() && tok->variable()->declarationId() == tok->varId()) { } else if (tok->variable() && tok->variable()->declarationId() == tok->varId()) {
var = tok->variable(); var = tok->variable();
} }
if (!isLifetimeBorrowed(tok, mSettings)) if (!ValueFlow::isLifetimeBorrowed(tok, mSettings))
continue; continue;
const Token* nextTok = nextAfterAstRightmostLeaf(tok->astTop()); const Token* nextTok = nextAfterAstRightmostLeaf(tok->astTop());
if (!nextTok) if (!nextTok)

View File

@ -1030,7 +1030,7 @@ void CheckBufferOverrun::objectIndex()
if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0) if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
continue; continue;
std::vector<ValueFlow::Value> values = getLifetimeObjValues(obj, false, -1); std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(obj, false, -1);
for (const ValueFlow::Value& v:values) { for (const ValueFlow::Value& v:values) {
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
continue; continue;

View File

@ -1446,7 +1446,7 @@ void CheckOther::checkConstVariable()
retTok = retTok->astOperand2(); retTok = retTok->astOperand2();
while (Token::simpleMatch(retTok, ".")) while (Token::simpleMatch(retTok, "."))
retTok = retTok->astOperand2(); retTok = retTok->astOperand2();
return hasLifetimeToken(getParentLifetime(retTok), var->nameToken()); return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken());
})) }))
continue; continue;
} }
@ -3671,8 +3671,8 @@ void CheckOther::checkComparePointers()
const Token *tok2 = tok->astOperand2(); const Token *tok2 = tok->astOperand2();
if (!astIsPointer(tok1) || !astIsPointer(tok2)) if (!astIsPointer(tok1) || !astIsPointer(tok2))
continue; continue;
ValueFlow::Value v1 = getLifetimeObjValue(tok1); ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1);
ValueFlow::Value v2 = getLifetimeObjValue(tok2); ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2);
if (!v1.isLocalLifetimeValue() || !v2.isLocalLifetimeValue()) if (!v1.isLocalLifetimeValue() || !v2.isLocalLifetimeValue())
continue; continue;
const Variable *var1 = v1.tokvalue->variable(); const Variable *var1 = v1.tokvalue->variable();

View File

@ -727,7 +727,7 @@ static bool isSameIteratorContainerExpression(const Token* tok1,
static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0) static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0)
{ {
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, false, path); std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(tok, false, path);
auto it = std::find_if(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) { auto it = std::find_if(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) {
return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator; return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator;
}); });
@ -1155,7 +1155,7 @@ void CheckStl::invalidContainer()
ErrorPath ep; ErrorPath ep;
bool addressOf = false; bool addressOf = false;
const Variable* var = getLifetimeVariable(info.tok, ep, &addressOf); const Variable* var = ValueFlow::getLifetimeVariable(info.tok, ep, &addressOf);
// Check the reference is created before the change // Check the reference is created before the change
if (var && var->declarationId() == r.tok->varId() && !addressOf) { if (var && var->declarationId() == r.tok->varId() && !addressOf) {
// An argument always reaches // An argument always reaches

View File

@ -1287,7 +1287,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
continue; continue;
FwdAnalysis fwdAnalysis(mTokenizer->isCPP(), mSettings->library); FwdAnalysis fwdAnalysis(mTokenizer->isCPP(), mSettings->library);
const Token* scopeEnd = getEndOfExprScope(expr, scope, /*smallest*/ false); const Token* scopeEnd = ValueFlow::getEndOfExprScope(expr, scope, /*smallest*/ false);
if (fwdAnalysis.unusedValue(expr, start, scopeEnd)) { if (fwdAnalysis.unusedValue(expr, start, scopeEnd)) {
if (!bailoutTypeName.empty()) { if (!bailoutTypeName.empty()) {
if (bailoutTypeName != "auto") if (bailoutTypeName != "auto")

View File

@ -1274,13 +1274,13 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
if (expr->isComparisonOp()) { if (expr->isComparisonOp()) {
if (rhs.isIntValue()) { if (rhs.isIntValue()) {
std::vector<ValueFlow::Value> result = std::vector<ValueFlow::Value> result =
infer(makeIntegralInferModel(), expr->str(), expr->astOperand1()->values(), {rhs}); infer(ValueFlow::makeIntegralInferModel(), expr->str(), expr->astOperand1()->values(), {rhs});
if (result.empty() || !result.front().isKnown()) if (result.empty() || !result.front().isKnown())
return unknown; return unknown;
return result.front(); return result.front();
} else if (lhs.isIntValue()) { } else if (lhs.isIntValue()) {
std::vector<ValueFlow::Value> result = std::vector<ValueFlow::Value> result =
infer(makeIntegralInferModel(), expr->str(), {lhs}, expr->astOperand2()->values()); infer(ValueFlow::makeIntegralInferModel(), expr->str(), {lhs}, expr->astOperand2()->values());
if (result.empty() || !result.front().isKnown()) if (result.empty() || !result.front().isKnown())
return unknown; return unknown;
return result.front(); return result.front();
@ -1353,7 +1353,7 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const
if (child->exprId() > 0 && pm.hasValue(child->exprId())) { if (child->exprId() > 0 && pm.hasValue(child->exprId())) {
ValueFlow::Value& v = pm.at(child->exprId()); ValueFlow::Value& v = pm.at(child->exprId());
if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) {
if (isContainerSizeChanged(child, v.indirect, settings)) if (ValueFlow::isContainerSizeChanged(child, v.indirect, settings))
v = unknown; v = unknown;
} else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) { } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) {
if (isVariableChanged(child, v.indirect, settings, true)) if (isVariableChanged(child, v.indirect, settings, true))

View File

@ -343,10 +343,10 @@ static void parseCompareEachInt(
}); });
} }
const Token* parseCompareInt(const Token* tok, const Token* ValueFlow::parseCompareInt(const Token* tok,
ValueFlow::Value& true_value, ValueFlow::Value& true_value,
ValueFlow::Value& false_value, ValueFlow::Value& false_value,
const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate) const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate)
{ {
const Token* result = nullptr; const Token* result = nullptr;
parseCompareEachInt( parseCompareEachInt(
@ -370,7 +370,7 @@ const Token* parseCompareInt(const Token* tok,
return result; return result;
} }
const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value) const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value)
{ {
return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> { return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> {
if (t->hasKnownIntValue()) if (t->hasKnownIntValue())
@ -417,7 +417,7 @@ static bool isNumeric(const ValueFlow::Value& value) {
return value.isIntValue() || value.isFloatValue(); return value.isIntValue() || value.isFloatValue();
} }
void combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result) void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value *result)
{ {
if (value1.isKnown() && value2.isKnown()) if (value1.isKnown() && value2.isKnown())
result->setKnown(); result->setKnown();
@ -688,7 +688,7 @@ static void setTokenValue(Token* tok,
} }
if (value.isLifetimeValue()) { if (value.isLifetimeValue()) {
if (!isLifetimeBorrowed(parent, settings)) if (!ValueFlow::isLifetimeBorrowed(parent, settings))
return; return;
if (value.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator && astIsIterator(parent)) { if (value.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator && astIsIterator(parent)) {
setTokenValue(parent,value,settings); setTokenValue(parent,value,settings);
@ -1288,7 +1288,6 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b
return tok->next(); return tok->next();
} }
static void valueFlowNumber(TokenList *tokenlist) static void valueFlowNumber(TokenList *tokenlist)
{ {
for (Token *tok = tokenlist->front(); tok;) { for (Token *tok = tokenlist->front(); tok;) {
@ -1973,8 +1972,8 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti
} }
} }
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist); static ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist);
ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist); static ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist);
static Analyzer::Result valueFlowForward(Token* startToken, static Analyzer::Result valueFlowForward(Token* startToken,
const Token* endToken, const Token* endToken,
@ -3229,7 +3228,7 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer {
enum class LifetimeCapture { Undefined, ByValue, ByReference }; enum class LifetimeCapture { Undefined, ByValue, ByReference };
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val) static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
{ {
std::string result; std::string result;
if (!val) if (!val)
@ -3253,7 +3252,7 @@ std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
return result; return result;
} }
std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath) std::string ValueFlow::lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath)
{ {
const Token *tokvalue = val ? val->tokvalue : nullptr; const Token *tokvalue = val ? val->tokvalue : nullptr;
const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr; const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr;
@ -3291,7 +3290,7 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Error
return msg; return msg;
} }
std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path) std::vector<ValueFlow::Value> ValueFlow::getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path)
{ {
std::vector<ValueFlow::Value> result; std::vector<ValueFlow::Value> result;
auto pred = [&](const ValueFlow::Value& v) { auto pred = [&](const ValueFlow::Value& v) {
@ -3338,9 +3337,9 @@ static bool derefShared(const Token* tok)
return !hasUniqueOwnership(ptrTok); return !hasUniqueOwnership(ptrTok);
} }
ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive) ValueFlow::Value ValueFlow::getLifetimeObjValue(const Token *tok, bool inconclusive)
{ {
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, inconclusive); std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(tok, inconclusive);
// There should only be one lifetime // There should only be one lifetime
if (values.size() != 1) if (values.size() != 1)
return ValueFlow::Value{}; return ValueFlow::Value{};
@ -3348,16 +3347,16 @@ ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
} }
template<class Predicate> template<class Predicate>
static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, static std::vector<ValueFlow::LifetimeToken> getLifetimeTokens(const Token* tok,
bool escape, bool escape,
ValueFlow::Value::ErrorPath errorPath, ValueFlow::Value::ErrorPath errorPath,
Predicate pred, Predicate pred,
int depth = 20) int depth = 20)
{ {
if (!tok) if (!tok)
return std::vector<LifetimeToken> {}; return std::vector<ValueFlow::LifetimeToken> {};
if (Token::simpleMatch(tok, "...")) if (Token::simpleMatch(tok, "..."))
return std::vector<LifetimeToken>{}; return std::vector<ValueFlow::LifetimeToken>{};
const Variable *var = tok->variable(); const Variable *var = tok->variable();
if (pred(tok)) if (pred(tok))
return {{tok, std::move(errorPath)}}; return {{tok, std::move(errorPath)}};
@ -3392,9 +3391,9 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
if (astIsContainer(contok)) if (astIsContainer(contok))
return getLifetimeTokens(contok, escape, std::move(errorPath), pred, depth - 1); return getLifetimeTokens(contok, escape, std::move(errorPath), pred, depth - 1);
else else
return std::vector<LifetimeToken>{}; return std::vector<ValueFlow::LifetimeToken>{};
} else { } else {
return std::vector<LifetimeToken> {}; return std::vector<ValueFlow::LifetimeToken> {};
} }
} }
} else if (Token::Match(tok->previous(), "%name% (")) { } else if (Token::Match(tok->previous(), "%name% (")) {
@ -3402,12 +3401,12 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
if (f) { if (f) {
if (!Function::returnsReference(f)) if (!Function::returnsReference(f))
return {{tok, std::move(errorPath)}}; return {{tok, std::move(errorPath)}};
std::vector<LifetimeToken> result; std::vector<ValueFlow::LifetimeToken> result;
std::vector<const Token*> returns = Function::findReturns(f); std::vector<const Token*> returns = Function::findReturns(f);
for (const Token* returnTok : returns) { for (const Token* returnTok : returns) {
if (returnTok == tok) if (returnTok == tok)
continue; continue;
for (LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, depth - returns.size())) { for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, depth - returns.size())) {
const Token* argvarTok = lt.token; const Token* argvarTok = lt.token;
const Variable* argvar = argvarTok->variable(); const Variable* argvar = argvarTok->variable();
if (!argvar) if (!argvar)
@ -3416,11 +3415,11 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
const int n = getArgumentPos(argvar, f); const int n = getArgumentPos(argvar, f);
if (n < 0) if (n < 0)
return std::vector<LifetimeToken> {}; return std::vector<ValueFlow::LifetimeToken> {};
std::vector<const Token*> args = getArguments(tok->previous()); std::vector<const Token*> args = getArguments(tok->previous());
// TODO: Track lifetimes of default parameters // TODO: Track lifetimes of default parameters
if (n >= args.size()) if (n >= args.size())
return std::vector<LifetimeToken> {}; return std::vector<ValueFlow::LifetimeToken> {};
argTok = args[n]; argTok = args[n];
lt.errorPath.emplace_back(returnTok, "Return reference."); lt.errorPath.emplace_back(returnTok, "Return reference.");
lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
@ -3432,7 +3431,7 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
"Calling member function on '" + argTok->expressionString() + "'."); "Calling member function on '" + argTok->expressionString() + "'.");
} }
if (argTok) { if (argTok) {
std::vector<LifetimeToken> arglts = LifetimeToken::setInconclusive( std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive(
getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, depth - returns.size()), getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, depth - returns.size()),
returns.size() > 1); returns.size() > 1);
result.insert(result.end(), arglts.cbegin(), arglts.cend()); result.insert(result.end(), arglts.cbegin(), arglts.cend());
@ -3445,7 +3444,7 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
const Library::Container::Yield y = library->getYield(tok->previous()->str()); const Library::Container::Yield y = library->getYield(tok->previous()->str());
if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) { if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) {
errorPath.emplace_back(tok->previous(), "Accessing container."); errorPath.emplace_back(tok->previous(), "Accessing container.");
return LifetimeToken::setAddressOf( return ValueFlow::LifetimeToken::setAddressOf(
getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, depth - 1), getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, depth - 1),
false); false);
} }
@ -3474,8 +3473,8 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, depth - 1); return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, depth - 1);
} }
} else { } else {
return LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1), return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1),
!(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "["))); !(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "[")));
} }
} else if (Token::simpleMatch(tok, "{") && getArgumentStart(tok) && } else if (Token::simpleMatch(tok, "{") && getArgumentStart(tok) &&
!Token::simpleMatch(getArgumentStart(tok), ",") && getArgumentStart(tok)->valueType()) { !Token::simpleMatch(getArgumentStart(tok), ",") && getArgumentStart(tok)->valueType()) {
@ -3490,14 +3489,14 @@ static std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
return {{tok, std::move(errorPath)}}; return {{tok, std::move(errorPath)}};
} }
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath) std::vector<ValueFlow::LifetimeToken> ValueFlow::getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath)
{ {
return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) { return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) {
return false; return false;
}); });
} }
bool hasLifetimeToken(const Token* tok, const Token* lifetime) bool ValueFlow::hasLifetimeToken(const Token* tok, const Token* lifetime)
{ {
bool result = false; bool result = false;
getLifetimeTokens(tok, false, ValueFlow::Value::ErrorPath{}, [&](const Token* tok2) { getLifetimeTokens(tok, false, ValueFlow::Value::ErrorPath{}, [&](const Token* tok2) {
@ -3509,7 +3508,7 @@ bool hasLifetimeToken(const Token* tok, const Token* lifetime)
static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf = nullptr) static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf = nullptr)
{ {
std::vector<LifetimeToken> lts = getLifetimeTokens(tok); std::vector<ValueFlow::LifetimeToken> lts = ValueFlow::getLifetimeTokens(tok);
if (lts.size() != 1) if (lts.size() != 1)
return nullptr; return nullptr;
if (lts.front().inconclusive) if (lts.front().inconclusive)
@ -3520,7 +3519,7 @@ static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPa
return lts.front().token; return lts.front().token;
} }
const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf) const Variable* ValueFlow::getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf)
{ {
const Token* tok2 = getLifetimeToken(tok, errorPath, addressOf); const Token* tok2 = getLifetimeToken(tok, errorPath, addressOf);
if (tok2 && tok2->variable()) if (tok2 && tok2->variable())
@ -3528,7 +3527,7 @@ const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPat
return nullptr; return nullptr;
} }
const Variable* getLifetimeVariable(const Token* tok) const Variable* ValueFlow::getLifetimeVariable(const Token* tok)
{ {
ValueFlow::Value::ErrorPath errorPath; ValueFlow::Value::ErrorPath errorPath;
return getLifetimeVariable(tok, errorPath, nullptr); return getLifetimeVariable(tok, errorPath, nullptr);
@ -3662,7 +3661,7 @@ static bool isDifferentType(const Token* src, const Token* dst)
return false; return false;
} }
bool isLifetimeBorrowed(const Token *tok, const Settings *settings) bool ValueFlow::isLifetimeBorrowed(const Token *tok, const Settings *settings)
{ {
if (!tok) if (!tok)
return true; return true;
@ -3729,7 +3728,7 @@ static const Token* getEndOfVarScope(const Variable* var)
return innerScope->bodyEnd; return innerScope->bodyEnd;
} }
const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope, bool smallest) const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* defaultScope, bool smallest)
{ {
const Token* end = nullptr; const Token* end = nullptr;
bool local = false; bool local = false;
@ -3767,7 +3766,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) { if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) {
std::list<ValueFlow::Value> values = tok->values(); std::list<ValueFlow::Value> values = tok->values();
values.remove_if(&isNotLifetimeValue); values.remove_if(&isNotLifetimeValue);
valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist); valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), values, tokenlist);
return; return;
} }
Token *parent = tok->astParent(); Token *parent = tok->astParent();
@ -3781,7 +3780,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
if (!parent->astOperand2() || parent->astOperand2()->values().empty()) if (!parent->astOperand2() || parent->astOperand2()->values().empty())
return; return;
if (!isLifetimeBorrowed(parent->astOperand2(), settings)) if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings))
return; return;
const Token* expr = getLHSVariableToken(parent); const Token* expr = getLHSVariableToken(parent);
@ -3791,7 +3790,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog
if (expr->exprId() == 0) if (expr->exprId() == 0)
return; return;
const Token* endOfVarScope = getEndOfExprScope(expr); const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr);
// Only forward lifetime values // Only forward lifetime values
std::list<ValueFlow::Value> values = parent->astOperand2()->values(); std::list<ValueFlow::Value> values = parent->astOperand2()->values();
@ -3938,7 +3937,7 @@ struct LifetimeStore {
if (!argtok) if (!argtok)
return false; return false;
bool update = false; bool update = false;
for (const LifetimeToken& lt : getLifetimeTokens(argtok)) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok)) {
if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
continue; continue;
ErrorPath er = errorPath; ErrorPath er = errorPath;
@ -4000,7 +3999,7 @@ struct LifetimeStore {
if (argtok->values().empty()) { if (argtok->values().empty()) {
ErrorPath er; ErrorPath er;
er.emplace_back(argtok, message); er.emplace_back(argtok, message);
for (const LifetimeToken& lt : getLifetimeTokens(argtok)) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok)) {
if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
continue; continue;
ValueFlow::Value value; ValueFlow::Value value;
@ -4029,7 +4028,7 @@ struct LifetimeStore {
if (!v.isLifetimeValue()) if (!v.isLifetimeValue())
continue; continue;
const Token *tok3 = v.tokvalue; const Token *tok3 = v.tokvalue;
for (const LifetimeToken& lt : getLifetimeTokens(tok3)) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok3)) {
if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
continue; continue;
ErrorPath er = v.errorPath; ErrorPath er = v.errorPath;
@ -4101,7 +4100,7 @@ struct LifetimeStore {
continue; continue;
const Token *tok2 = v.tokvalue; const Token *tok2 = v.tokvalue;
ErrorPath er = v.errorPath; ErrorPath er = v.errorPath;
const Variable *var = getLifetimeVariable(tok2, er); const Variable *var = ValueFlow::getLifetimeVariable(tok2, er);
// TODO: the inserted data is never used // TODO: the inserted data is never used
er.insert(er.end(), errorPath.cbegin(), errorPath.cend()); er.insert(er.end(), errorPath.cbegin(), errorPath.cend());
if (!var) if (!var)
@ -4199,9 +4198,9 @@ static void valueFlowLifetimeUserConstructor(Token* tok,
const Token* expr = tok2->astOperand2(); const Token* expr = tok2->astOperand2();
if (!var) if (!var)
continue; continue;
if (!isLifetimeBorrowed(expr, settings)) if (!ValueFlow::isLifetimeBorrowed(expr, settings))
continue; continue;
const Variable* argvar = getLifetimeVariable(expr); const Variable* argvar = ValueFlow::getLifetimeVariable(expr);
if (var->isReference() || var->isRValueReference()) { if (var->isReference() || var->isRValueReference()) {
if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
paramCapture[argvar] = LifetimeCapture::ByReference; paramCapture[argvar] = LifetimeCapture::ByReference;
@ -4312,7 +4311,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
LifetimeStore{ LifetimeStore{
args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
.byDerefCopy(memtok, tokenlist, errorLogger, settings); .byDerefCopy(memtok, tokenlist, errorLogger, settings);
} else if (!args.empty() && isLifetimeBorrowed(args.back(), settings)) { } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) {
LifetimeStore{ LifetimeStore{
args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}
.byVal(memtok, tokenlist, errorLogger, settings); .byVal(memtok, tokenlist, errorLogger, settings);
@ -4331,7 +4330,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog
for (const Token* returnTok : returns) { for (const Token* returnTok : returns) {
if (returnTok == tok) if (returnTok == tok)
continue; continue;
const Variable *returnVar = getLifetimeVariable(returnTok); const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok);
if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) { if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) {
LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger); LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger);
ls.inconclusive = inconclusive; ls.inconclusive = inconclusive;
@ -4750,7 +4749,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase* /*db*/, Erro
} }
// address of // address of
else if (tok->isUnaryOp("&")) { else if (tok->isUnaryOp("&")) {
for (const LifetimeToken& lt : getLifetimeTokens(tok->astOperand1())) { for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok->astOperand1())) {
if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) if (!settings->certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive)
continue; continue;
ErrorPath errorPath = lt.errorPath; ErrorPath errorPath = lt.errorPath;
@ -4869,7 +4868,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase* /*db*/, Erro
// Check variables // Check variables
else if (tok->variable()) { else if (tok->variable()) {
ErrorPath errorPath; ErrorPath errorPath;
const Variable * var = getLifetimeVariable(tok, errorPath); const Variable * var = ValueFlow::getLifetimeVariable(tok, errorPath);
if (!var) if (!var)
continue; continue;
if (var->nameToken() == tok) if (var->nameToken() == tok)
@ -5002,7 +5001,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab
continue; continue;
if (parent && parent->astOperand1() && parent->astOperand1()->varId() == varId) if (parent && parent->astOperand1() && parent->astOperand1()->varId() == varId)
continue; continue;
const Token* const endOfVarScope = getEndOfExprScope(varTok); const Token* const endOfVarScope = ValueFlow::getEndOfExprScope(varTok);
const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok); const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove); const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
@ -5261,7 +5260,7 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba
continue; continue;
Token* start = nextAfterAstRightmostLeaf(tok); Token* start = nextAfterAstRightmostLeaf(tok);
const Token* end = getEndOfExprScope(tok->astOperand1(), scope); const Token* end = ValueFlow::getEndOfExprScope(tok->astOperand1(), scope);
ValueFlow::Value rhs = makeSymbolic(tok->astOperand2()); ValueFlow::Value rhs = makeSymbolic(tok->astOperand2());
rhs.errorPath.emplace_back(tok, rhs.errorPath.emplace_back(tok,
@ -5306,6 +5305,8 @@ static const Token* isStrlenOf(const Token* tok, const Token* expr, int depth =
return nullptr; return nullptr;
} }
static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val);
static void valueFlowSymbolicOperators(TokenList* tokenlist, SymbolDatabase* symboldatabase) static void valueFlowSymbolicOperators(TokenList* tokenlist, SymbolDatabase* symboldatabase)
{ {
for (const Scope* scope : symboldatabase->functionScopes) { for (const Scope* scope : symboldatabase->functionScopes) {
@ -5530,7 +5531,7 @@ static void valueFlowForwardAssign(Token* const tok,
{ {
if (Token::simpleMatch(tok->astParent(), "return")) if (Token::simpleMatch(tok->astParent(), "return"))
return; return;
const Token* endOfVarScope = getEndOfExprScope(expr); const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr);
if (std::any_of(values.cbegin(), values.cend(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) { if (std::any_of(values.cbegin(), values.cend(), std::mem_fn(&ValueFlow::Value::isLifetimeValue))) {
valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings);
values.remove_if(std::mem_fn(&ValueFlow::Value::isLifetimeValue)); values.remove_if(std::mem_fn(&ValueFlow::Value::isLifetimeValue));
@ -5872,7 +5873,7 @@ static bool isBreakScope(const Token* const endToken)
return Token::findmatch(endToken->link(), "break|goto", endToken); return Token::findmatch(endToken->link(), "break|goto", endToken);
} }
ValueFlow::Value asImpossible(ValueFlow::Value v) ValueFlow::Value ValueFlow::asImpossible(ValueFlow::Value v)
{ {
v.invertRange(); v.invertRange();
v.setImpossible(); v.setImpossible();
@ -5881,7 +5882,7 @@ ValueFlow::Value asImpossible(ValueFlow::Value v)
static void insertImpossible(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input) static void insertImpossible(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
{ {
std::transform(input.cbegin(), input.cend(), std::back_inserter(values), &asImpossible); std::transform(input.cbegin(), input.cend(), std::back_inserter(values), &ValueFlow::asImpossible);
} }
static void insertNegateKnown(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input) static void insertNegateKnown(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
@ -6476,7 +6477,7 @@ struct ConditionHandler {
changeKnownToPossible(values); changeKnownToPossible(values);
} }
} }
forward(after, getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist); forward(after, ValueFlow::getEndOfExprScope(cond.vartok, scope), cond.vartok, values, tokenlist);
} }
}); });
} }
@ -6548,7 +6549,7 @@ struct IntegralInferModel : InferModel {
} }
}; };
ValuePtr<InferModel> makeIntegralInferModel() { ValuePtr<InferModel> ValueFlow::makeIntegralInferModel() {
return IntegralInferModel{}; return IntegralInferModel{};
} }
@ -6564,18 +6565,6 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math
return ValueFlow::Value{}; return ValueFlow::Value{};
} }
ValueFlow::Value inferCondition(const std::string &op, MathLib::bigint val, const Token* varTok)
{
if (!varTok)
return ValueFlow::Value{};
if (varTok->hasKnownIntValue())
return ValueFlow::Value{};
std::vector<ValueFlow::Value> r = infer(IntegralInferModel{}, op, val, varTok->values());
if (r.size() == 1 && r.front().isKnown())
return r.front();
return ValueFlow::Value{};
}
struct IteratorInferModel : InferModel { struct IteratorInferModel : InferModel {
virtual ValueFlow::Value::ValueType getType() const = 0; virtual ValueFlow::Value::ValueType getType() const = 0;
bool match(const ValueFlow::Value& value) const override { bool match(const ValueFlow::Value& value) const override {
@ -6944,14 +6933,14 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
if (executeBody && vartok) { if (executeBody && vartok) {
std::list<ValueFlow::Value> initValues; std::list<ValueFlow::Value> initValues;
initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower); initValues.emplace_back(initValue, ValueFlow::Value::Bound::Lower);
initValues.push_back(asImpossible(initValues.back())); initValues.push_back(ValueFlow::asImpossible(initValues.back()));
Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist); Analyzer::Result result = valueFlowForward(bodyStart, bodyStart->link(), vartok, initValues, tokenlist);
if (!result.action.isModified()) { if (!result.action.isModified()) {
std::list<ValueFlow::Value> lastValues; std::list<ValueFlow::Value> lastValues;
lastValues.emplace_back(lastValue, ValueFlow::Value::Bound::Upper); lastValues.emplace_back(lastValue, ValueFlow::Value::Bound::Upper);
lastValues.back().conditional = true; lastValues.back().conditional = true;
lastValues.push_back(asImpossible(lastValues.back())); lastValues.push_back(ValueFlow::asImpossible(lastValues.back()));
if (stepValue != 1) if (stepValue != 1)
lastValues.pop_front(); lastValues.pop_front();
valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist); valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist);
@ -7838,7 +7827,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
return Action::Invalid; return Action::Invalid;
if (isLikelyStreamRead(isCPP(), tok->astParent())) if (isLikelyStreamRead(isCPP(), tok->astParent()))
return Action::Invalid; return Action::Invalid;
if (astIsContainer(tok) && isContainerSizeChanged(tok, getIndirect(tok), getSettings())) if (astIsContainer(tok) && ValueFlow::isContainerSizeChanged(tok, getIndirect(tok), getSettings()))
return read | Action::Invalid; return read | Action::Invalid;
return read; return read;
} }
@ -7871,9 +7860,9 @@ static const Token* parseBinaryIntOp(const Token* expr,
return varTok; return varTok;
} }
const Token* solveExprValue(const Token* expr, const Token* ValueFlow::solveExprValue(const Token* expr,
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval, const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
ValueFlow::Value& value) ValueFlow::Value& value)
{ {
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue()) if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
return expr; return expr;
@ -7889,24 +7878,24 @@ const Token* solveExprValue(const Token* expr,
switch (expr->str()[0]) { switch (expr->str()[0]) {
case '+': { case '+': {
value.intvalue -= intval; value.intvalue -= intval;
return solveExprValue(binaryTok, eval, value); return ValueFlow::solveExprValue(binaryTok, eval, value);
} }
case '-': { case '-': {
if (rhs) if (rhs)
value.intvalue = intval - value.intvalue; value.intvalue = intval - value.intvalue;
else else
value.intvalue += intval; value.intvalue += intval;
return solveExprValue(binaryTok, eval, value); return ValueFlow::solveExprValue(binaryTok, eval, value);
} }
case '*': { case '*': {
if (intval == 0) if (intval == 0)
break; break;
value.intvalue /= intval; value.intvalue /= intval;
return solveExprValue(binaryTok, eval, value); return ValueFlow::solveExprValue(binaryTok, eval, value);
} }
case '^': { case '^': {
value.intvalue ^= intval; value.intvalue ^= intval;
return solveExprValue(binaryTok, eval, value); return ValueFlow::solveExprValue(binaryTok, eval, value);
} }
} }
} }
@ -7915,7 +7904,7 @@ const Token* solveExprValue(const Token* expr,
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
{ {
return solveExprValue( return ValueFlow::solveExprValue(
expr, expr,
[](const Token* tok) -> std::vector<MathLib::bigint> { [](const Token* tok) -> std::vector<MathLib::bigint> {
if (tok->hasKnownIntValue()) if (tok->hasKnownIntValue())
@ -7940,7 +7929,7 @@ ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Va
return ExpressionAnalyzer(exprTok, value, tokenlist); return ExpressionAnalyzer(exprTok, value, tokenlist);
} }
bool isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings, int depth) bool ValueFlow::isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings, int depth)
{ {
if (!tok) if (!tok)
return false; return false;
@ -7991,7 +7980,7 @@ static bool isContainerSizeChanged(nonneg int varId,
for (const Token *tok = start; tok != end; tok = tok->next()) { for (const Token *tok = start; tok != end; tok = tok->next()) {
if (tok->varId() != varId) if (tok->varId() != varId)
continue; continue;
if (isContainerSizeChanged(tok, indirect, settings, depth)) if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth))
return true; return true;
} }
return false; return false;

View File

@ -47,7 +47,7 @@ class ValuePtr;
namespace ValueFlow { namespace ValueFlow {
/// Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFlow::setValues). /// Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFlow::setValues).
const ValueFlow::Value * valueFlowConstantFoldAST(Token *expr, const Settings *settings); const Value * valueFlowConstantFoldAST(Token *expr, const Settings *settings);
/// Perform valueflow analysis. /// Perform valueflow analysis.
void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings); void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings);
@ -56,82 +56,77 @@ namespace ValueFlow {
size_t getSizeOf(const ValueType &vt, const Settings *settings); size_t getSizeOf(const ValueType &vt, const Settings *settings);
const ValueFlow::Value* findValue(const std::list<ValueFlow::Value>& values, const Value* findValue(const std::list<Value>& values,
const Settings* settings, const Settings* settings,
const std::function<bool(const ValueFlow::Value&)> &pred); const std::function<bool(const Value&)> &pred);
std::vector<ValueFlow::Value> isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true); std::vector<Value> isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true);
Value asImpossible(Value v);
bool isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings = nullptr, int depth = 20);
struct LifetimeToken {
const Token* token;
Value::ErrorPath errorPath;
bool addressOf;
bool inconclusive;
LifetimeToken() : token(nullptr), errorPath(), addressOf(false), inconclusive(false) {}
LifetimeToken(const Token* token, Value::ErrorPath errorPath)
: token(token), errorPath(std::move(errorPath)), addressOf(false), inconclusive(false)
{}
LifetimeToken(const Token* token, bool addressOf, Value::ErrorPath errorPath)
: token(token), errorPath(std::move(errorPath)), addressOf(addressOf), inconclusive(false)
{}
static std::vector<LifetimeToken> setAddressOf(std::vector<LifetimeToken> v, bool b) {
for (LifetimeToken& x : v)
x.addressOf = b;
return v;
}
static std::vector<LifetimeToken> setInconclusive(std::vector<LifetimeToken> v, bool b) {
for (LifetimeToken& x : v)
x.inconclusive = b;
return v;
}
};
const Token *parseCompareInt(const Token *tok, Value &true_value, Value &false_value, const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate);
const Token *parseCompareInt(const Token *tok, Value &true_value, Value &false_value);
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
const Token* solveExprValue(const Token* expr,
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
Value& value);
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
bool escape = false,
Value::ErrorPath errorPath = Value::ErrorPath{});
bool hasLifetimeToken(const Token* tok, const Token* lifetime);
const Variable* getLifetimeVariable(const Token* tok, Value::ErrorPath& errorPath, bool* addressOf = nullptr);
const Variable* getLifetimeVariable(const Token* tok);
bool isLifetimeBorrowed(const Token *tok, const Settings *settings);
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath);
CPPCHECKLIB Value getLifetimeObjValue(const Token *tok, bool inconclusive = false);
CPPCHECKLIB std::vector<Value> getLifetimeObjValues(const Token* tok,
bool inconclusive = false,
MathLib::bigint path = 0);
const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope = nullptr, bool smallest = true);
void combineValueProperties(const Value& value1, const Value& value2, Value* result);
} }
ValueFlow::Value asImpossible(ValueFlow::Value v);
bool isContainerSizeChanged(const Token* tok, int indirect, const Settings* settings = nullptr, int depth = 20);
struct LifetimeToken {
const Token* token;
ValueFlow::Value::ErrorPath errorPath;
bool addressOf;
bool inconclusive;
LifetimeToken() : token(nullptr), errorPath(), addressOf(false), inconclusive(false) {}
LifetimeToken(const Token* token, ValueFlow::Value::ErrorPath errorPath)
: token(token), errorPath(std::move(errorPath)), addressOf(false), inconclusive(false)
{}
LifetimeToken(const Token* token, bool addressOf, ValueFlow::Value::ErrorPath errorPath)
: token(token), errorPath(std::move(errorPath)), addressOf(addressOf), inconclusive(false)
{}
static std::vector<LifetimeToken> setAddressOf(std::vector<LifetimeToken> v, bool b) {
for (LifetimeToken& x : v)
x.addressOf = b;
return v;
}
static std::vector<LifetimeToken> setInconclusive(std::vector<LifetimeToken> v, bool b) {
for (LifetimeToken& x : v)
x.inconclusive = b;
return v;
}
};
const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value, const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate);
const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value);
ValueFlow::Value inferCondition(const std::string& op, MathLib::bigint val, const Token* varTok);
ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val);
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
const Token* solveExprValue(const Token* expr,
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
ValueFlow::Value& value);
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
bool escape = false,
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});
bool hasLifetimeToken(const Token* tok, const Token* lifetime);
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);
std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ValueFlow::Value::ErrorPath &errorPath);
CPPCHECKLIB ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive = false);
CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok,
bool inconclusive = false,
MathLib::bigint path = 0);
const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope = nullptr, bool smallest = true);
void combineValueProperties(const ValueFlow::Value& value1, const ValueFlow::Value& value2, ValueFlow::Value* result);
#endif // valueflowH #endif // valueflowH