From 2885a75ea6f7d111518e5c19b8e4be75a63a3b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 5 Nov 2016 09:29:22 +0100 Subject: [PATCH] ValueFlow: handle ~ in setTokenValue --- lib/valueflow.cpp | 87 +++++++++++++++++++++++++++--------------- test/testvalueflow.cpp | 7 ++++ 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6d6bd650a..9924efc2a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -287,7 +287,7 @@ static bool addValue(Token *tok, const ValueFlow::Value &value) } /** 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)) return; @@ -298,11 +298,11 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) // Cast.. if (parent->str() == "(" && tok == parent->link()->next()) { - setTokenValue(parent,value); + setTokenValue(parent,value,settings); } else if (parent->str() == ":") { - setTokenValue(parent,value); + setTokenValue(parent,value,settings); } 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 bool cond(condvalue.tokvalue || condvalue.intvalue != 0); if (cond && !tok->astOperand1()) { // true condition, no second operator - setTokenValue(parent, condvalue); + setTokenValue(parent, condvalue, settings); } else { const Token *op = cond ? tok->astOperand1() : tok->astOperand2(); const std::list &values = op->values; if (std::find(values.begin(), values.end(), value) != values.end()) - setTokenValue(parent, value); + setTokenValue(parent, value, settings); } } else { // is condition only depending on 1 variable? @@ -345,7 +345,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) if (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. if (Token::Match(parent, "[&*]") && value.isKnown() && value.tokvalue==nullptr && value.intvalue==0) { - setTokenValue(parent, value); + setTokenValue(parent, value, settings); return; } @@ -383,27 +383,27 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) switch (parent->str()[0]) { case '+': result.intvalue = value1->intvalue + value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '-': result.intvalue = value1->intvalue - value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '*': result.intvalue = value1->intvalue * value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '/': if (value2->intvalue == 0) break; result.intvalue = value1->intvalue / value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '%': if (value2->intvalue == 0) break; result.intvalue = value1->intvalue % value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '=': if (parent->str() == "==") { @@ -411,7 +411,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) result.intvalue = 0; else result.intvalue = value1->intvalue == value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); } break; case '!': @@ -420,7 +420,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) result.intvalue = 1; else result.intvalue = value1->intvalue != value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); } break; case '>': @@ -430,9 +430,11 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) result.intvalue = value1->intvalue > value2->intvalue; else if (parent->str() == ">=") result.intvalue = value1->intvalue >= value2->intvalue; + else if (parent->str() == ">>") + result.intvalue = value1->intvalue >> value2->intvalue; else break; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '<': if (value1->tokvalue || value2->tokvalue) @@ -441,27 +443,29 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) result.intvalue = value1->intvalue < value2->intvalue; else if (parent->str() == "<=") result.intvalue = value1->intvalue <= value2->intvalue; + else if (parent->str() == "<<") + result.intvalue = value1->intvalue << value2->intvalue; else break; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '&': if (parent->str() == "&") result.intvalue = value1->intvalue & value2->intvalue; else result.intvalue = value1->intvalue && value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '|': if (parent->str() == "|") result.intvalue = value1->intvalue | value2->intvalue; else result.intvalue = value1->intvalue || value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; case '^': result.intvalue = value1->intvalue ^ value2->intvalue; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); break; default: // unhandled operator, do nothing @@ -480,7 +484,30 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) continue; ValueFlow::Value v(*it); v.intvalue = !v.intvalue; - setTokenValue(parent, v); + setTokenValue(parent, v, settings); + } + } + + // ~ + else if (parent->str() == "~") { + std::list::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<= 0 && index < s.size()) { result.intvalue = s[index]; - setTokenValue(parent, result); + setTokenValue(parent, result, settings); } } else if (value1->tokvalue->str() == "{") { MathLib::bigint index = value2->intvalue; @@ -536,7 +563,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) } if (Token::Match(element, "%num% [,}]")) { 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)) { ValueFlow::Value value(MathLib::toLongNumber(tok->str())); value.setKnown(); - setTokenValue(const_cast(tok), value); + setTokenValue(const_cast(tok), value, settings); } else if (tok->enumerator() && tok->enumerator()->value_known) { ValueFlow::Value value(tok->enumerator()->value); value.setKnown(); - setTokenValue(const_cast(tok), value); + setTokenValue(const_cast(tok), value, settings); } else if (tok->str() == "NULL" || (cpp && tok->str() == "nullptr")) { ValueFlow::Value value(0); value.setKnown(); - setTokenValue(const_cast(tok), value); + setTokenValue(const_cast(tok), value, settings); } else if (Token::simpleMatch(tok, "sizeof (") && tok->tokAt(2)) { const Token *tok2 = tok->tokAt(2); if (tok2->enumerator() && tok2->enumerator()->scope) { @@ -575,8 +602,8 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti } ValueFlow::Value value(size); value.setKnown(); - setTokenValue(const_cast(tok), value); - setTokenValue(const_cast(tok->next()), value); + setTokenValue(const_cast(tok), value, settings); + setTokenValue(const_cast(tok->next()), value, settings); } else if (tok2->type() && tok2->type()->isEnumType()) { long long size = settings->sizeof_int; if (tok2->type()->classScope) { @@ -591,8 +618,8 @@ static Token * valueFlowSetConstantValue(const Token *tok, const Settings *setti } ValueFlow::Value value(size); value.setKnown(); - setTokenValue(const_cast(tok), value); - setTokenValue(const_cast(tok->next()), value); + setTokenValue(const_cast(tok), value, settings); + setTokenValue(const_cast(tok->next()), value, settings); } // skip over enum tok = tok->linkAt(1); diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 3a3e2aaf3..15cdd4411 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -339,6 +339,13 @@ private: ASSERT_EQUALS(1U, values.size()); 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" " a = !x;\n"