42 #include <type_traits> 
   47     struct ForwardTraversal {
 
   48         enum class Progress { Continue, Break, Skip };
 
   51             : analyzer(analyzer), tokenList(tokenList), errorLogger(errorLogger), settings(settings)
 
   59         bool analyzeTerminate{};
 
   61         std::vector<Token*> loopEnds;
 
   67             return Progress::Break;
 
   71             explicit Branch(
Token* tok = 
nullptr) : endBlock(tok) {}
 
   72             Token* endBlock = 
nullptr;
 
   76             bool escapeUnknown = 
false;
 
   78             bool isEscape()
 const {
 
   79                 return escape || escapeUnknown;
 
   81             bool isConclusiveEscape()
 const {
 
   82                 return escape && !escapeUnknown;
 
   84             bool isModified()
 const {
 
   85                 return action.
isModified() && !isConclusiveEscape();
 
   87             bool isInconclusive()
 const {
 
  100         std::pair<bool, bool> evalCond(
const Token* tok, 
const Token* ctx = 
nullptr)
 const {
 
  102                 return std::make_pair(
false, 
false);
 
  103             std::vector<MathLib::bigint> result = analyzer->evaluate(tok, ctx);
 
  105             const bool checkThen = std::any_of(result.cbegin(), result.cend(), [](
int x) {
 
  108             const bool checkElse = std::any_of(result.cbegin(), result.cend(), [](
int x) {
 
  111             return std::make_pair(checkThen, checkElse);
 
  114         bool isConditionTrue(
const Token* tok, 
const Token* ctx = 
nullptr)
 const {
 
  115             return evalCond(tok, ctx).first;
 
  118         template<
class T, 
class F, 
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
 
  119         Progress traverseTok(T* tok, 
const F &f, 
bool traverseUnknown, T** out = 
nullptr) {
 
  124                 traverseRecursive(tok->next()->astOperand2(), f, traverseUnknown);
 
  128                 if (loopEnds.empty())
 
  132                     *out = loopEnds.back();
 
  134                 traverseRecursive(tok->astOperand2(), f, traverseUnknown);
 
  135                 traverseRecursive(tok->astOperand1(), f, traverseUnknown);
 
  139                 traverseRecursive(tok->next()->astOperand2(), f, traverseUnknown);
 
  144                 return Progress::Skip;
 
  145             } 
else if (tok->astOperand1() && tok->astOperand2() && 
Token::Match(tok, 
"?|&&|%oror%")) {
 
  146                 if (traverseConditional(tok, f, traverseUnknown) == Progress::Break)
 
  150                 return Progress::Skip;
 
  153                 if (checkScope(lambdaEndToken).isModified())
 
  156                     *out = lambdaEndToken->next();
 
  158             } 
else if (tok->str() == 
"{" && tok->scope() && tok->scope()->isClassOrStruct()) {
 
  162                 if (f(tok) == Progress::Break)
 
  165             return Progress::Continue;
 
  168         template<
class T, 
class F, 
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
 
  169         Progress traverseRecursive(T* tok, 
const F &f, 
bool traverseUnknown, 
unsigned int recursion=0) {
 
  171                 return Progress::Continue;
 
  172             if (recursion > 10000)
 
  173                 return Progress::Skip;
 
  174             T* firstOp = tok->astOperand1();
 
  175             T* secondOp = tok->astOperand2();
 
  181                 std::swap(firstOp, secondOp);
 
  182             if (firstOp && traverseRecursive(firstOp, f, traverseUnknown, recursion+1) == Progress::Break)
 
  184             const Progress p = tok->isAssignmentOp() ? Progress::Continue : traverseTok(tok, f, traverseUnknown);
 
  185             if (p == Progress::Break)
 
  187             if (p == Progress::Continue && secondOp && traverseRecursive(secondOp, f, traverseUnknown, recursion+1) == Progress::Break)
 
  189             if (tok->isAssignmentOp() && traverseTok(tok, f, traverseUnknown) == Progress::Break)
 
  191             return Progress::Continue;
 
  194         template<
class T, 
class F, 
REQUIRES(
"T must be a Token class", std::is_convertible<T*, const Token*> )>
 
  195         Progress traverseConditional(T* tok, F f, 
bool traverseUnknown) {
 
  196             if (
Token::Match(tok, 
"?|&&|%oror%") && tok->astOperand1() && tok->astOperand2()) {
 
  197                 T* condTok = tok->astOperand1();
 
  198                 T* childTok = tok->astOperand2();
 
  199                 bool checkThen, checkElse;
 
  200                 std::tie(checkThen, checkElse) = evalCond(condTok);
 
  201                 if (!checkThen && !checkElse) {
 
  202                     if (!traverseUnknown && analyzer->stopOnCondition(condTok) && stopUpdates()) {
 
  203                         return Progress::Continue;
 
  208                 if (childTok->str() == 
":") {
 
  209                     if (checkThen && traverseRecursive(childTok->astOperand1(), f, traverseUnknown) == Progress::Break)
 
  211                     if (checkElse && traverseRecursive(childTok->astOperand2(), f, traverseUnknown) == Progress::Break)
 
  214                     if (!checkThen && tok->str() == 
"&&")
 
  215                         return Progress::Continue;
 
  216                     if (!checkElse && tok->str() == 
"||")
 
  217                         return Progress::Continue;
 
  218                     if (traverseRecursive(childTok, f, traverseUnknown) == Progress::Break)
 
  222             return Progress::Continue;
 
  225         Progress update(
Token* tok) {
 
  228             if (!action.
isNone() && !analyzeOnly)
 
  237             return Progress::Continue;
 
  240         Progress updateTok(
Token* tok, 
Token** out = 
nullptr) {
 
  241             auto f = [
this](
Token* tok2) {
 
  244             return traverseTok(tok, f, 
false, out);
 
  247         Progress updateRecursive(
Token* tok) {
 
  248             auto f = [
this](
Token* tok2) {
 
  251             return traverseRecursive(tok, f, 
false);
 
  256             auto f = [&](
const Token* tok) {
 
  260                 return Progress::Continue;
 
  262             traverseRecursive(start, f, 
true);
 
  268             for (
const Token* tok = start; tok && tok != end; tok = tok->
next()) {
 
  277         ForwardTraversal fork(
bool analyze = 
false)
 const {
 
  278             ForwardTraversal ft = *
this;
 
  280                 ft.analyzeOnly = 
true;
 
  281                 ft.analyzeTerminate = 
true;
 
  287         std::vector<ForwardTraversal> tryForkScope(
Token* endBlock, 
bool isModified = 
false)
 const {
 
  288             if (analyzer->updateScope(endBlock, isModified)) {
 
  289                 ForwardTraversal ft = fork();
 
  290                 return {std::move(ft)};
 
  292             return std::vector<ForwardTraversal> {};
 
  295         std::vector<ForwardTraversal> tryForkUpdateScope(
Token* endBlock, 
bool isModified = 
false)
 const {
 
  296             std::vector<ForwardTraversal> result = tryForkScope(endBlock, isModified);
 
  297             for (ForwardTraversal& ft : result)
 
  298                 ft.updateScope(endBlock);
 
  302         static bool hasGoto(
const Token* endBlock) {
 
  306         static bool hasJump(
const Token* endBlock) {
 
  310         bool hasInnerReturnScope(
const Token* start, 
const Token* end)
 const {
 
  311             for (
const Token* tok=start; tok != end; tok = tok->
previous()) {
 
  313                     const Token* ftok = 
nullptr;
 
  323             const Token* ftok = 
nullptr;
 
  336             return analyzeRange(endBlock->
link(), endBlock);
 
  350         bool checkBranch(Branch& branch)
 const {
 
  353             std::vector<ForwardTraversal> ft1 = tryForkUpdateScope(branch.endBlock, a.
isModified());
 
  354             const bool bail = hasGoto(branch.endBlock);
 
  358                     if (!branch.escape && hasInnerReturnScope(branch.endBlock->previous(), branch.endBlock->link())) {
 
  359                         ForwardTraversal ft2 = fork(
true);
 
  360                         ft2.updateScope(branch.endBlock);
 
  362                             branch.escape = 
true;
 
  363                             branch.escapeUnknown = 
false;
 
  368                         branch.escape = 
true;
 
  369                         branch.escapeUnknown = 
false;
 
  376         bool reentersLoop(
Token* endBlock, 
const Token* condTok, 
const Token* stepTok)
 const {
 
  381             bool stepChangesCond = 
false;
 
  384                 if (exprToks.first != 
nullptr && exprToks.second != 
nullptr)
 
  390             const bool condChanged =
 
  394             const bool changed = stepChangesCond || bodyChangesCond || condChanged;
 
  397             ForwardTraversal ft = fork(
true);
 
  398             ft.updateScope(endBlock);
 
  399             return ft.isConditionTrue(condTok) && bodyChangesCond;
 
  402         Progress updateInnerLoop(
Token* endBlock, 
Token* stepTok, 
Token* condTok) {
 
  403             loopEnds.push_back(endBlock);
 
  407             if (endBlock && updateScope(endBlock) == Progress::Break)
 
  409             if (stepTok && updateRecursive(stepTok) == Progress::Break)
 
  411             if (condTok && !
Token::simpleMatch(condTok, 
":") && updateRecursive(condTok) == Progress::Break)
 
  413             return Progress::Continue;
 
  416         Progress updateLoop(
const Token* endToken,
 
  419                             Token* initTok = 
nullptr,
 
  420                             Token* stepTok = 
nullptr,
 
  422             if (initTok && updateRecursive(initTok) == Progress::Break)
 
  424             const bool isDoWhile = 
precedes(endBlock, condTok);
 
  425             bool checkThen = 
true;
 
  426             bool checkElse = 
false;
 
  428                 std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->
previous() : 
nullptr);
 
  430             if (checkElse && exit) {
 
  431                 if (hasJump(endBlock)) {
 
  432                     if (!analyzer->lowerToPossible())
 
  434                     if (analyzer->isConditional() && stopUpdates())
 
  437                 return Progress::Continue;
 
  443                 condAnalysis = analyzeRecursive(condTok);
 
  444                 allAnalysis |= condAnalysis;
 
  447                 allAnalysis |= analyzeRecursive(stepTok);
 
  448             actions |= allAnalysis;
 
  450             if (checkElse && isDoWhile &&
 
  453                 if (updateScope(endBlock) == Progress::Break)
 
  455                 return updateRecursive(condTok);
 
  458                 if (!analyzer->lowerToInconclusive())
 
  461                 if (!analyzer->lowerToPossible())
 
  467                     if (updateRecursive(condTok) == Progress::Break)
 
  470             if (!checkThen && !checkElse && !isDoWhile && analyzer->stopOnCondition(condTok) && stopUpdates())
 
  474                 return Progress::Continue;
 
  475             if (checkThen || isDoWhile) {
 
  479                 if (updateInnerLoop(endBlock, stepTok, condTok) == Progress::Break)
 
  482                 if (allAnalysis.
isModified() && reentersLoop(endBlock, condTok, stepTok))
 
  487                 std::vector<ForwardTraversal> ftv = tryForkScope(endBlock, allAnalysis.
isModified());
 
  488                 bool forkContinue = 
true;
 
  489                 for (ForwardTraversal& ft : ftv) {
 
  492                     if (ft.updateInnerLoop(endBlock, stepTok, condTok) == Progress::Break)
 
  493                         forkContinue = 
false;
 
  496                 if (allAnalysis.
isModified() || !forkContinue) {
 
  500                     if (analyzer->isConditional() && stopUpdates())
 
  502                     analyzer->assume(condTok, 
false);
 
  505                     for (ForwardTraversal& ft : ftv) {
 
  506                         if (!ft.actions.isIncremental())
 
  507                             ft.updateRange(endBlock, endToken);
 
  513                 if (updateInnerLoop(endBlock, stepTok, condTok) == Progress::Break)
 
  514                     return Progress::Break;
 
  518             return Progress::Continue;
 
  521         Progress updateLoopExit(
const Token* endToken,
 
  524                                 Token* initTok = 
nullptr,
 
  525                                 Token* stepTok = 
nullptr) {
 
  526             return updateLoop(endToken, endBlock, condTok, initTok, stepTok, 
true);
 
  529         Progress updateScope(
Token* endBlock, 
int depth = 20)
 
  533             assert(endBlock->
link());
 
  534             Token* ctx = endBlock->
link()->previous();
 
  536                 ctx = ctx->
link()->previous();
 
  538                 analyzer->updateState(ctx);
 
  539             return updateRange(endBlock->
link(), endBlock, depth);
 
  542         Progress updateRange(
Token* start, 
const Token* end, 
int depth = 20) {
 
  547                 Token* next = 
nullptr;
 
  548                 if (tok->
index() <= i)
 
  559                     if (tok->
str() == 
"<") {
 
  567                     if (updateRecursive(assignTok) == Progress::Break)
 
  586                         if (updateLoop(end, endBlock, condTok, 
nullptr, stepTok) == Progress::Break)
 
  589                 } 
else if (tok->
str() == 
"break") {
 
  593                     tok = skipTo(tok, scopeEndToken, end);
 
  596                     if (!analyzer->lowerToPossible())
 
  602                     if (!analyzer->lowerToPossible())
 
  604                 } 
else if (tok->
link() && tok->
str() == 
"}") {
 
  615                         if (!condTok->hasKnownIntValue() || inLoop) {
 
  616                             if (!analyzer->lowerToPossible())
 
  618                         } 
else if (condTok->values().front().intvalue == inElse) {
 
  623                             Token* stepTok = getStepTokFromEnd(tok);
 
  624                             bool checkThen, checkElse;
 
  625                             std::tie(checkThen, checkElse) = evalCond(condTok);
 
  626                             if (stepTok && !checkElse) {
 
  627                                 if (updateRecursive(stepTok) == Progress::Break)
 
  629                                 if (updateRecursive(condTok) == Progress::Break)
 
  632                                 std::tie(checkThen, checkElse) = evalCond(condTok);
 
  635                                 if (updateLoopExit(end, tok, condTok, 
nullptr, stepTok) == Progress::Break)
 
  644                         if (!analyzer->lowerToPossible())
 
  653                         reportError(
Severity::information, 
"normalCheckLevelMaxBranches", 
"Limiting analysis of branches. Use --check-level=exhaustive to analyze all branches.");
 
  660                     if (initTok && updateRecursive(initTok) == Progress::Break)
 
  666                             if (conTok && updateRecursive(conTok) == Progress::Break)
 
  668                             bool isEmpty = 
false;
 
  669                             std::vector<MathLib::bigint> result =
 
  674                                 isEmpty = result.front() != 0;
 
  675                             if (!isEmpty && updateLoop(end, endBlock, condTok) == Progress::Break)
 
  680                             if (updateLoop(end, endBlock, condTok, 
nullptr, stepTok) == Progress::Break)
 
  686                         if (updateRecursive(condTok) == Progress::Break)
 
  688                         Branch thenBranch{endBlock};
 
  689                         Branch elseBranch{endBlock->
tokAt(2) ? endBlock->
linkAt(2) : 
nullptr};
 
  691                         std::tie(thenBranch.check, elseBranch.check) = evalCond(condTok);
 
  692                         if (!thenBranch.check && !elseBranch.check && analyzer->stopOnCondition(condTok) && stopUpdates())
 
  698                         thenBranch.escape = 
isEscapeScope(endBlock, thenBranch.escapeUnknown);
 
  699                         if (thenBranch.check) {
 
  700                             thenBranch.active = 
true;
 
  701                             if (updateScope(endBlock, depth - 1) == Progress::Break)
 
  703                         } 
else if (!elseBranch.check) {
 
  704                             thenBranch.active = 
true;
 
  705                             if (checkBranch(thenBranch))
 
  711                             if (elseBranch.check) {
 
  712                                 elseBranch.active = 
true;
 
  713                                 const Progress result = updateScope(endBlock->
linkAt(2), depth - 1);
 
  714                                 if (result == Progress::Break)
 
  716                             } 
else if (!thenBranch.check) {
 
  717                                 elseBranch.active = 
true;
 
  718                                 if (checkBranch(elseBranch))
 
  721                             tok = endBlock->
linkAt(2);
 
  725                         if (thenBranch.active)
 
  726                             actions |= thenBranch.action;
 
  727                         if (elseBranch.active)
 
  728                             actions |= elseBranch.action;
 
  731                         if (thenBranch.isDead() && elseBranch.isDead()) {
 
  732                             if (thenBranch.isModified() && elseBranch.isModified())
 
  734                             if (thenBranch.isConclusiveEscape() && elseBranch.isConclusiveEscape())
 
  739                         if (thenBranch.active && thenBranch.isEscape() && !hasElse) {
 
  740                             if (!thenBranch.isConclusiveEscape()) {
 
  741                                 if (!analyzer->lowerToInconclusive())
 
  743                             } 
else if (thenBranch.check) {
 
  746                                 if (analyzer->isConditional() && stopUpdates())
 
  748                                 analyzer->assume(condTok, 
false);
 
  751                         if (thenBranch.isInconclusive() || elseBranch.isInconclusive()) {
 
  752                             if (!analyzer->lowerToInconclusive())
 
  754                         } 
else if (thenBranch.isModified() || elseBranch.isModified()) {
 
  755                             if (!hasElse && analyzer->isConditional() && stopUpdates())
 
  757                             if (!analyzer->lowerToPossible())
 
  759                             analyzer->assume(condTok, elseBranch.isModified());
 
  764                     ForwardTraversal tryTraversal = fork();
 
  765                     tryTraversal.updateScope(endBlock, depth - 1);
 
  766                     bool bail = tryTraversal.actions.isModified();
 
  768                         actions = tryTraversal.actions;
 
  769                         terminate = tryTraversal.terminate;
 
  777                         endBlock = endCatch->
linkAt(1);
 
  778                         ForwardTraversal ft = fork();
 
  779                         ft.updateScope(endBlock, depth - 1);
 
  788                     if (updateLoop(end, endBlock, condTok) == Progress::Break)
 
  796                     bool checkThen, checkElse;
 
  797                     std::tie(checkThen, checkElse) = evalCond(condTok);
 
  806                 } 
else if (
Token* callTok = callExpr(tok)) {
 
  808                     if (start != callTok && tok != callTok && updateRecursive(callTok->astOperand1()) == Progress::Break)
 
  812                         updateRange(callTok->next(), callTok->link(), depth - 1) == Progress::Break)
 
  814                     if (updateTok(callTok) == Progress::Break)
 
  816                     tok = callTok->
link();
 
  820                     if (updateTok(tok, &next) == Progress::Break)
 
  826                             return Progress::Continue;
 
  830                 if (tok->
next() == start)
 
  833             return Progress::Continue;
 
  836         void reportError(
Severity severity, 
const std::string& 
id, 
const std::string& msg) {
 
  904     ForwardTraversal ft{a, tokenList, errorLogger, settings};
 
  906         ft.analyzer->updateState(start);
 
  907     ft.updateRange(start, end);
 
  917     ForwardTraversal ft{a, tokenList, errorLogger, settings};
 
  918     (void)ft.updateRecursive(start);
 
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
 
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
 
bool astIsLHS(const Token *tok)
 
bool isEscapeFunction(const Token *ftok, const Library *library)
 
static bool isFunctionCall(const Token *tok)
 
Token * getInitTok(Token *tok)
 
const Token * findNextTokenFromBreak(const Token *breakToken)
For a "break" token, locate the next token to execute.
 
Token * getCondTokFromEnd(Token *endBlock)
 
Token * getCondTok(Token *tok)
 
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
 
const Token * nextAfterAstRightmostLeaf(const Token *tok)
 
Token * getStepTok(Token *tok)
 
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
 
bool isUnevaluated(const Token *tok)
 
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
 
const Token * findAstNode(const Token *ast, const TFunc &pred)
 
This is an interface, which the class responsible of error logging should implement.
 
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
 
File name and line number.
 
Wrapper for error messages, provided by reportErr()
 
This is just a container for general settings so that we don't need to pass individual values to func...
 
static bool terminated()
termination requested?
 
const std::string & getSourceFilePath() const
 
The token list that the TokenList generates is a linked-list of this class.
 
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
 
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
 
bool hasKnownIntValue() const
 
bool isControlFlowKeyword() const
 
std::pair< const Token *, const Token * > findExpressionStartEndTokens() const
 
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
 
const Token * tokAt(int index) const
 
void astOperand2(Token *tok)
 
void scope(const Scope *s)
Associate this token with given scope.
 
void link(Token *linkToToken)
Create link to given token.
 
const Token * linkAt(int index) const
 
void variable(const Variable *v)
Associate this token with given variable.
 
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
 
void astParent(Token *tok)
 
#define REQUIRES(msg,...)
 
Analyzer::Result valueFlowGenericForward(Token *start, const Token *end, const ValuePtr< Analyzer > &a, const TokenList &tokenList, ErrorLogger &errorLogger, const Settings &settings)
 
Severity
enum class for severity.
 
@ information
Checking information.
 
static const Token * assignExpr(const Token *tok)
 
bool isInconclusive() const
 
bool isIdempotent() const
 
bool isIncremental() const
 
Simple container to be thrown when internal error is detected.
 
bool contains(const Range &r, const T &x)
 
static bool isEscapeScope(const Token *tok, const Settings &settings, bool unknown=false)