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