valueFlowContainerSize: forward analysis inside conditional code

This commit is contained in:
Daniel Marjamäki 2018-08-10 22:18:38 +02:00
parent 4a502a7f6b
commit 10461e5429
2 changed files with 48 additions and 10 deletions

View File

@ -3499,11 +3499,26 @@ 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;
// possible value before condition
valueFlowContainerReverse(scope.classDef, tok->varId(), value, settings); valueFlowContainerReverse(scope.classDef, tok->varId(), value, settings);
// possible value after condition
const Token *after = scope.bodyEnd; const Token *after = scope.bodyEnd;
if (Token::simpleMatch(after, "} else {")) if (Token::simpleMatch(after, "} else {"))
after = after->linkAt(2); after = after->linkAt(2);
valueFlowContainerForward(after, tok->varId(), value, settings); valueFlowContainerForward(after, tok->varId(), value, settings);
// known value in conditional code
if (conditionToken->str() == "==" || conditionToken->str() == "(") {
const Token *parent = conditionToken;
while (parent && parent->str() != "!")
parent = parent->astParent();
if (!parent) {
value.setKnown();
valueFlowContainerForward(scope.bodyStart, tok->varId(), value, settings);
}
}
} }
} }
} }

View File

@ -3245,17 +3245,33 @@ 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) { static std::string isPossibleContainerSizeValue(const std::list<ValueFlow::Value> &values, MathLib::bigint i) {
return values.size() == 1 && if (values.size() != 1)
values.front().isContainerSizeValue() && return "values.size():" + std::to_string(values.size());
values.front().isPossible() && if (!values.front().isContainerSizeValue())
values.front().intvalue == i; return "ContainerSizeValue";
if (!values.front().isPossible())
return "Possible";
if (values.front().intvalue != i)
return "intvalue:" + std::to_string(values.front().intvalue);
return "";
}
static std::string isKnownContainerSizeValue(const std::list<ValueFlow::Value> &values, MathLib::bigint i) {
if (values.size() != 1)
return "values.size():" + std::to_string(values.size());
if (!values.front().isContainerSizeValue())
return "ContainerSizeValue";
if (!values.front().isKnown())
return "Known";
if (values.front().intvalue != i)
return "intvalue:" + std::to_string(values.front().intvalue);
return "";
} }
void valueFlowContainerSize() { void valueFlowContainerSize() {
const char *code; const char *code;
LOAD_LIB_2(settings.library, "std.cfg"); LOAD_LIB_2(settings.library, "std.cfg");
// valueFlowContainerReverse // valueFlowContainerReverse
@ -3263,13 +3279,13 @@ private:
" ints.front();\n" " ints.front();\n"
" if (ints.empty()) {}\n" " if (ints.empty()) {}\n"
"}"; "}";
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0)); ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
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"
"}"; "}";
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0)); ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
code = "void f(std::list<int> ints) {\n" code = "void f(std::list<int> ints) {\n"
" ints.front();\n" " ints.front();\n"
@ -3282,14 +3298,21 @@ private:
" v[10] = 0;\n" " v[10] = 0;\n"
" if (v.size() == 10) {}\n" " if (v.size() == 10) {}\n"
"}"; "}";
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "v ["), 10)); ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "v ["), 10));
// valueFlowContainerForward // valueFlowContainerForward
code = "void f(const std::list<int> &ints) {\n" code = "void f(const std::list<int> &ints) {\n"
" if (ints.empty()) {}\n" " if (ints.empty()) {}\n"
" ints.front();\n" " ints.front();\n"
"}"; "}";
ASSERT(isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0)); ASSERT_EQUALS("", isPossibleContainerSizeValue(tokenValues(code, "ints . front"), 0));
code = "void f(const std::list<int> &ints) {\n"
" if (ints.empty()) {\n"
" ints.front();\n"
" }\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front"), 0));
} }
}; };