valueFlowContainerSize: add simple forward analysis
This commit is contained in:
parent
2b10e38eec
commit
4a502a7f6b
|
@ -1832,7 +1832,7 @@ static bool valueFlowForward(Token * const startToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward known values in the else branch
|
// Forward known values in the else branch
|
||||||
if(Token::simpleMatch(end, "} else {")) {
|
if (Token::simpleMatch(end, "} else {")) {
|
||||||
std::list<ValueFlow::Value> knownValues;
|
std::list<ValueFlow::Value> knownValues;
|
||||||
std::copy_if(values.begin(), values.end(), std::back_inserter(knownValues), std::mem_fn(&ValueFlow::Value::isKnown));
|
std::copy_if(values.begin(), values.end(), std::back_inserter(knownValues), std::mem_fn(&ValueFlow::Value::isKnown));
|
||||||
valueFlowForward(end->tokAt(2),
|
valueFlowForward(end->tokAt(2),
|
||||||
|
@ -3441,7 +3441,24 @@ static void valueFlowContainerReverse(const Token *tok, unsigned int containerId
|
||||||
if (Token::Match(tok, "%name% ="))
|
if (Token::Match(tok, "%name% ="))
|
||||||
break;
|
break;
|
||||||
if (!tok->valueType() || !tok->valueType()->container)
|
if (!tok->valueType() || !tok->valueType()->container)
|
||||||
|
break;
|
||||||
|
if (Token::Match(tok, "%name% . %name% (") && tok->valueType()->container->getAction(tok->strAt(2)) != Library::Container::Action::NO_ACTION)
|
||||||
|
break;
|
||||||
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void valueFlowContainerForward(const Token *tok, unsigned int containerId, const ValueFlow::Value &value, const Settings *settings)
|
||||||
|
{
|
||||||
|
while (nullptr != (tok = tok->next())) {
|
||||||
|
if (Token::Match(tok, "[{}]"))
|
||||||
|
break;
|
||||||
|
if (tok->varId() != containerId)
|
||||||
continue;
|
continue;
|
||||||
|
if (Token::Match(tok, "%name% ="))
|
||||||
|
break;
|
||||||
|
if (!tok->valueType() || !tok->valueType()->container)
|
||||||
|
break;
|
||||||
if (Token::Match(tok, "%name% . %name% (") && tok->valueType()->container->getAction(tok->strAt(2)) != Library::Container::Action::NO_ACTION)
|
if (Token::Match(tok, "%name% . %name% (") && tok->valueType()->container->getAction(tok->strAt(2)) != Library::Container::Action::NO_ACTION)
|
||||||
break;
|
break;
|
||||||
setTokenValue(const_cast<Token *>(tok), value, settings);
|
setTokenValue(const_cast<Token *>(tok), value, settings);
|
||||||
|
@ -3483,6 +3500,10 @@ static void valueFlowContainerSize(TokenList * /*tokenlist*/, SymbolDatabase* sy
|
||||||
ValueFlow::Value value(conditionToken, intval);
|
ValueFlow::Value value(conditionToken, intval);
|
||||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
valueFlowContainerReverse(scope.classDef, tok->varId(), value, settings);
|
valueFlowContainerReverse(scope.classDef, tok->varId(), value, settings);
|
||||||
|
const Token *after = scope.bodyEnd;
|
||||||
|
if (Token::simpleMatch(after, "} else {"))
|
||||||
|
after = after->linkAt(2);
|
||||||
|
valueFlowContainerForward(after, tok->varId(), value, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,8 @@ private:
|
||||||
|
|
||||||
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
||||||
if (tok->str() == "x" && tok->linenr() == linenr) {
|
if (tok->str() == "x" && tok->linenr() == linenr) {
|
||||||
for(const ValueFlow::Value& val:tok->values()) {
|
for (const ValueFlow::Value& val:tok->values()) {
|
||||||
if(val.isKnown() && val.intvalue == value)
|
if (val.isKnown() && val.intvalue == value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3245,9 +3245,16 @@ private:
|
||||||
ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0);
|
ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isPossibleContainerSizeValue(const std::list<ValueFlow::Value> &values, MathLib::bigint i) {
|
||||||
|
return values.size() == 1 &&
|
||||||
|
values.front().isContainerSizeValue() &&
|
||||||
|
values.front().isPossible() &&
|
||||||
|
values.front().intvalue == i;
|
||||||
|
}
|
||||||
|
|
||||||
void valueFlowContainerSize() {
|
void valueFlowContainerSize() {
|
||||||
const char *code;
|
const char *code;
|
||||||
std::list<ValueFlow::Value> values;
|
|
||||||
|
|
||||||
LOAD_LIB_2(settings.library, "std.cfg");
|
LOAD_LIB_2(settings.library, "std.cfg");
|
||||||
|
|
||||||
|
@ -3256,37 +3263,33 @@ private:
|
||||||
" ints.front();\n"
|
" ints.front();\n"
|
||||||
" if (ints.empty()) {}\n"
|
" if (ints.empty()) {}\n"
|
||||||
"}";
|
"}";
|
||||||
values = tokenValues(code, "ints . front");
|
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
|
||||||
ASSERT_EQUALS(1, values.size());
|
|
||||||
ASSERT_EQUALS(true, values.empty() ? true : values.front().isContainerSizeValue());
|
|
||||||
ASSERT_EQUALS(0, values.empty() ? 0 : values.front().intvalue);
|
|
||||||
|
|
||||||
code = "void f(const std::list<int> &ints) {\n"
|
code = "void f(const std::list<int> &ints) {\n"
|
||||||
" ints.front();\n"
|
" ints.front();\n"
|
||||||
" if (ints.size()==0) {}\n"
|
" if (ints.size()==0) {}\n"
|
||||||
"}";
|
"}";
|
||||||
values = tokenValues(code, "ints . front");
|
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
|
||||||
ASSERT_EQUALS(1, values.size());
|
|
||||||
ASSERT_EQUALS(true, values.empty() ? true : values.front().isContainerSizeValue());
|
|
||||||
ASSERT_EQUALS(0, values.empty() ? 0 : values.front().intvalue);
|
|
||||||
|
|
||||||
code = "void f(std::list<int> ints) {\n"
|
code = "void f(std::list<int> ints) {\n"
|
||||||
" ints.front();\n"
|
" ints.front();\n"
|
||||||
" ints.pop_back();\n"
|
" ints.pop_back();\n"
|
||||||
" if (ints.empty()) {}\n"
|
" if (ints.empty()) {}\n"
|
||||||
"}";
|
"}";
|
||||||
values = tokenValues(code, "ints . front");
|
ASSERT(tokenValues(code, "ints . front").empty());
|
||||||
ASSERT_EQUALS(true, values.empty());
|
|
||||||
|
|
||||||
code = "void f(std::vector<int> v) {\n"
|
code = "void f(std::vector<int> v) {\n"
|
||||||
" v[10] = 0;\n"
|
" v[10] = 0;\n"
|
||||||
" if (v.size() == 10) {}\n"
|
" if (v.size() == 10) {}\n"
|
||||||
"}";
|
"}";
|
||||||
values = tokenValues(code, "v [");
|
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "v ["), 10));
|
||||||
ASSERT_EQUALS(1, values.size());
|
|
||||||
ASSERT_EQUALS(true, values.empty() ? true : values.front().isContainerSizeValue());
|
|
||||||
ASSERT_EQUALS(10, values.empty() ? 10 : values.front().intvalue);
|
|
||||||
|
|
||||||
|
// valueFlowContainerForward
|
||||||
|
code = "void f(const std::list<int> &ints) {\n"
|
||||||
|
" if (ints.empty()) {}\n"
|
||||||
|
" ints.front();\n"
|
||||||
|
"}";
|
||||||
|
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue