From 88491267d65042fd61a536cd695d3ea3feddd575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 16 Jul 2015 17:33:16 +0200 Subject: [PATCH] ValueFlow: Added Value::valueKind that says if value is known or possible --- lib/valueflow.cpp | 22 +++++++++++++++++----- lib/valueflow.h | 16 ++++++++++++++-- test/testvalueflow.cpp | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index cfbf3a038..377e82bd5 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -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::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); diff --git a/lib/valueflow.h b/lib/valueflow.h index 53b0e7abb..0b4d43ebe 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -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); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 64ad18202..e59b27673 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -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)