ValueFlow: Improved when using '[' on arrays and strings
This commit is contained in:
parent
8427398d9d
commit
d1892786b8
@ -317,14 +317,16 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token *parent = const_cast<Token*>(tok->astParent());
|
Token *parent = const_cast<Token*>(tok->astParent());
|
||||||
|
if (!parent)
|
||||||
|
return;
|
||||||
|
|
||||||
// Cast..
|
// Cast..
|
||||||
if (parent && parent->str() == "(" && tok == parent->link()->next()) {
|
if (parent->str() == "(" && tok == parent->link()->next()) {
|
||||||
setTokenValue(parent,value);
|
setTokenValue(parent,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculations..
|
// Calculations..
|
||||||
else if (parent && parent->isArithmeticalOp() && parent->astOperand1() && parent->astOperand2()) {
|
else if (parent->isArithmeticalOp() && parent->astOperand1() && parent->astOperand2()) {
|
||||||
std::list<ValueFlow::Value>::const_iterator value1, value2;
|
std::list<ValueFlow::Value>::const_iterator value1, value2;
|
||||||
for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) {
|
for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) {
|
||||||
for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) {
|
for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) {
|
||||||
@ -365,6 +367,49 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Array element
|
||||||
|
else if (parent->str() == "[" && parent->astOperand1() && parent->astOperand2()) {
|
||||||
|
std::list<ValueFlow::Value>::const_iterator value1, value2;
|
||||||
|
for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) {
|
||||||
|
if (!value1->tokvalue)
|
||||||
|
continue;
|
||||||
|
for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) {
|
||||||
|
if (value2->tokvalue)
|
||||||
|
continue;
|
||||||
|
if (value1->varId == 0U || value2->varId == 0U ||
|
||||||
|
(value1->varId == value2->varId && value1->varvalue == value2->varvalue)) {
|
||||||
|
ValueFlow::Value result(0);
|
||||||
|
result.condition = value1->condition ? value1->condition : value2->condition;
|
||||||
|
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->tokvalue->type() == Token::eString) {
|
||||||
|
const std::string s = value1->tokvalue->strValue();
|
||||||
|
const MathLib::bigint index = value2->intvalue;
|
||||||
|
if (index >= 0 && index < s.size()) {
|
||||||
|
result.intvalue = s[index];
|
||||||
|
setTokenValue(parent, result);
|
||||||
|
}
|
||||||
|
} else if (value1->tokvalue->str() == "{") {
|
||||||
|
MathLib::bigint index = value2->intvalue;
|
||||||
|
const Token *element = value1->tokvalue->next();
|
||||||
|
while (index > 0 && element->str() != "}") {
|
||||||
|
if (element->str() == ",")
|
||||||
|
--index;
|
||||||
|
if (Token::Match(element, "[{}()[]]"))
|
||||||
|
break;
|
||||||
|
element = element->next();
|
||||||
|
}
|
||||||
|
if (Token::Match(element, "%num% [,}]")) {
|
||||||
|
result.intvalue = MathLib::toLongNumber(element->str());
|
||||||
|
setTokenValue(parent, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowNumber(TokenList *tokenlist)
|
static void valueFlowNumber(TokenList *tokenlist)
|
||||||
@ -377,28 +422,40 @@ static void valueFlowNumber(TokenList *tokenlist)
|
|||||||
|
|
||||||
static void valueFlowString(TokenList *tokenlist)
|
static void valueFlowString(TokenList *tokenlist)
|
||||||
{
|
{
|
||||||
std::map<unsigned int, const Token *> constantStrings;
|
|
||||||
|
|
||||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
if (tok->type() == Token::eString) {
|
if (tok->type() == Token::eString) {
|
||||||
ValueFlow::Value strvalue;
|
ValueFlow::Value strvalue;
|
||||||
strvalue.tokvalue = tok;
|
strvalue.tokvalue = tok;
|
||||||
setTokenValue(tok, strvalue);
|
setTokenValue(tok, strvalue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void valueFlowArray(TokenList *tokenlist)
|
||||||
|
{
|
||||||
|
std::map<unsigned int, const Token *> constantArrays;
|
||||||
|
|
||||||
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "const %type% %var% [ %num%| ] = {")) {
|
||||||
|
const Token *vartok = tok->tokAt(2);
|
||||||
|
const Token *rhstok = vartok->next()->link()->tokAt(2);
|
||||||
|
constantArrays[vartok->varId()] = rhstok;
|
||||||
|
tok = rhstok->link();
|
||||||
|
}
|
||||||
|
|
||||||
if (Token::Match(tok, "const char %var% [ %num%| ] = %str% ;")) {
|
if (Token::Match(tok, "const char %var% [ %num%| ] = %str% ;")) {
|
||||||
const Token *vartok = tok->tokAt(2);
|
const Token *vartok = tok->tokAt(2);
|
||||||
const Token *strtok = vartok->next()->link()->tokAt(2);
|
const Token *strtok = vartok->next()->link()->tokAt(2);
|
||||||
constantStrings[vartok->varId()] = strtok;
|
constantArrays[vartok->varId()] = strtok;
|
||||||
tok = vartok->next();
|
tok = strtok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->varId() > 0U) {
|
if (tok->varId() > 0U) {
|
||||||
const std::map<unsigned int, const Token *>::const_iterator it = constantStrings.find(tok->varId());
|
const std::map<unsigned int, const Token *>::const_iterator it = constantArrays.find(tok->varId());
|
||||||
if (it != constantStrings.end()) {
|
if (it != constantArrays.end()) {
|
||||||
ValueFlow::Value strvalue;
|
ValueFlow::Value value;
|
||||||
strvalue.tokvalue = it->second;
|
value.tokvalue = it->second;
|
||||||
setTokenValue(tok, strvalue);
|
setTokenValue(tok, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1781,6 +1838,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
|||||||
|
|
||||||
valueFlowNumber(tokenlist);
|
valueFlowNumber(tokenlist);
|
||||||
valueFlowString(tokenlist);
|
valueFlowString(tokenlist);
|
||||||
|
valueFlowArray(tokenlist);
|
||||||
valueFlowPointerAlias(tokenlist);
|
valueFlowPointerAlias(tokenlist);
|
||||||
valueFlowFunctionReturn(tokenlist, errorLogger, settings);
|
valueFlowFunctionReturn(tokenlist, errorLogger, settings);
|
||||||
valueFlowBitAnd(tokenlist);
|
valueFlowBitAnd(tokenlist);
|
||||||
|
@ -37,6 +37,7 @@ private:
|
|||||||
TEST_CASE(valueFlowNumber);
|
TEST_CASE(valueFlowNumber);
|
||||||
TEST_CASE(valueFlowString);
|
TEST_CASE(valueFlowString);
|
||||||
TEST_CASE(valueFlowPointerAlias);
|
TEST_CASE(valueFlowPointerAlias);
|
||||||
|
TEST_CASE(valueFlowArrayElement);
|
||||||
|
|
||||||
TEST_CASE(valueFlowBitAnd);
|
TEST_CASE(valueFlowBitAnd);
|
||||||
|
|
||||||
@ -198,6 +199,24 @@ private:
|
|||||||
ASSERT_EQUALS(true, testValueOfX(code, 4, "& i"));
|
ASSERT_EQUALS(true, testValueOfX(code, 4, "& i"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void valueFlowArrayElement() {
|
||||||
|
const char *code;
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" const int a[] = {43,23,12};\n"
|
||||||
|
" int x = a[0];\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 43));
|
||||||
|
|
||||||
|
code = "void f() {\n"
|
||||||
|
" const char abcd[] = \"abcd\";\n"
|
||||||
|
" int x = abcd[2];\n"
|
||||||
|
" return x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 'c'));
|
||||||
|
}
|
||||||
|
|
||||||
void valueFlowCalculations() {
|
void valueFlowCalculations() {
|
||||||
const char *code;
|
const char *code;
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user