From afd13ea11dd403d516a9c3e5a4fa0a244d032297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 28 Jan 2023 10:20:47 +0100 Subject: [PATCH] ValueFlow: some interface and namespace cleanups (#4746) --- lib/astutils.cpp | 6 +- lib/checkautovariables.cpp | 12 +-- lib/checkbufferoverrun.cpp | 2 +- lib/checkother.cpp | 6 +- lib/checkstl.cpp | 4 +- lib/checkunusedvar.cpp | 2 +- lib/programmemory.cpp | 6 +- lib/valueflow.cpp | 157 +++++++++++++++++-------------------- lib/valueflow.h | 147 +++++++++++++++++----------------- 9 files changed, 163 insertions(+), 179 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index bd0ddc59a..8d888179b 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -879,7 +879,7 @@ bool extractForLoopValues(const Token *forToken, const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2(); if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%")) return false; - std::vector minInitValue = getMinValue(makeIntegralInferModel(), initExpr->astOperand2()->values()); + std::vector minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values()); *varid = initExpr->astOperand1()->varId(); *knownInitValue = initExpr->astOperand2()->hasKnownIntValue(); *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) { - ValueFlow::Value v1 = getLifetimeObjValue(tok1); + ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1); if (!v1.isLifetimeValue()) return false; - ValueFlow::Value v2 = getLifetimeObjValue(tok2); + ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2); if (!v2.isLifetimeValue()) return false; return v1.tokvalue == v2.tokvalue; diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 6866205b5..f048709ba 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -518,7 +518,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token for (const Token *tok = start; tok && tok != end; tok = tok->next()) { // Return reference from function 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) continue; 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()->isArgument()) { ErrorPath errorPath; - const Variable *var = getLifetimeVariable(tok, errorPath); + const Variable *var = ValueFlow::getLifetimeVariable(tok, errorPath); if (var && isInScope(var->nameToken(), tok->scope())) { errorDanglingReference(tok, var, errorPath); continue; } // Reference to temporary } 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) continue; 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); if (!exprs.insert(parent).second) 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; if (val.isLocalLifetimeValue()) { if (escape) { if (getPointerDepth(tok) < getPointerDepth(tokvalue)) continue; - if (!isLifetimeBorrowed(tok, mSettings)) + if (!ValueFlow::isLifetimeBorrowed(tok, mSettings)) continue; if (tokvalue->exprId() == tok->exprId() && !(tok->variable() && tok->variable()->isArray()) && !astIsContainerView(tok->astParent())) @@ -604,7 +604,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token } else if (tok->variable() && tok->variable()->declarationId() == tok->varId()) { var = tok->variable(); } - if (!isLifetimeBorrowed(tok, mSettings)) + if (!ValueFlow::isLifetimeBorrowed(tok, mSettings)) continue; const Token* nextTok = nextAfterAstRightmostLeaf(tok->astTop()); if (!nextTok) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index f3a1959e8..73e9dc2b5 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1030,7 +1030,7 @@ void CheckBufferOverrun::objectIndex() if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0) continue; - std::vector values = getLifetimeObjValues(obj, false, -1); + std::vector values = ValueFlow::getLifetimeObjValues(obj, false, -1); for (const ValueFlow::Value& v:values) { if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) continue; diff --git a/lib/checkother.cpp b/lib/checkother.cpp index d5766ac5a..8eb5097d0 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1446,7 +1446,7 @@ void CheckOther::checkConstVariable() retTok = retTok->astOperand2(); while (Token::simpleMatch(retTok, ".")) retTok = retTok->astOperand2(); - return hasLifetimeToken(getParentLifetime(retTok), var->nameToken()); + return ValueFlow::hasLifetimeToken(getParentLifetime(retTok), var->nameToken()); })) continue; } @@ -3671,8 +3671,8 @@ void CheckOther::checkComparePointers() const Token *tok2 = tok->astOperand2(); if (!astIsPointer(tok1) || !astIsPointer(tok2)) continue; - ValueFlow::Value v1 = getLifetimeObjValue(tok1); - ValueFlow::Value v2 = getLifetimeObjValue(tok2); + ValueFlow::Value v1 = ValueFlow::getLifetimeObjValue(tok1); + ValueFlow::Value v2 = ValueFlow::getLifetimeObjValue(tok2); if (!v1.isLocalLifetimeValue() || !v2.isLocalLifetimeValue()) continue; const Variable *var1 = v1.tokvalue->variable(); diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index 9f7328501..c6919fcce 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -727,7 +727,7 @@ static bool isSameIteratorContainerExpression(const Token* tok1, static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0) { - std::vector values = getLifetimeObjValues(tok, false, path); + std::vector values = ValueFlow::getLifetimeObjValues(tok, false, path); auto it = std::find_if(values.cbegin(), values.cend(), [](const ValueFlow::Value& v) { return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator; }); @@ -1155,7 +1155,7 @@ void CheckStl::invalidContainer() ErrorPath ep; 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 if (var && var->declarationId() == r.tok->varId() && !addressOf) { // An argument always reaches diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 07e7a5567..5b3e69b2f 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1287,7 +1287,7 @@ void CheckUnusedVar::checkFunctionVariableUsage() continue; 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 (!bailoutTypeName.empty()) { if (bailoutTypeName != "auto") diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index ed92134c2..a65805834 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -1274,13 +1274,13 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const if (expr->isComparisonOp()) { if (rhs.isIntValue()) { std::vector result = - infer(makeIntegralInferModel(), expr->str(), expr->astOperand1()->values(), {rhs}); + infer(ValueFlow::makeIntegralInferModel(), expr->str(), expr->astOperand1()->values(), {rhs}); if (result.empty() || !result.front().isKnown()) return unknown; return result.front(); } else if (lhs.isIntValue()) { std::vector result = - infer(makeIntegralInferModel(), expr->str(), {lhs}, expr->astOperand2()->values()); + infer(ValueFlow::makeIntegralInferModel(), expr->str(), {lhs}, expr->astOperand2()->values()); if (result.empty() || !result.front().isKnown()) return unknown; 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())) { ValueFlow::Value& v = pm.at(child->exprId()); if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { - if (isContainerSizeChanged(child, v.indirect, settings)) + if (ValueFlow::isContainerSizeChanged(child, v.indirect, settings)) v = unknown; } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) { if (isVariableChanged(child, v.indirect, settings, true)) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5f908aa97..1b6db105f 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -343,10 +343,10 @@ static void parseCompareEachInt( }); } -const Token* parseCompareInt(const Token* tok, - ValueFlow::Value& true_value, - ValueFlow::Value& false_value, - const std::function(const Token*)>& evaluate) +const Token* ValueFlow::parseCompareInt(const Token* tok, + ValueFlow::Value& true_value, + ValueFlow::Value& false_value, + const std::function(const Token*)>& evaluate) { const Token* result = nullptr; parseCompareEachInt( @@ -370,7 +370,7 @@ const Token* parseCompareInt(const Token* tok, 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 { if (t->hasKnownIntValue()) @@ -417,7 +417,7 @@ static bool isNumeric(const ValueFlow::Value& value) { 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()) result->setKnown(); @@ -688,7 +688,7 @@ static void setTokenValue(Token* tok, } if (value.isLifetimeValue()) { - if (!isLifetimeBorrowed(parent, settings)) + if (!ValueFlow::isLifetimeBorrowed(parent, settings)) return; if (value.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator && astIsIterator(parent)) { setTokenValue(parent,value,settings); @@ -1288,7 +1288,6 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b return tok->next(); } - static void valueFlowNumber(TokenList *tokenlist) { for (Token *tok = tokenlist->front(); tok;) { @@ -1973,8 +1972,8 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti } } -ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist); -ValuePtr makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist); +static ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist); +static ValuePtr makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Value& value, const TokenList* tokenlist); static Analyzer::Result valueFlowForward(Token* startToken, const Token* endToken, @@ -3229,7 +3228,7 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer { 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; if (!val) @@ -3253,7 +3252,7 @@ std::string lifetimeType(const Token *tok, const ValueFlow::Value *val) 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 Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr; @@ -3291,7 +3290,7 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Error return msg; } -std::vector getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path) +std::vector ValueFlow::getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path) { std::vector result; auto pred = [&](const ValueFlow::Value& v) { @@ -3338,9 +3337,9 @@ static bool derefShared(const Token* tok) return !hasUniqueOwnership(ptrTok); } -ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive) +ValueFlow::Value ValueFlow::getLifetimeObjValue(const Token *tok, bool inconclusive) { - std::vector values = getLifetimeObjValues(tok, inconclusive); + std::vector values = ValueFlow::getLifetimeObjValues(tok, inconclusive); // There should only be one lifetime if (values.size() != 1) return ValueFlow::Value{}; @@ -3348,16 +3347,16 @@ ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive) } template -static std::vector getLifetimeTokens(const Token* tok, - bool escape, - ValueFlow::Value::ErrorPath errorPath, - Predicate pred, - int depth = 20) +static std::vector getLifetimeTokens(const Token* tok, + bool escape, + ValueFlow::Value::ErrorPath errorPath, + Predicate pred, + int depth = 20) { if (!tok) - return std::vector {}; + return std::vector {}; if (Token::simpleMatch(tok, "...")) - return std::vector{}; + return std::vector{}; const Variable *var = tok->variable(); if (pred(tok)) return {{tok, std::move(errorPath)}}; @@ -3392,9 +3391,9 @@ static std::vector getLifetimeTokens(const Token* tok, if (astIsContainer(contok)) return getLifetimeTokens(contok, escape, std::move(errorPath), pred, depth - 1); else - return std::vector{}; + return std::vector{}; } else { - return std::vector {}; + return std::vector {}; } } } else if (Token::Match(tok->previous(), "%name% (")) { @@ -3402,12 +3401,12 @@ static std::vector getLifetimeTokens(const Token* tok, if (f) { if (!Function::returnsReference(f)) return {{tok, std::move(errorPath)}}; - std::vector result; + std::vector result; std::vector returns = Function::findReturns(f); for (const Token* returnTok : returns) { if (returnTok == tok) 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 Variable* argvar = argvarTok->variable(); if (!argvar) @@ -3416,11 +3415,11 @@ static std::vector getLifetimeTokens(const Token* tok, if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { const int n = getArgumentPos(argvar, f); if (n < 0) - return std::vector {}; + return std::vector {}; std::vector args = getArguments(tok->previous()); // TODO: Track lifetimes of default parameters if (n >= args.size()) - return std::vector {}; + return std::vector {}; argTok = args[n]; lt.errorPath.emplace_back(returnTok, "Return reference."); lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); @@ -3432,7 +3431,7 @@ static std::vector getLifetimeTokens(const Token* tok, "Calling member function on '" + argTok->expressionString() + "'."); } if (argTok) { - std::vector arglts = LifetimeToken::setInconclusive( + std::vector arglts = ValueFlow::LifetimeToken::setInconclusive( getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, depth - returns.size()), returns.size() > 1); result.insert(result.end(), arglts.cbegin(), arglts.cend()); @@ -3445,7 +3444,7 @@ static std::vector getLifetimeTokens(const Token* tok, const Library::Container::Yield y = library->getYield(tok->previous()->str()); if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) { 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), false); } @@ -3474,8 +3473,8 @@ static std::vector getLifetimeTokens(const Token* tok, return getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, depth - 1); } } else { - return LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, depth - 1), - !(astIsContainer(vartok) && Token::simpleMatch(vartok->astParent(), "["))); + return ValueFlow::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()) { @@ -3490,14 +3489,14 @@ static std::vector getLifetimeTokens(const Token* tok, return {{tok, std::move(errorPath)}}; } -std::vector getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath) +std::vector ValueFlow::getLifetimeTokens(const Token* tok, bool escape, ValueFlow::Value::ErrorPath errorPath) { return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) { return false; }); } -bool hasLifetimeToken(const Token* tok, const Token* lifetime) +bool ValueFlow::hasLifetimeToken(const Token* tok, const Token* lifetime) { bool result = false; 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) { - std::vector lts = getLifetimeTokens(tok); + std::vector lts = ValueFlow::getLifetimeTokens(tok); if (lts.size() != 1) return nullptr; if (lts.front().inconclusive) @@ -3520,7 +3519,7 @@ static const Token* getLifetimeToken(const Token* tok, ValueFlow::Value::ErrorPa 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); if (tok2 && tok2->variable()) @@ -3528,7 +3527,7 @@ const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPat return nullptr; } -const Variable* getLifetimeVariable(const Token* tok) +const Variable* ValueFlow::getLifetimeVariable(const Token* tok) { ValueFlow::Value::ErrorPath errorPath; return getLifetimeVariable(tok, errorPath, nullptr); @@ -3662,7 +3661,7 @@ static bool isDifferentType(const Token* src, const Token* dst) return false; } -bool isLifetimeBorrowed(const Token *tok, const Settings *settings) +bool ValueFlow::isLifetimeBorrowed(const Token *tok, const Settings *settings) { if (!tok) return true; @@ -3729,7 +3728,7 @@ static const Token* getEndOfVarScope(const Variable* var) 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; bool local = false; @@ -3767,7 +3766,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog if (Token::Match(tok->previous(), "%var% {|(") && isVariableDecl(tok->previous())) { std::list values = tok->values(); values.remove_if(&isNotLifetimeValue); - valueFlowForward(nextAfterAstRightmostLeaf(tok), getEndOfExprScope(tok), tok->previous(), values, tokenlist); + valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), values, tokenlist); return; } Token *parent = tok->astParent(); @@ -3781,7 +3780,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog if (!parent->astOperand2() || parent->astOperand2()->values().empty()) return; - if (!isLifetimeBorrowed(parent->astOperand2(), settings)) + if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings)) return; const Token* expr = getLHSVariableToken(parent); @@ -3791,7 +3790,7 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog if (expr->exprId() == 0) return; - const Token* endOfVarScope = getEndOfExprScope(expr); + const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr); // Only forward lifetime values std::list values = parent->astOperand2()->values(); @@ -3938,7 +3937,7 @@ struct LifetimeStore { if (!argtok) return 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) continue; ErrorPath er = errorPath; @@ -4000,7 +3999,7 @@ struct LifetimeStore { if (argtok->values().empty()) { ErrorPath er; 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) continue; ValueFlow::Value value; @@ -4029,7 +4028,7 @@ struct LifetimeStore { if (!v.isLifetimeValue()) continue; 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) continue; ErrorPath er = v.errorPath; @@ -4101,7 +4100,7 @@ struct LifetimeStore { continue; const Token *tok2 = v.tokvalue; ErrorPath er = v.errorPath; - const Variable *var = getLifetimeVariable(tok2, er); + const Variable *var = ValueFlow::getLifetimeVariable(tok2, er); // TODO: the inserted data is never used er.insert(er.end(), errorPath.cbegin(), errorPath.cend()); if (!var) @@ -4199,9 +4198,9 @@ static void valueFlowLifetimeUserConstructor(Token* tok, const Token* expr = tok2->astOperand2(); if (!var) continue; - if (!isLifetimeBorrowed(expr, settings)) + if (!ValueFlow::isLifetimeBorrowed(expr, settings)) continue; - const Variable* argvar = getLifetimeVariable(expr); + const Variable* argvar = ValueFlow::getLifetimeVariable(expr); if (var->isReference() || var->isRValueReference()) { if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { paramCapture[argvar] = LifetimeCapture::ByReference; @@ -4312,7 +4311,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog LifetimeStore{ args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} .byDerefCopy(memtok, tokenlist, errorLogger, settings); - } else if (!args.empty() && isLifetimeBorrowed(args.back(), settings)) { + } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) { LifetimeStore{ args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} .byVal(memtok, tokenlist, errorLogger, settings); @@ -4331,7 +4330,7 @@ static void valueFlowLifetimeFunction(Token *tok, TokenList *tokenlist, ErrorLog for (const Token* returnTok : returns) { if (returnTok == tok) continue; - const Variable *returnVar = getLifetimeVariable(returnTok); + const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok); if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings, tokenlist->isCPP()))) { LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, errorLogger); ls.inconclusive = inconclusive; @@ -4750,7 +4749,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase* /*db*/, Erro } // address of 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) continue; ErrorPath errorPath = lt.errorPath; @@ -4869,7 +4868,7 @@ static void valueFlowLifetime(TokenList *tokenlist, SymbolDatabase* /*db*/, Erro // Check variables else if (tok->variable()) { ErrorPath errorPath; - const Variable * var = getLifetimeVariable(tok, errorPath); + const Variable * var = ValueFlow::getLifetimeVariable(tok, errorPath); if (!var) continue; if (var->nameToken() == tok) @@ -5002,7 +5001,7 @@ static void valueFlowAfterMove(TokenList* tokenlist, SymbolDatabase* symboldatab continue; if (parent && parent->astOperand1() && parent->astOperand1()->varId() == varId) continue; - const Token* const endOfVarScope = getEndOfExprScope(varTok); + const Token* const endOfVarScope = ValueFlow::getEndOfExprScope(varTok); const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok); const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove); @@ -5261,7 +5260,7 @@ static void valueFlowSymbolic(TokenList* tokenlist, SymbolDatabase* symboldataba continue; 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()); rhs.errorPath.emplace_back(tok, @@ -5306,6 +5305,8 @@ static const Token* isStrlenOf(const Token* tok, const Token* expr, int depth = return nullptr; } +static ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val); + static void valueFlowSymbolicOperators(TokenList* tokenlist, SymbolDatabase* symboldatabase) { for (const Scope* scope : symboldatabase->functionScopes) { @@ -5530,7 +5531,7 @@ static void valueFlowForwardAssign(Token* const tok, { if (Token::simpleMatch(tok->astParent(), "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))) { valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); 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); } -ValueFlow::Value asImpossible(ValueFlow::Value v) +ValueFlow::Value ValueFlow::asImpossible(ValueFlow::Value v) { v.invertRange(); v.setImpossible(); @@ -5881,7 +5882,7 @@ ValueFlow::Value asImpossible(ValueFlow::Value v) static void insertImpossible(std::list& values, const std::list& 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& values, const std::list& input) @@ -6476,7 +6477,7 @@ struct ConditionHandler { 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 makeIntegralInferModel() { +ValuePtr ValueFlow::makeIntegralInferModel() { return IntegralInferModel{}; } @@ -6564,18 +6565,6 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math 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 r = infer(IntegralInferModel{}, op, val, varTok->values()); - if (r.size() == 1 && r.front().isKnown()) - return r.front(); - return ValueFlow::Value{}; -} - struct IteratorInferModel : InferModel { virtual ValueFlow::Value::ValueType getType() const = 0; bool match(const ValueFlow::Value& value) const override { @@ -6944,14 +6933,14 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas if (executeBody && vartok) { std::list initValues; 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); if (!result.action.isModified()) { std::list lastValues; lastValues.emplace_back(lastValue, ValueFlow::Value::Bound::Upper); lastValues.back().conditional = true; - lastValues.push_back(asImpossible(lastValues.back())); + lastValues.push_back(ValueFlow::asImpossible(lastValues.back())); if (stepValue != 1) lastValues.pop_front(); valueFlowForward(bodyStart, bodyStart->link(), vartok, lastValues, tokenlist); @@ -7838,7 +7827,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { return Action::Invalid; if (isLikelyStreamRead(isCPP(), tok->astParent())) 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; } @@ -7871,9 +7860,9 @@ static const Token* parseBinaryIntOp(const Token* expr, return varTok; } -const Token* solveExprValue(const Token* expr, - const std::function(const Token*)>& eval, - ValueFlow::Value& value) +const Token* ValueFlow::solveExprValue(const Token* expr, + const std::function(const Token*)>& eval, + ValueFlow::Value& value) { if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue()) return expr; @@ -7889,24 +7878,24 @@ const Token* solveExprValue(const Token* expr, switch (expr->str()[0]) { case '+': { value.intvalue -= intval; - return solveExprValue(binaryTok, eval, value); + return ValueFlow::solveExprValue(binaryTok, eval, value); } case '-': { if (rhs) value.intvalue = intval - value.intvalue; else value.intvalue += intval; - return solveExprValue(binaryTok, eval, value); + return ValueFlow::solveExprValue(binaryTok, eval, value); } case '*': { if (intval == 0) break; value.intvalue /= intval; - return solveExprValue(binaryTok, eval, value); + return ValueFlow::solveExprValue(binaryTok, eval, value); } case '^': { 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) { - return solveExprValue( + return ValueFlow::solveExprValue( expr, [](const Token* tok) -> std::vector { if (tok->hasKnownIntValue()) @@ -7940,7 +7929,7 @@ ValuePtr makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Va 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) return false; @@ -7991,7 +7980,7 @@ static bool isContainerSizeChanged(nonneg int varId, for (const Token *tok = start; tok != end; tok = tok->next()) { if (tok->varId() != varId) continue; - if (isContainerSizeChanged(tok, indirect, settings, depth)) + if (ValueFlow::isContainerSizeChanged(tok, indirect, settings, depth)) return true; } return false; diff --git a/lib/valueflow.h b/lib/valueflow.h index 020d3b7c0..007154eae 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -47,7 +47,7 @@ class ValuePtr; namespace ValueFlow { /// 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. 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); - const ValueFlow::Value* findValue(const std::list& values, - const Settings* settings, - const std::function &pred); + const Value* findValue(const std::list& values, + const Settings* settings, + const std::function &pred); - std::vector isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true); + std::vector 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 setAddressOf(std::vector v, bool b) { + for (LifetimeToken& x : v) + x.addressOf = b; + return v; + } + + static std::vector setInconclusive(std::vector 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(const Token*)>& evaluate); + const Token *parseCompareInt(const Token *tok, Value &true_value, Value &false_value); + + CPPCHECKLIB ValuePtr makeIntegralInferModel(); + + const Token* solveExprValue(const Token* expr, + const std::function(const Token*)>& eval, + Value& value); + + std::vector 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 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 setAddressOf(std::vector v, bool b) { - for (LifetimeToken& x : v) - x.addressOf = b; - return v; - } - - static std::vector setInconclusive(std::vector 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(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 makeIntegralInferModel(); - -const Token* solveExprValue(const Token* expr, - const std::function(const Token*)>& eval, - ValueFlow::Value& value); - -std::vector 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 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