Refactorized CheckStl::mismatchingContainersError:

- Improved error message
- Made patterns more generic by using Token::nextArgument()
This commit is contained in:
PKEuS 2012-04-17 12:21:41 +02:00
parent 88aa08e71b
commit 82cd022646
2 changed files with 40 additions and 39 deletions

View File

@ -184,7 +184,7 @@ void CheckStl::iterators()
// Error message for bad iterator usage.. // Error message for bad iterator usage..
void CheckStl::mismatchingContainersError(const Token *tok) void CheckStl::mismatchingContainersError(const Token *tok)
{ {
reportError(tok, Severity::error, "mismatchingContainers", "mismatching containers"); reportError(tok, Severity::error, "mismatchingContainers", "Iterators of mismatching containers are used together.");
} }
void CheckStl::mismatchingContainers() void CheckStl::mismatchingContainers()
@ -193,7 +193,7 @@ void CheckStl::mismatchingContainers()
"adjacent_find", "binary_search", "count", "count_if", "equal", "equal_range", "find", "find_if", "for_each", "generate", "lower_bound", "make_heap", "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", "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", "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" "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 static const char* const algorithm22_strings[] = { // func(begin1, end1, begin2, end2
"find_end", "find_first_of", "includes", "lexicographical_compare", "merge", "partial_sort_copy", "find_end", "find_first_of", "includes", "lexicographical_compare", "merge", "partial_sort_copy",
@ -210,47 +210,40 @@ void CheckStl::mismatchingContainers()
static const std::string iteratorBeginFuncPattern = "begin|cbegin|rbegin|crbegin"; static const std::string iteratorBeginFuncPattern = "begin|cbegin|rbegin|crbegin";
static const std::string iteratorEndFuncPattern = "end|cend|rend|crend"; static const std::string iteratorEndFuncPattern = "end|cend|rend|crend";
static const std::string pattern2 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) ,|)"; static const std::string pattern1x1_1 = "%var% . " + iteratorBeginFuncPattern + " ( ) , ";
static const std::string pattern22 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) , %var% . " + iteratorBeginFuncPattern + " ( ) , %var% . " + iteratorEndFuncPattern + " ( ) ,|)"; static const std::string pattern1x1_2 = "%var% . " + iteratorEndFuncPattern + " ( ) ,|)";
static const std::string pattern1x1_1 = "std :: %type% ( %var% . " + iteratorBeginFuncPattern + " ( ) , "; static const std::string pattern2 = pattern1x1_1 + pattern1x1_2;
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 (!Token::Match(tok, "std :: %type% ( !!)"))
continue; continue;
const Token* arg1 = tok->tokAt(4);
// 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, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) { if (Token::Match(arg1, pattern2.c_str()) && algorithm2.find(tok->strAt(2)) != algorithm2.end()) {
if (tok->strAt(4) != tok->strAt(10)) { if (arg1->str() != arg1->strAt(6)) {
mismatchingContainersError(tok); mismatchingContainersError(arg1);
} }
tok = tok->tokAt(15); } else if (algorithm22.find(tok->strAt(2)) != algorithm22.end()) {
} else if (Token::Match(tok, pattern22.c_str()) && algorithm22.find(tok->strAt(2)) != algorithm22.end()) { if (Token::Match(arg1, pattern2.c_str()) && arg1->str() != arg1->strAt(6))
if (tok->strAt(4) != tok->strAt(10) || tok->strAt(16) != tok->strAt(22)) { mismatchingContainersError(arg1);
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 // Find third parameter
const Token *tok2 = tok->tokAt(10); const Token* arg3 = arg1;
int bracket = 0; for (unsigned int i = 0; i < 2 && arg3; i++)
for (; tok2; tok2 = tok2->next()) { arg3 = arg3->nextArgument();
if (tok2->str() == "(") if (Token::Match(arg3, pattern2.c_str()) && arg3->str() != arg3->strAt(6))
bracket++; mismatchingContainersError(arg3);
else if (tok2->str() == ")") } else if (Token::Match(arg1, pattern1x1_1.c_str()) && algorithm1x1.find(tok->strAt(2)) != algorithm1x1.end()) {
bracket--; // Find third parameter
else if (tok2->str() == "," && bracket == 0) const Token *arg3 = arg1->tokAt(6)->nextArgument();
break; if (Token::Match(arg3, pattern1x1_2.c_str())) {
} if (arg1->str() != arg3->str()) {
if (tok2 && Token::Match(tok2, pattern1x1_2.c_str())) { mismatchingContainersError(arg1);
if (tok->strAt(4) != tok2->strAt(1)) {
mismatchingContainersError(tok);
} }
tok = tok2->tokAt(6); }
} else
tok = tok->tokAt(9);
} }
tok = arg1->linkAt(-1);
} }
} }

View File

@ -206,7 +206,7 @@ private:
" std::vector<int> ints2;\n" " std::vector<int> ints2;\n"
" std::vector<int>::iterator it = std::find(ints1.begin(), ints2.end(), 22);\n" " std::vector<int>::iterator it = std::find(ints1.begin(), ints2.end(), 22);\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Iterators of mismatching containers are used together.\n", errout.str());
} }
void iterator6() { void iterator6() {
@ -227,7 +227,7 @@ private:
" std::set<int>::iterator it2 = ints2.end();\n" " std::set<int>::iterator it2 = ints2.end();\n"
" ints2.insert(it1, it2);\n" " ints2.insert(it1, it2);\n"
"}\n"); "}\n");
TODO_ASSERT_EQUALS("error", "", errout.str()); TODO_ASSERT_EQUALS("[test.cpp:6]: (error) Iterators of mismatching containers are used together.\n", "", errout.str());
} }
void iterator7() { void iterator7() {
@ -235,9 +235,9 @@ private:
"{\n" "{\n"
" std::vector<int> ints1;\n" " std::vector<int> ints1;\n"
" std::vector<int> ints2;\n" " std::vector<int> ints2;\n"
" std::vector<int>::iterator it = std::inplace_merge(ints1.begin(), std:.advance(ints1.rbegin(), 5), ints2.end());\n" " std::vector<int>::iterator it = std::inplace_merge(ints1.begin(), std::advance(ints1.rbegin(), 5), ints2.end());\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Iterators of mismatching containers are used together.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -255,7 +255,7 @@ private:
" std::vector<int> ints2;\n" " std::vector<int> ints2;\n"
" std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints2.end(), ints1.begin(), ints1.end());\n" " std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints2.end(), ints1.begin(), ints1.end());\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Iterators of mismatching containers are used together.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"
@ -263,7 +263,15 @@ private:
" std::vector<int> ints2;\n" " std::vector<int> ints2;\n"
" std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints1.end());\n" " std::vector<int>::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints1.end());\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) mismatching containers\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Iterators of mismatching containers are used together.\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(foo.bar.begin(), foo.bar.end()-6, ints2.begin(), ints1.end());\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Iterators of mismatching containers are used together.\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"