Add tests for container changes

This commit is contained in:
Paul 2020-08-09 22:52:03 -05:00
parent 26693df788
commit fec2914700
4 changed files with 62 additions and 4 deletions

View File

@ -5640,6 +5640,11 @@ struct ContainerVariableForwardAnalyzer : VariableForwardAnalyzer {
if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) { return rhsval.isKnown() && rhsval.isContainerSizeValue(); }))
return Action::Read | Action::Write;
}
} else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP)
return Action::Read | Action::Write;
const Token* arg = tok->tokAt(4);
}
return Action::None;
}
@ -5664,6 +5669,12 @@ struct ContainerVariableForwardAnalyzer : VariableForwardAnalyzer {
}
}
}
} else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
if (action == Library::Container::Action::PUSH)
value->intvalue++;
if (action == Library::Container::Action::POP)
value->intvalue--;
}
}
@ -5885,6 +5896,19 @@ static void valueFlowContainerSize(TokenList *tokenlist, SymbolDatabase* symbold
value.setKnown();
valueFlowContainerForward(containerTok->next(), containerTok->variable(), value, tokenlist);
}
} else if (Token::Match(tok, "%var% . %name% (") && tok->valueType() && tok->valueType()->container) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
if (action == Library::Container::Action::CLEAR) {
ValueFlow::Value value(0);
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
value.setKnown();
valueFlowContainerForward(tok->next(), tok->variable(), value, tokenlist);
} else if (action == Library::Container::Action::RESIZE && tok->tokAt(4)->hasKnownIntValue()) {
ValueFlow::Value value(tok->tokAt(4)->values().front());
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
value.setKnown();
valueFlowContainerForward(tok->next(), tok->variable(), value, tokenlist);
}
}
}
}

View File

@ -88,7 +88,7 @@ void QList1(QList<int> intListArg)
QList<QString> qstringList2 = {"one", "two"};
(void)qstringList2[1];
qstringList2.clear();
// TODO: cppcheck-suppress containerOutOfBounds #9243
// cppcheck-suppress containerOutOfBounds
(void)qstringList2[1];
QList<QString> qstringList3;
@ -117,7 +117,7 @@ void QList1(QList<int> intListArg)
qstringList4.append("a");
(void)qstringList4[0];
qstringList4.clear();
// TODO: cppcheck-suppress containerOutOfBounds #9243
// cppcheck-suppress containerOutOfBounds
(void)qstringList4[0];
}

View File

@ -33,7 +33,8 @@ wxString containerOutOfBounds_wxArrayString(void)
wxArrayString a;
a.Add("42");
a.Clear();
// cppcheck-suppress containerOutOfBounds
// TODO: wxArrayString is defined to be a vector
// TODO: cppcheck-suppress containerOutOfBounds
return a[0];
}
@ -42,7 +43,8 @@ int containerOutOfBounds_wxArrayInt(void)
wxArrayInt a;
a.Add(42);
a.Clear();
// cppcheck-suppress containerOutOfBounds
// TODO: wxArrayString is defined to be a vector
// TODO: cppcheck-suppress containerOutOfBounds
return a[0];
}

View File

@ -324,6 +324,12 @@ private:
return tok ? tok->values() : std::list<ValueFlow::Value>();
}
std::list<ValueFlow::Value> tokenValues(const char code[], const char tokstr[], ValueFlow::Value::ValueType vt, const Settings *s = nullptr) {
std::list<ValueFlow::Value> values = tokenValues(code, tokstr, s);
values.remove_if([&](const ValueFlow::Value& v) { return v.valueType != vt; });
return values;
}
ValueFlow::Value valueOfTok(const char code[], const char tokstr[]) {
std::list<ValueFlow::Value> values = tokenValues(code, tokstr);
return values.size() == 1U && !values.front().isTokValue() ? values.front() : ValueFlow::Value();
@ -4439,6 +4445,32 @@ private:
" x = s + s;\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "+"), 8));
code = "void f(const std::vector<int> &ints) {\n"
" ints.clear();\n"
" ints.front();\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 0));
code = "void f(const std::vector<int> &ints) {\n"
" ints.resize(3);\n"
" ints.front();\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 3));
code = "void f(const std::vector<int> &ints) {\n"
" ints.resize(3);\n"
" ints.push_back(3);\n"
" ints.front();\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 4));
code = "void f(const std::vector<int> &ints) {\n"
" ints.resize(3);\n"
" ints.pop_back();\n"
" ints.front();\n"
"}";
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "ints . front", ValueFlow::Value::CONTAINER_SIZE), 2));
}
void valueFlowDynamicBufferSize() {