ValueFlow: Added Value::valueKind that says if value is known or possible

This commit is contained in:
Daniel Marjamäki 2015-07-16 17:33:16 +02:00
parent daf859c5bd
commit 88491267d6
3 changed files with 67 additions and 7 deletions

View File

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

View File

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

View File

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