Fix reverse analysis when modifying variable with function (#4800)

This commit is contained in:
Paul Fultz II 2023-02-23 11:04:16 -06:00 committed by GitHub
parent fb88883813
commit 91d2526c41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 16 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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