diff --git a/lib/analyzer.h b/lib/analyzer.h index 502407a53..7adde79ab 100644 --- a/lib/analyzer.h +++ b/lib/analyzer.h @@ -42,6 +42,7 @@ struct Analyzer { Inconclusive = (1 << 3), Match = (1 << 4), Idempotent = (1 << 5), + Incremental = (1 << 6), }; void set(unsigned int f, bool state = true) { @@ -80,6 +81,10 @@ struct Analyzer { return get(Idempotent); } + bool isIncremental() const { + return get(Incremental); + } + bool matches() const { return get(Match); } diff --git a/lib/forwardanalyzer.cpp b/lib/forwardanalyzer.cpp index 75c1692a2..507c3a9f7 100644 --- a/lib/forwardanalyzer.cpp +++ b/lib/forwardanalyzer.cpp @@ -320,12 +320,14 @@ struct ForwardTraversal { Token* writeTok = findRange(endBlock->link(), endBlock, std::mem_fn(&Analyzer::Action::isModified)); const Token* nextStatement = Token::findmatch(writeTok, ";|}", endBlock); if (!Token::Match(nextStatement, ";|} break ;")) { - continueUpdateRangeAfterLoop(ftv, endBlock, endToken); + if (!allAnalysis.isIncremental()) + continueUpdateRangeAfterLoop(ftv, endBlock, endToken); return Break(Terminate::Bail); } } else { if (stepTok && updateRecursive(stepTok) == Progress::Break) { - continueUpdateRangeAfterLoop(ftv, endBlock, endToken); + if (!allAnalysis.isIncremental()) + continueUpdateRangeAfterLoop(ftv, endBlock, endToken); return Break(Terminate::Bail); } } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 14f465b7b..14e515168 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1893,13 +1893,14 @@ struct ValueFlowAnalyzer : Analyzer { } else { if (rhsValue && !value->isImpossible() && value->equalValue(*rhsValue)) a = Action::Idempotent; + a |= Action::Incremental; } return a; } // increment/decrement if (Token::Match(tok->previous(), "++|-- %name%") || Token::Match(tok, "%name% ++|--")) { - return Action::Read | Action::Write; + return Action::Read | Action::Write | Action::Incremental; } return Action::None; } @@ -5706,17 +5707,17 @@ struct ContainerVariableAnalyzer : VariableAnalyzer { if (tok->valueType()->container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) { const Token* rhs = parent->astOperand2(); if (rhs->tokType() == Token::eString) - return Action::Read | Action::Write; + return Action::Read | Action::Write | Action::Incremental; if (rhs->valueType() && rhs->valueType()->container && rhs->valueType()->container->stdStringLike) { if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) { return rhsval.isKnown() && rhsval.isContainerSizeValue(); })) - return Action::Read | Action::Write; + return Action::Read | Action::Write | Action::Incremental; } } else if (Token::Match(tok, "%name% . %name% (")) { Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) - return Action::Read | Action::Write; + return Action::Read | Action::Write | Action::Incremental; } return Action::None; } diff --git a/test/teststl.cpp b/test/teststl.cpp index a440fa44e..84924d9e8 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -380,6 +380,22 @@ private: " return ArrS[0];\n" "}\n", true); ASSERT_EQUALS("", errout.str()); + + checkNormal("extern void Bar(const double, const double);\n" + "void f(std::vector &r, const double ) {\n" + " std::vector result;\n" + " double d = 0.0;\n" + " const double inc = 0.1;\n" + " for(unsigned int i = 0; i < 10; ++i) {\n" + " result.push_back(d);\n" + " d = (i + 1) * inc;\n" + " }\n" + " Bar(1.0, d);\n" + " Bar(10U, result.size());\n" + " Bar(0.0, result[0]);\n" + " Bar(0.34, result[1]);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void outOfBoundsIndexExpression() {