ValueFlow: Added Value::valueKind that says if value is known or possible
This commit is contained in:
parent
daf859c5bd
commit
88491267d6
|
@ -374,6 +374,8 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||
result.inconclusive = value1->inconclusive | value2->inconclusive;
|
||||
result.varId = (value1->varId != 0U) ? value1->varId : value2->varId;
|
||||
result.varvalue = (result.varId == value1->varId) ? value1->intvalue : value2->intvalue;
|
||||
if (value1->valueKind == value2->valueKind)
|
||||
result.valueKind = value1->valueKind;
|
||||
switch (parent->str()[0]) {
|
||||
case '+':
|
||||
result.intvalue = value1->intvalue + value2->intvalue;
|
||||
|
@ -452,14 +454,20 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||
static void valueFlowNumber(TokenList *tokenlist)
|
||||
{
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
if (tok->isNumber() && MathLib::isInt(tok->str()))
|
||||
setTokenValue(tok, ValueFlow::Value(MathLib::toLongNumber(tok->str())));
|
||||
if (tok->isNumber() && MathLib::isInt(tok->str())) {
|
||||
ValueFlow::Value value(MathLib::toLongNumber(tok->str()));
|
||||
value.valueKind = ValueFlow::Value::Known;
|
||||
setTokenValue(tok, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenlist->isCPP()) {
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
if (tok->isName() && !tok->varId() && Token::Match(tok, "false|true"))
|
||||
setTokenValue(tok, ValueFlow::Value(tok->str() == "true"));
|
||||
if (tok->isName() && !tok->varId() && Token::Match(tok, "false|true")) {
|
||||
ValueFlow::Value value(tok->str() == "true");
|
||||
value.valueKind = ValueFlow::Value::Known;
|
||||
setTokenValue(tok, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -470,6 +478,7 @@ static void valueFlowString(TokenList *tokenlist)
|
|||
if (tok->type() == Token::eString) {
|
||||
ValueFlow::Value strvalue;
|
||||
strvalue.tokvalue = tok;
|
||||
strvalue.valueKind = ValueFlow::Value::Known;
|
||||
setTokenValue(tok, strvalue);
|
||||
}
|
||||
}
|
||||
|
@ -1054,8 +1063,11 @@ static bool valueFlowForward(Token * const startToken,
|
|||
|
||||
// Set "conditional" flag for all values
|
||||
std::list<ValueFlow::Value>::iterator it;
|
||||
for (it = values.begin(); it != values.end(); ++it)
|
||||
for (it = values.begin(); it != values.end(); ++it) {
|
||||
it->conditional = true;
|
||||
if (it->valueKind == ValueFlow::Value::Known)
|
||||
it->valueKind = ValueFlow::Value::Possible;
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok2,"} else {"))
|
||||
tok2 = tok2->linkAt(2);
|
||||
|
|
|
@ -30,8 +30,8 @@ class Settings;
|
|||
namespace ValueFlow {
|
||||
class Value {
|
||||
public:
|
||||
explicit Value(long long val = 0) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false) {}
|
||||
Value(const Token *c, long long val) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false) {}
|
||||
explicit Value(long long val = 0) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
|
||||
Value(const Token *c, long long val) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
|
||||
|
||||
/** int value */
|
||||
long long intvalue;
|
||||
|
@ -56,6 +56,18 @@ namespace ValueFlow {
|
|||
|
||||
/** Is this value passed as default parameter to the function? */
|
||||
bool defaultArg;
|
||||
|
||||
/** How known is this value */
|
||||
enum ValueKind {
|
||||
/** This value is possible, other unlisted values may also be possible */
|
||||
Possible,
|
||||
/** Only listed values are possible */
|
||||
Known,
|
||||
/** Max value. Greater values are impossible. */
|
||||
Max,
|
||||
/** Min value. Smaller values are impossible. */
|
||||
Min
|
||||
} valueKind;
|
||||
};
|
||||
|
||||
void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings);
|
||||
|
|
|
@ -65,6 +65,8 @@ private:
|
|||
TEST_CASE(valueFlowFunctionReturn);
|
||||
|
||||
TEST_CASE(valueFlowFunctionDefaultParameter);
|
||||
|
||||
TEST_CASE(knownValue);
|
||||
}
|
||||
|
||||
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
||||
|
@ -1512,6 +1514,40 @@ private:
|
|||
"};";
|
||||
testValueOfX(code, 2U, 2); // Don't crash (#6494)
|
||||
}
|
||||
|
||||
void knownValue() {
|
||||
const char *code;
|
||||
ValueFlow::Value value;
|
||||
|
||||
ASSERT_EQUALS(ValueFlow::Value::ValueKind::Known, valueOfTok("x = 1;", "1").valueKind);
|
||||
|
||||
// after assignment
|
||||
code = "void f() {\n"
|
||||
" int x = 1;\n"
|
||||
" return x + 2;\n" // <- known value
|
||||
"}";
|
||||
value = valueOfTok(code, "+");
|
||||
ASSERT_EQUALS(3, value.intvalue);
|
||||
ASSERT_EQUALS(ValueFlow::Value::ValueKind::Known, value.valueKind);
|
||||
|
||||
code = "void f() {\n"
|
||||
" int x;\n"
|
||||
" if (ab) { x = 7; }\n"
|
||||
" return x + 2;\n" // <- possible value
|
||||
"}";
|
||||
value = valueOfTok(code, "+");
|
||||
ASSERT_EQUALS(9, value.intvalue);
|
||||
ASSERT_EQUALS(ValueFlow::Value::ValueKind::Possible, value.valueKind);
|
||||
|
||||
// after condition
|
||||
code = "int f(int x) {\n"
|
||||
" if (x == 4) {}\n"
|
||||
" return x + 1;\n" // <- possible value
|
||||
"}";
|
||||
value = valueOfTok(code, "+");
|
||||
ASSERT_EQUALS(5, value.intvalue);
|
||||
ASSERT_EQUALS(ValueFlow::Value::ValueKind::Possible, value.valueKind);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestValueFlow)
|
||||
|
|
Loading…
Reference in New Issue