Fix reverse analysis when modifying variable with function (#4800)
This commit is contained in:
parent
fb88883813
commit
91d2526c41
|
@ -56,12 +56,12 @@ struct ReverseTraversal {
|
|||
|
||||
bool update(Token* tok) {
|
||||
Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Reverse);
|
||||
if (!action.isNone())
|
||||
analyzer->update(tok, action, Analyzer::Direction::Reverse);
|
||||
if (action.isInconclusive() && !analyzer->lowerToInconclusive())
|
||||
return false;
|
||||
if (action.isInvalid())
|
||||
return false;
|
||||
if (!action.isNone())
|
||||
analyzer->update(tok, action, Analyzer::Direction::Reverse);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -7751,11 +7751,10 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
|||
return tok->exprId() == expr->exprId() || (astIsIterator(tok) && isAliasOf(tok, expr->exprId()));
|
||||
}
|
||||
|
||||
Action isWritable(const Token* tok, Direction d) const override {
|
||||
Action isWritable(const Token* tok, Direction /*d*/) const override
|
||||
{
|
||||
if (astIsIterator(tok))
|
||||
return Action::None;
|
||||
if (d == Direction::Reverse)
|
||||
return Action::None;
|
||||
if (!getValue(tok))
|
||||
return Action::None;
|
||||
if (!tok->valueType())
|
||||
|
@ -7788,8 +7787,6 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
|||
}
|
||||
|
||||
void writeValue(ValueFlow::Value* val, const Token* tok, Direction d) const override {
|
||||
if (d == Direction::Reverse)
|
||||
return;
|
||||
if (!val)
|
||||
return;
|
||||
if (!tok->astParent())
|
||||
|
@ -7800,26 +7797,31 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
|||
return;
|
||||
const Token* parent = tok->astParent();
|
||||
const Library::Container* container = getLibraryContainer(tok);
|
||||
int n = 0;
|
||||
|
||||
if (container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) {
|
||||
const Token* rhs = parent->astOperand2();
|
||||
const Library::Container* rhsContainer = getLibraryContainer(rhs);
|
||||
if (rhs->tokType() == Token::eString)
|
||||
val->intvalue += Token::getStrLength(rhs);
|
||||
n = Token::getStrLength(rhs);
|
||||
else if (rhsContainer && rhsContainer->stdStringLike) {
|
||||
for (const ValueFlow::Value &rhsval : rhs->values()) {
|
||||
if (rhsval.isKnown() && rhsval.isContainerSizeValue()) {
|
||||
val->intvalue += rhsval.intvalue;
|
||||
}
|
||||
}
|
||||
auto it = std::find_if(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value& rhsval) {
|
||||
return rhsval.isKnown() && rhsval.isContainerSizeValue();
|
||||
});
|
||||
if (it != rhs->values().end())
|
||||
n = it->intvalue;
|
||||
}
|
||||
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
|
||||
const Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
|
||||
if (action == Library::Container::Action::PUSH)
|
||||
val->intvalue++;
|
||||
n = 1;
|
||||
if (action == Library::Container::Action::POP)
|
||||
val->intvalue--;
|
||||
n = -1;
|
||||
}
|
||||
if (d == Direction::Reverse)
|
||||
val->intvalue -= n;
|
||||
else
|
||||
val->intvalue += n;
|
||||
}
|
||||
|
||||
int getIndirect(const Token* tok) const override
|
||||
|
|
|
@ -1529,6 +1529,7 @@ private:
|
|||
" if (x == 4);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 2));
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 2));
|
||||
|
||||
code = "void f(int x) {\n"
|
||||
" a = x;\n"
|
||||
|
@ -1536,6 +1537,7 @@ private:
|
|||
" if (x == 4);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 6));
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 6));
|
||||
|
||||
code = "void f(int x) {\n"
|
||||
" a = x;\n"
|
||||
|
@ -1543,6 +1545,7 @@ private:
|
|||
" if (x == 42);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 21));
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 21));
|
||||
|
||||
code = "void f(int x) {\n"
|
||||
" a = x;\n"
|
||||
|
@ -1550,6 +1553,7 @@ private:
|
|||
" if (x == 42);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 210));
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 210));
|
||||
|
||||
// bailout: assignment
|
||||
bailout("void f(int x) {\n"
|
||||
|
@ -1612,6 +1616,13 @@ private:
|
|||
" if (x) {}\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
||||
|
||||
code = "void g(int&);"
|
||||
"void f(int x) {\n"
|
||||
" g(x);\n"
|
||||
" if (x == 5);\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(false, testValueOfX(code, 2U, 5));
|
||||
}
|
||||
|
||||
void valueFlowBeforeConditionLoop() { // while, for, do-while
|
||||
|
@ -5666,7 +5677,7 @@ private:
|
|||
" ints.pop_back();\n"
|
||||
" if (ints.empty()) {}\n"
|
||||
"}";
|
||||
ASSERT(tokenValues(code, "ints . front").empty());
|
||||
ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 1));
|
||||
|
||||
code = "void f(std::vector<int> v) {\n"
|
||||
" v[10] = 0;\n" // <- container size can be 10
|
||||
|
|
Loading…
Reference in New Issue