ValueFlow: handle ~ in setTokenValue
This commit is contained in:
parent
40bf269ea0
commit
2885a75ea6
|
@ -287,7 +287,7 @@ static bool addValue(Token *tok, const ValueFlow::Value &value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** set ValueFlow value and perform calculations if possible */
|
/** set ValueFlow value and perform calculations if possible */
|
||||||
static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Settings *settings=nullptr)
|
||||||
{
|
{
|
||||||
if (!addValue(tok,value))
|
if (!addValue(tok,value))
|
||||||
return;
|
return;
|
||||||
|
@ -298,11 +298,11 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
|
|
||||||
// Cast..
|
// Cast..
|
||||||
if (parent->str() == "(" && tok == parent->link()->next()) {
|
if (parent->str() == "(" && tok == parent->link()->next()) {
|
||||||
setTokenValue(parent,value);
|
setTokenValue(parent,value,settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (parent->str() == ":") {
|
else if (parent->str() == ":") {
|
||||||
setTokenValue(parent,value);
|
setTokenValue(parent,value,settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2() && parent->astOperand1()) {
|
else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2() && parent->astOperand1()) {
|
||||||
|
@ -311,12 +311,12 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
const ValueFlow::Value &condvalue = parent->astOperand1()->values.front();
|
const ValueFlow::Value &condvalue = parent->astOperand1()->values.front();
|
||||||
const bool cond(condvalue.tokvalue || condvalue.intvalue != 0);
|
const bool cond(condvalue.tokvalue || condvalue.intvalue != 0);
|
||||||
if (cond && !tok->astOperand1()) { // true condition, no second operator
|
if (cond && !tok->astOperand1()) { // true condition, no second operator
|
||||||
setTokenValue(parent, condvalue);
|
setTokenValue(parent, condvalue, settings);
|
||||||
} else {
|
} else {
|
||||||
const Token *op = cond ? tok->astOperand1() : tok->astOperand2();
|
const Token *op = cond ? tok->astOperand1() : tok->astOperand2();
|
||||||
const std::list<ValueFlow::Value> &values = op->values;
|
const std::list<ValueFlow::Value> &values = op->values;
|
||||||
if (std::find(values.begin(), values.end(), value) != values.end())
|
if (std::find(values.begin(), values.end(), value) != values.end())
|
||||||
setTokenValue(parent, value);
|
setTokenValue(parent, value, settings);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// is condition only depending on 1 variable?
|
// is condition only depending on 1 variable?
|
||||||
|
@ -345,7 +345,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
if (varId)
|
if (varId)
|
||||||
v.varId = varId;
|
v.varId = varId;
|
||||||
|
|
||||||
setTokenValue(parent, v);
|
setTokenValue(parent, v, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
|
|
||||||
// known result when a operand is 0.
|
// known result when a operand is 0.
|
||||||
if (Token::Match(parent, "[&*]") && value.isKnown() && value.tokvalue==nullptr && value.intvalue==0) {
|
if (Token::Match(parent, "[&*]") && value.isKnown() && value.tokvalue==nullptr && value.intvalue==0) {
|
||||||
setTokenValue(parent, value);
|
setTokenValue(parent, value, settings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,27 +383,27 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
switch (parent->str()[0]) {
|
switch (parent->str()[0]) {
|
||||||
case '+':
|
case '+':
|
||||||
result.intvalue = value1->intvalue + value2->intvalue;
|
result.intvalue = value1->intvalue + value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
result.intvalue = value1->intvalue - value2->intvalue;
|
result.intvalue = value1->intvalue - value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
result.intvalue = value1->intvalue * value2->intvalue;
|
result.intvalue = value1->intvalue * value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
if (value2->intvalue == 0)
|
if (value2->intvalue == 0)
|
||||||
break;
|
break;
|
||||||
result.intvalue = value1->intvalue / value2->intvalue;
|
result.intvalue = value1->intvalue / value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
if (value2->intvalue == 0)
|
if (value2->intvalue == 0)
|
||||||
break;
|
break;
|
||||||
result.intvalue = value1->intvalue % value2->intvalue;
|
result.intvalue = value1->intvalue % value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (parent->str() == "==") {
|
if (parent->str() == "==") {
|
||||||
|
@ -411,7 +411,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
result.intvalue = 0;
|
result.intvalue = 0;
|
||||||
else
|
else
|
||||||
result.intvalue = value1->intvalue == value2->intvalue;
|
result.intvalue = value1->intvalue == value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
|
@ -420,7 +420,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
result.intvalue = 1;
|
result.intvalue = 1;
|
||||||
else
|
else
|
||||||
result.intvalue = value1->intvalue != value2->intvalue;
|
result.intvalue = value1->intvalue != value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
|
@ -430,9 +430,11 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
result.intvalue = value1->intvalue > value2->intvalue;
|
result.intvalue = value1->intvalue > value2->intvalue;
|
||||||
else if (parent->str() == ">=")
|
else if (parent->str() == ">=")
|
||||||
result.intvalue = value1->intvalue >= value2->intvalue;
|
result.intvalue = value1->intvalue >= value2->intvalue;
|
||||||
|
else if (parent->str() == ">>")
|
||||||
|
result.intvalue = value1->intvalue >> value2->intvalue;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
if (value1->tokvalue || value2->tokvalue)
|
if (value1->tokvalue || value2->tokvalue)
|
||||||
|
@ -441,27 +443,29 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
result.intvalue = value1->intvalue < value2->intvalue;
|
result.intvalue = value1->intvalue < value2->intvalue;
|
||||||
else if (parent->str() == "<=")
|
else if (parent->str() == "<=")
|
||||||
result.intvalue = value1->intvalue <= value2->intvalue;
|
result.intvalue = value1->intvalue <= value2->intvalue;
|
||||||
|
else if (parent->str() == "<<")
|
||||||
|
result.intvalue = value1->intvalue << value2->intvalue;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '&':
|
case '&':
|
||||||
if (parent->str() == "&")
|
if (parent->str() == "&")
|
||||||
result.intvalue = value1->intvalue & value2->intvalue;
|
result.intvalue = value1->intvalue & value2->intvalue;
|
||||||
else
|
else
|
||||||
result.intvalue = value1->intvalue && value2->intvalue;
|
result.intvalue = value1->intvalue && value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '|':
|
case '|':
|
||||||
if (parent->str() == "|")
|
if (parent->str() == "|")
|
||||||
result.intvalue = value1->intvalue | value2->intvalue;
|
result.intvalue = value1->intvalue | value2->intvalue;
|
||||||
else
|
else
|
||||||
result.intvalue = value1->intvalue || value2->intvalue;
|
result.intvalue = value1->intvalue || value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
result.intvalue = value1->intvalue ^ value2->intvalue;
|
result.intvalue = value1->intvalue ^ value2->intvalue;
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// unhandled operator, do nothing
|
// unhandled operator, do nothing
|
||||||
|
@ -480,7 +484,30 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
continue;
|
continue;
|
||||||
ValueFlow::Value v(*it);
|
ValueFlow::Value v(*it);
|
||||||
v.intvalue = !v.intvalue;
|
v.intvalue = !v.intvalue;
|
||||||
setTokenValue(parent, v);
|
setTokenValue(parent, v, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~
|
||||||
|
else if (parent->str() == "~") {
|
||||||
|
std::list<ValueFlow::Value>::const_iterator it;
|
||||||
|
for (it = tok->values.begin(); it != tok->values.end(); ++it) {
|
||||||
|
if (it->tokvalue)
|
||||||
|
continue;
|
||||||
|
ValueFlow::Value v(*it);
|
||||||
|
v.intvalue = ~v.intvalue;
|
||||||
|
unsigned int bits = 0;
|
||||||
|
if (tok->valueType() &&
|
||||||
|
tok->valueType()->sign == ValueType::Sign::UNSIGNED &&
|
||||||
|
tok->valueType()->pointer == 0) {
|
||||||
|
if (tok->valueType()->type == ValueType::Type::INT)
|
||||||
|
bits = settings->int_bit;
|
||||||
|
else if (tok->valueType()->type == ValueType::Type::LONG)
|
||||||
|
bits = settings->long_bit;
|
||||||
|
}
|
||||||
|
if (bits > 0 && bits < 64)
|
||||||
|
v.intvalue &= (1ULL<<bits) - 1ULL;
|
||||||
|
setTokenValue(parent, v, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +519,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
continue;
|
continue;
|
||||||
ValueFlow::Value v(*it);
|
ValueFlow::Value v(*it);
|
||||||
v.intvalue = -v.intvalue;
|
v.intvalue = -v.intvalue;
|
||||||
setTokenValue(parent, v);
|
setTokenValue(parent, v, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +549,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result);
|
||||||
} else if (index >= 0 && index < s.size()) {
|
} else if (index >= 0 && index < s.size()) {
|
||||||
result.intvalue = s[index];
|
result.intvalue = s[index];
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
}
|
}
|
||||||
} else if (value1->tokvalue->str() == "{") {
|
} else if (value1->tokvalue->str() == "{") {
|
||||||
MathLib::bigint index = value2->intvalue;
|
MathLib::bigint index = value2->intvalue;
|
||||||
|
@ -536,7 +563,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
||||||
}
|
}
|
||||||
if (Token::Match(element, "%num% [,}]")) {
|
if (Token::Match(element, "%num% [,}]")) {
|
||||||
result.intvalue = MathLib::toLongNumber(element->str());
|
result.intvalue = MathLib::toLongNumber(element->str());
|
||||||
setTokenValue(parent, result);
|
setTokenValue(parent, result, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,15 +579,15 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
|
||||||
if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) {
|
if ((tok->isNumber() && MathLib::isInt(tok->str())) || (tok->tokType() == Token::eChar)) {
|
||||||
ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
|
ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
} else if (tok->enumerator() && tok->enumerator()->value_known) {
|
} else if (tok->enumerator() && tok->enumerator()->value_known) {
|
||||||
ValueFlow::Value value(tok->enumerator()->value);
|
ValueFlow::Value value(tok->enumerator()->value);
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
} else if (tok->str() == "NULL" || (cpp && tok->str() == "nullptr")) {
|
} else if (tok->str() == "NULL" || (cpp && tok->str() == "nullptr")) {
|
||||||
ValueFlow::Value value(0);
|
ValueFlow::Value value(0);
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
} else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) {
|
} else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) {
|
||||||
const Token *tok2 = tok->tokAt(2);
|
const Token *tok2 = tok->tokAt(2);
|
||||||
if (tok2->enumerator() && tok2->enumerator()->scope) {
|
if (tok2->enumerator() && tok2->enumerator()->scope) {
|
||||||
|
@ -575,8 +602,8 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
|
||||||
}
|
}
|
||||||
ValueFlow::Value value(size);
|
ValueFlow::Value value(size);
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
setTokenValue(const_cast<Token *>(tok->next()), value);
|
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
|
||||||
} else if (tok2->type() && tok2->type()->isEnumType()) {
|
} else if (tok2->type() && tok2->type()->isEnumType()) {
|
||||||
long long size = settings->sizeof_int;
|
long long size = settings->sizeof_int;
|
||||||
if (tok2->type()->classScope) {
|
if (tok2->type()->classScope) {
|
||||||
|
@ -591,8 +618,8 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti
|
||||||
}
|
}
|
||||||
ValueFlow::Value value(size);
|
ValueFlow::Value value(size);
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
setTokenValue(const_cast<Token *>(tok), value);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
setTokenValue(const_cast<Token *>(tok->next()), value);
|
setTokenValue(const_cast<Token *>(tok->next()), value, settings);
|
||||||
}
|
}
|
||||||
// skip over enum
|
// skip over enum
|
||||||
tok = tok->linkAt(1);
|
tok = tok->linkAt(1);
|
||||||
|
|
|
@ -339,6 +339,13 @@ private:
|
||||||
ASSERT_EQUALS(1U, values.size());
|
ASSERT_EQUALS(1U, values.size());
|
||||||
ASSERT_EQUALS(123, values.empty() ? 0 : values.front().intvalue);
|
ASSERT_EQUALS(123, values.empty() ? 0 : values.front().intvalue);
|
||||||
|
|
||||||
|
// ~
|
||||||
|
code = "x = ~0U;";
|
||||||
|
settings.platform(cppcheck::Platform::Native); // ensure platform is native
|
||||||
|
values = tokenValues(code,"~");
|
||||||
|
ASSERT_EQUALS(1U, values.size());
|
||||||
|
ASSERT_EQUALS(~0U, values.back().intvalue);
|
||||||
|
|
||||||
// !
|
// !
|
||||||
code = "void f(int x) {\n"
|
code = "void f(int x) {\n"
|
||||||
" a = !x;\n"
|
" a = !x;\n"
|
||||||
|
|
Loading…
Reference in New Issue