Reuse 'extractForLoopValues' in ValueFlow

This commit is contained in:
Daniel Marjamäki 2020-06-29 21:01:43 +02:00
parent 7d9220e96c
commit a0770f05e1
4 changed files with 19 additions and 50 deletions

View File

@ -438,6 +438,7 @@ const Token* getCondTokFromEnd(const Token* endBlock)
bool extractForLoopValues(const Token *forToken,
nonneg int * const varid,
bool * const knownInitValue,
MathLib::bigint * const initValue,
MathLib::bigint * const stepValue,
MathLib::bigint * const lastValue)
@ -447,10 +448,11 @@ bool extractForLoopValues(const Token *forToken,
const Token *initExpr = forToken->next()->astOperand2()->astOperand1();
const Token *condExpr = forToken->next()->astOperand2()->astOperand2()->astOperand1();
const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2();
if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%") || !initExpr->astOperand2()->hasKnownIntValue())
if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%"))
return false;
*varid = initExpr->astOperand1()->varId();
*initValue = initExpr->astOperand2()->getKnownIntValue();
*knownInitValue = initExpr->astOperand2()->hasKnownIntValue();
*initValue = (*knownInitValue) ? initExpr->astOperand2()->getKnownIntValue() : 0;
if (!Token::Match(condExpr, "<|<=") || !condExpr->isBinaryOp() || condExpr->astOperand1()->varId() != *varid || !condExpr->astOperand2()->hasKnownIntValue())
return false;
if (!incExpr || !incExpr->isUnaryOp("++") || incExpr->astOperand1()->varId() != *varid)

View File

@ -113,6 +113,7 @@ const Token* getCondTokFromEnd(const Token* endBlock);
*/
bool extractForLoopValues(const Token *forToken,
nonneg int * const varid,
bool * const knownInitValue,
long long * const initValue,
long long * const stepValue,
long long * const lastValue);

View File

@ -2371,8 +2371,9 @@ static std::string execute(const Token *start, const Token *end, Data &data)
if (Token::simpleMatch(tok, "for (")) {
nonneg int varid;
bool hasKnownInitValue;
MathLib::bigint initValue, stepValue, lastValue;
if (extractForLoopValues(tok, &varid, &initValue, &stepValue, &lastValue)) {
if (extractForLoopValues(tok, &varid, &hasKnownInitValue, &initValue, &stepValue, &lastValue) && hasKnownInitValue) {
auto loopValues = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), initValue, lastValue);
data.assignValue(tok, varid, loopValues);
tok = tok->linkAt(1);

View File

@ -4444,44 +4444,6 @@ static void valueFlowInferCondition(TokenList* tokenlist,
}
}
static bool valueFlowForLoop1(const Token *tok, int * const varid, MathLib::bigint * const num1, MathLib::bigint * const num2, MathLib::bigint * const numAfter)
{
tok = tok->tokAt(2);
if (!Token::Match(tok, "%type%| %var% ="))
return false;
const Token * const vartok = Token::Match(tok, "%var% =") ? tok : tok->next();
*varid = vartok->varId();
tok = vartok->tokAt(2);
const Token * const num1tok = Token::Match(tok, "%num% ;") ? tok : nullptr;
if (num1tok)
*num1 = MathLib::toLongNumber(num1tok->str());
while (Token::Match(tok, "%name%|%num%|%or%|+|-|*|/|&|[|]|("))
tok = (tok->str() == "(") ? tok->link()->next() : tok->next();
if (!tok || tok->str() != ";")
return false;
tok = tok->next();
const Token *num2tok = nullptr;
if (Token::Match(tok, "%varid% <|<=|!=", vartok->varId())) {
tok = tok->next();
num2tok = tok->astOperand2();
if (num2tok && num2tok->str() == "(" && !num2tok->astOperand2())
num2tok = num2tok->astOperand1();
if (!Token::Match(num2tok, "%num% ;|%oror%")) // TODO: || enlarges the scope of the condition, so it should not cause FP, but it should no lnger be part of this pattern as soon as valueFlowForLoop2 can handle an unknown RHS of || better
num2tok = nullptr;
}
if (!num2tok)
return false;
*num2 = MathLib::toLongNumber(num2tok->str()) - ((tok->str()=="<=") ? 0 : 1);
*numAfter = *num2 + 1;
if (!num1tok)
*num1 = *num2;
while (tok && tok->str() != ";")
tok = tok->next();
if (!Token::Match(tok, "; %varid% ++ ) {", vartok->varId()) && !Token::Match(tok, "; ++ %varid% ) {", vartok->varId()))
return false;
return true;
}
static bool valueFlowForLoop2(const Token *tok,
ProgramMemory *memory1,
ProgramMemory *memory2,
@ -4663,16 +4625,19 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas
!Token::simpleMatch(tok->next()->astOperand2()->astOperand2(), ";"))
continue;
int varid(0);
MathLib::bigint num1(0), num2(0), numAfter(0);
nonneg int varid;
bool knownInitValue;
MathLib::bigint initValue, stepValue, lastValue;
if (valueFlowForLoop1(tok, &varid, &num1, &num2, &numAfter)) {
if (num1 <= num2) {
valueFlowForLoopSimplify(bodyStart, varid, false, num1, tokenlist, errorLogger, settings);
valueFlowForLoopSimplify(bodyStart, varid, false, num2, tokenlist, errorLogger, settings);
valueFlowForLoopSimplifyAfter(tok, varid, numAfter, tokenlist, errorLogger, settings);
} else
valueFlowForLoopSimplifyAfter(tok, varid, num1, tokenlist, errorLogger, settings);
if (extractForLoopValues(tok, &varid, &knownInitValue, &initValue, &stepValue, &lastValue)) {
const bool executeBody = !knownInitValue || initValue <= lastValue;
if (executeBody) {
valueFlowForLoopSimplify(bodyStart, varid, false, initValue, tokenlist, errorLogger, settings);
if (stepValue == 1)
valueFlowForLoopSimplify(bodyStart, varid, false, lastValue, tokenlist, errorLogger, settings);
}
const MathLib::bigint afterValue = executeBody ? lastValue + stepValue : initValue;
valueFlowForLoopSimplifyAfter(tok, varid, afterValue, tokenlist, errorLogger, settings);
} else {
ProgramMemory mem1, mem2, memAfter;
if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) {