Fixed #3223 (Improve check: Check more STL algorithms for missmatching containers check)
This commit is contained in:
parent
ea02bd905a
commit
dc15641954
|
@ -98,7 +98,7 @@ void CheckStl::iterators()
|
||||||
const Token *decltok = variableInfo ? variableInfo->typeStartToken() : NULL;
|
const Token *decltok = variableInfo ? variableInfo->typeStartToken() : NULL;
|
||||||
|
|
||||||
if (Token::Match(decltok, "const| std :: set"))
|
if (Token::Match(decltok, "const| std :: set"))
|
||||||
continue; // No warning
|
continue; // No warning
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show error message, mismatching iterator is used.
|
// Show error message, mismatching iterator is used.
|
||||||
|
@ -170,16 +170,67 @@ void CheckStl::mismatchingContainersError(const Token *tok)
|
||||||
|
|
||||||
void CheckStl::mismatchingContainers()
|
void CheckStl::mismatchingContainers()
|
||||||
{
|
{
|
||||||
|
static const char* const algorithm2_strings[] = { // func(begin1, end1
|
||||||
|
"adjacent_find", "binary_search", "count", "count_if", "equal", "equal_range", "find", "find_if", "for_each", "generate", "lower_bound", "make_heap",
|
||||||
|
"max_element", "min_element", "mismatch", "next_permutation", "partition", "pop_heap", "prev_permutation", "push_heap", "random_shuffle", "remove",
|
||||||
|
"remove_copy", "remove_copy_if", "remove_if", "replace", "replace_copy", "replace_copy_if", "replace_if", "reverse", "reverse_copy", "search_n",
|
||||||
|
"sort", "sort_heap", "stable_partition", "stable_sort", "swap_ranges", "transform", "unique", "unique_copy", "upper_bound"
|
||||||
|
};
|
||||||
|
static const char* const algorithm22_strings[] = { // func(begin1, end1, begin2, end2
|
||||||
|
"find_end", "find_first_of", "includes", "lexicographical_compare", "merge", "partial_sort_copy",
|
||||||
|
"search", "set_difference", "set_intersection", "set_symmetric_difference", "set_union"
|
||||||
|
};
|
||||||
|
static const char* const algorithm1x1_strings[] = { // func(begin1, x, end1
|
||||||
|
"inplace_merge", "nth_element", "partial_sort", "rotate", "rotate_copy"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::set<std::string> algorithm2(algorithm2_strings, &algorithm2_strings[sizeof(algorithm2_strings) / sizeof(*algorithm2_strings)]);
|
||||||
|
static const std::set<std::string> algorithm22(algorithm22_strings, &algorithm22_strings[sizeof(algorithm22_strings) / sizeof(*algorithm22_strings)]);
|
||||||
|
static const std::set<std::string> algorithm1x1(algorithm1x1_strings, &algorithm1x1_strings[sizeof(algorithm1x1_strings) / sizeof(*algorithm1x1_strings)]);
|
||||||
|
|
||||||
|
static const std::string iteratorBeginFuncPattern = "begin|cbegin|rbegin|crbegin";
|
||||||
|
static const std::string iteratorEndFuncPattern = "end|cend|rend|crend";
|
||||||
|
|
||||||
|
static const std::string pattern2 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) ,|)";
|
||||||
|
static const std::string pattern22 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) , %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) ,|)";
|
||||||
|
static const std::string pattern1x1_1 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , ";
|
||||||
|
static const std::string pattern1x1_2 = ", %var% . " + iteratorEndFuncPattern + " ( ) ,|)";
|
||||||
|
|
||||||
// Check if different containers are used in various calls of standard functions
|
// Check if different containers are used in various calls of standard functions
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||||
if (tok->str() != "std")
|
if (tok->str() != "std")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: If iterator variables are used instead then there are false negatives.
|
// TODO: If iterator variables are used instead then there are false negatives.
|
||||||
if (Token::Match(tok, "std :: find|find_if|count|transform|replace|replace_if|sort ( %var% . begin|rbegin ( ) , %var% . end|rend ( ) ,")) {
|
if (Token::Match(tok, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) {
|
||||||
if (tok->tokAt(4)->str() != tok->tokAt(10)->str()) {
|
if (tok->tokAt(4)->str() != tok->tokAt(10)->str()) {
|
||||||
mismatchingContainersError(tok);
|
mismatchingContainersError(tok);
|
||||||
}
|
}
|
||||||
|
tok = tok->tokAt(15);
|
||||||
|
} else if (Token::Match(tok, pattern22.c_str()) && algorithm22.find(tok->strAt(2)) != algorithm22.end()) {
|
||||||
|
if (tok->tokAt(4)->str() != tok->tokAt(10)->str() || tok->tokAt(16)->str() != tok->tokAt(22)->str()) {
|
||||||
|
mismatchingContainersError(tok);
|
||||||
|
}
|
||||||
|
tok = tok->tokAt(27);
|
||||||
|
} else if (Token::Match(tok, pattern1x1_1.c_str()) && algorithm1x1.find(tok->strAt(2)) != algorithm1x1.end()) {
|
||||||
|
// Find third parameter
|
||||||
|
const Token *tok2 = tok->tokAt(10);
|
||||||
|
int bracket = 0;
|
||||||
|
for (; tok2; tok2 = tok2->next()) {
|
||||||
|
if (tok2->str() == "(")
|
||||||
|
bracket++;
|
||||||
|
else if (tok2->str() == ")")
|
||||||
|
bracket--;
|
||||||
|
else if (tok2->str() == "," && bracket == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tok2 && Token::Match(tok2, pattern1x1_2.c_str())) {
|
||||||
|
if (tok->tokAt(4)->str() != tok2->tokAt(1)->str()) {
|
||||||
|
mismatchingContainersError(tok);
|
||||||
|
}
|
||||||
|
tok = tok2->tokAt(6);
|
||||||
|
} else
|
||||||
|
tok = tok->tokAt(9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +247,6 @@ void CheckStl::stlOutOfBounds()
|
||||||
// check if the for loop condition is wrong
|
// check if the for loop condition is wrong
|
||||||
unsigned int indent = 0;
|
unsigned int indent = 0;
|
||||||
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
|
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
|
||||||
|
|
||||||
if (tok2->str() == "(")
|
if (tok2->str() == "(")
|
||||||
++indent;
|
++indent;
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ private:
|
||||||
TEST_CASE(iterator6);
|
TEST_CASE(iterator6);
|
||||||
TEST_CASE(iterator7);
|
TEST_CASE(iterator7);
|
||||||
TEST_CASE(iterator8);
|
TEST_CASE(iterator8);
|
||||||
|
TEST_CASE(iterator9);
|
||||||
|
TEST_CASE(iterator10);
|
||||||
|
|
||||||
TEST_CASE(dereference);
|
TEST_CASE(dereference);
|
||||||
TEST_CASE(dereference_member);
|
TEST_CASE(dereference_member);
|
||||||
|
@ -214,6 +216,50 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterator7() {
|
void iterator7() {
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::vector<int> ints1;\n"
|
||||||
|
" std::vector<int> ints2;\n"
|
||||||
|
" std::vector<int>::iterator it = std::inplace_merge(ints1.begin(), std:.advance(ints1.rbegin(), 5), ints2.end());\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::vector<int> ints1;\n"
|
||||||
|
" std::vector<int> ints2;\n"
|
||||||
|
" std::vector<int>::iterator it = std::inplace_merge(ints1.begin(), std::advance(ints2.rbegin(), 5), ints1.end());\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void iterator8() {
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::vector<int> ints1;\n"
|
||||||
|
" std::vector<int> ints2;\n"
|
||||||
|
" std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints2.end(), ints1.begin(), ints1.end());\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::vector<int> ints1;\n"
|
||||||
|
" std::vector<int> ints2;\n"
|
||||||
|
" std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints1.end());\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::vector<int> ints1;\n"
|
||||||
|
" std::vector<int> ints2;\n"
|
||||||
|
" std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints2.end());\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void iterator9() {
|
||||||
// Ticket #1600
|
// Ticket #1600
|
||||||
check("void foo(std::vector<int> &r)\n"
|
check("void foo(std::vector<int> &r)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -266,7 +312,7 @@ private:
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:14] (error) After insert, the iterator 'aI' may be invalid", "", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:14] (error) After insert, the iterator 'aI' may be invalid", "", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void iterator8() {
|
void iterator10() {
|
||||||
// Ticket #1679
|
// Ticket #1679
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
|
Loading…
Reference in New Issue