ValueFlow: Assume constant is nonzero when its negated (#4041)
* ValueFlow: Assume constant is nonzero when its negated * Format * Format
This commit is contained in:
parent
4eed29502c
commit
5d5562266d
|
@ -275,6 +275,77 @@ const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, Val
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isInConstructorList(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return false;
|
||||||
|
if (!astIsRHS(tok))
|
||||||
|
return false;
|
||||||
|
const Token* parent = tok->astParent();
|
||||||
|
if (!Token::Match(parent, "{|("))
|
||||||
|
return false;
|
||||||
|
if (!Token::Match(parent->previous(), "%var% {|("))
|
||||||
|
return false;
|
||||||
|
if (!parent->astOperand1() || !parent->astOperand2())
|
||||||
|
return false;
|
||||||
|
do {
|
||||||
|
parent = parent->astParent();
|
||||||
|
} while (Token::simpleMatch(parent, ","));
|
||||||
|
return Token::simpleMatch(parent, ":") && !Token::simpleMatch(parent->astParent(), "?");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ValueType> getParentValueTypes(const Token* tok,
|
||||||
|
const Settings* settings = nullptr,
|
||||||
|
const Token** parent = nullptr)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return {};
|
||||||
|
if (!tok->astParent())
|
||||||
|
return {};
|
||||||
|
if (isInConstructorList(tok)) {
|
||||||
|
if (parent)
|
||||||
|
*parent = tok->astParent()->astOperand1();
|
||||||
|
if (tok->astParent()->astOperand1()->valueType())
|
||||||
|
return {*tok->astParent()->astOperand1()->valueType()};
|
||||||
|
return {};
|
||||||
|
} else if (Token::Match(tok->astParent(), "(|{|,")) {
|
||||||
|
int argn = -1;
|
||||||
|
const Token* ftok = getTokenArgumentFunction(tok, argn);
|
||||||
|
if (ftok && ftok->function()) {
|
||||||
|
std::vector<ValueType> result;
|
||||||
|
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
|
||||||
|
const Token* nameTok = nullptr;
|
||||||
|
for (const Variable* var : getArgumentVars(ftok, argn)) {
|
||||||
|
if (!var)
|
||||||
|
continue;
|
||||||
|
if (!var->valueType())
|
||||||
|
continue;
|
||||||
|
nameTok = var->nameToken();
|
||||||
|
result.push_back(*var->valueType());
|
||||||
|
}
|
||||||
|
if (result.size() == 1 && nameTok && parent) {
|
||||||
|
*parent = nameTok;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settings && Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
|
||||||
|
astIsContainer(tok->astParent()->tokAt(-2)->astOperand1())) {
|
||||||
|
const Token* contTok = tok->astParent()->tokAt(-2)->astOperand1();
|
||||||
|
const ValueType* vtCont = contTok->valueType();
|
||||||
|
if (!vtCont->containerTypeToken)
|
||||||
|
return {};
|
||||||
|
ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
|
||||||
|
return {std::move(vtParent)};
|
||||||
|
}
|
||||||
|
if (Token::Match(tok->astParent(), "return|(|{|%assign%") && parent) {
|
||||||
|
*parent = tok->astParent();
|
||||||
|
}
|
||||||
|
if (tok->astParent()->valueType())
|
||||||
|
return {*tok->astParent()->valueType()};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
static bool isEscapeScope(const Token* tok, TokenList * tokenlist, bool unknown = false)
|
static bool isEscapeScope(const Token* tok, TokenList * tokenlist, bool unknown = false)
|
||||||
{
|
{
|
||||||
if (!Token::simpleMatch(tok, "{"))
|
if (!Token::simpleMatch(tok, "{"))
|
||||||
|
@ -1547,6 +1618,17 @@ static std::vector<MathLib::bigint> minUnsignedValue(const Token* tok, int depth
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isConvertedToIntegral(const Token* tok, const Settings* settings)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return false;
|
||||||
|
std::vector<ValueType> parentTypes = getParentValueTypes(tok, settings);
|
||||||
|
if (parentTypes.empty())
|
||||||
|
return false;
|
||||||
|
const ValueType& vt = parentTypes.front();
|
||||||
|
return vt.type != ValueType::UNKNOWN_INT && vt.isIntegral();
|
||||||
|
}
|
||||||
|
|
||||||
static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* settings)
|
static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* settings)
|
||||||
{
|
{
|
||||||
for (Token* tok = tokenList->front(); tok; tok = tok->next()) {
|
for (Token* tok = tokenList->front(); tok; tok = tok->next()) {
|
||||||
|
@ -1602,6 +1684,11 @@ static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* sett
|
||||||
ValueFlow::Value value{0};
|
ValueFlow::Value value{0};
|
||||||
value.setImpossible();
|
value.setImpossible();
|
||||||
setTokenValue(tok, value, settings);
|
setTokenValue(tok, value, settings);
|
||||||
|
} else if (tok->isIncompleteVar() && tok->astParent() && tok->astParent()->isUnaryOp("-") &&
|
||||||
|
isConvertedToIntegral(tok->astParent(), settings)) {
|
||||||
|
ValueFlow::Value value{0};
|
||||||
|
value.setImpossible();
|
||||||
|
setTokenValue(tok, value, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3359,77 +3446,6 @@ static bool isDifferentType(const Token* src, const Token* dst)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isInConstructorList(const Token* tok)
|
|
||||||
{
|
|
||||||
if (!tok)
|
|
||||||
return false;
|
|
||||||
if (!astIsRHS(tok))
|
|
||||||
return false;
|
|
||||||
const Token* parent = tok->astParent();
|
|
||||||
if (!Token::Match(parent, "{|("))
|
|
||||||
return false;
|
|
||||||
if (!Token::Match(parent->previous(), "%var% {|("))
|
|
||||||
return false;
|
|
||||||
if (!parent->astOperand1() || !parent->astOperand2())
|
|
||||||
return false;
|
|
||||||
do {
|
|
||||||
parent = parent->astParent();
|
|
||||||
} while (Token::simpleMatch(parent, ","));
|
|
||||||
return Token::simpleMatch(parent, ":") && !Token::simpleMatch(parent->astParent(), "?");
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<ValueType> getParentValueTypes(const Token* tok,
|
|
||||||
const Settings* settings = nullptr,
|
|
||||||
const Token** parent = nullptr)
|
|
||||||
{
|
|
||||||
if (!tok)
|
|
||||||
return {};
|
|
||||||
if (!tok->astParent())
|
|
||||||
return {};
|
|
||||||
if (isInConstructorList(tok)) {
|
|
||||||
if (parent)
|
|
||||||
*parent = tok->astParent()->astOperand1();
|
|
||||||
if (tok->astParent()->astOperand1()->valueType())
|
|
||||||
return {*tok->astParent()->astOperand1()->valueType()};
|
|
||||||
return {};
|
|
||||||
} else if (Token::Match(tok->astParent(), "(|{|,")) {
|
|
||||||
int argn = -1;
|
|
||||||
const Token* ftok = getTokenArgumentFunction(tok, argn);
|
|
||||||
if (ftok && ftok->function()) {
|
|
||||||
std::vector<ValueType> result;
|
|
||||||
std::vector<const Variable*> argsVars = getArgumentVars(ftok, argn);
|
|
||||||
const Token* nameTok = nullptr;
|
|
||||||
for (const Variable* var : getArgumentVars(ftok, argn)) {
|
|
||||||
if (!var)
|
|
||||||
continue;
|
|
||||||
if (!var->valueType())
|
|
||||||
continue;
|
|
||||||
nameTok = var->nameToken();
|
|
||||||
result.push_back(*var->valueType());
|
|
||||||
}
|
|
||||||
if (result.size() == 1 && nameTok && parent) {
|
|
||||||
*parent = nameTok;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (settings && Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
|
|
||||||
astIsContainer(tok->astParent()->tokAt(-2)->astOperand1())) {
|
|
||||||
const Token* contTok = tok->astParent()->tokAt(-2)->astOperand1();
|
|
||||||
const ValueType* vtCont = contTok->valueType();
|
|
||||||
if (!vtCont->containerTypeToken)
|
|
||||||
return {};
|
|
||||||
ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
|
|
||||||
return {std::move(vtParent)};
|
|
||||||
}
|
|
||||||
if (Token::Match(tok->astParent(), "return|(|{|%assign%") && parent) {
|
|
||||||
*parent = tok->astParent();
|
|
||||||
}
|
|
||||||
if (tok->astParent()->valueType())
|
|
||||||
return {*tok->astParent()->valueType()};
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
|
bool isLifetimeBorrowed(const Token *tok, const Settings *settings)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
|
|
@ -5065,6 +5065,17 @@ private:
|
||||||
"}\n";
|
"}\n";
|
||||||
values = tokenValues(code, "x ; }", ValueFlow::Value::ValueType::UNINIT);
|
values = tokenValues(code, "x ; }", ValueFlow::Value::ValueType::UNINIT);
|
||||||
ASSERT_EQUALS(0, values.size());
|
ASSERT_EQUALS(0, values.size());
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" int i;\n"
|
||||||
|
" if (x) {\n"
|
||||||
|
" int y = -ENOMEM;\n" // assume constant ENOMEM is nonzero since it's negated
|
||||||
|
" if (y != 0) return;\n"
|
||||||
|
" i++;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
values = tokenValues(code, "i ++", ValueFlow::Value::ValueType::UNINIT);
|
||||||
|
ASSERT_EQUALS(0, values.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowConditionExpressions() {
|
void valueFlowConditionExpressions() {
|
||||||
|
|
Loading…
Reference in New Issue