Remove hardcoded lists of functions/templates/types (#5069)
* Remove hardcoded list of functions * Remove hardcoded list of templates * Remove hardcoded list of types * Format * Fix test * Unused variable * Add tests * auto -> int
This commit is contained in:
parent
ac41b45a5f
commit
774123d28d
|
@ -1148,16 +1148,18 @@ bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const
|
|||
return false;
|
||||
}
|
||||
|
||||
const Library::Container* Library::detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator) const
|
||||
const Library::Container* Library::detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator, bool withoutStd) const
|
||||
{
|
||||
for (const std::pair<const std::string, Library::Container> & c : containers) {
|
||||
const Container& container = c.second;
|
||||
if (container.startPattern.empty())
|
||||
continue;
|
||||
|
||||
const int offset = (withoutStd && container.startPattern2.find("std :: ") == 0) ? 7 : 0;
|
||||
|
||||
// If endPattern is undefined, it will always match, but itEndPattern has to be defined.
|
||||
if (detect != IteratorOnly && container.endPattern.empty()) {
|
||||
if (!Token::Match(typeStart, container.startPattern2.c_str()))
|
||||
if (!Token::Match(typeStart, container.startPattern2.c_str() + offset))
|
||||
continue;
|
||||
|
||||
if (isIterator)
|
||||
|
@ -1169,7 +1171,7 @@ const Library::Container* Library::detectContainerInternal(const Token* typeStar
|
|||
if (!tok->link())
|
||||
continue;
|
||||
|
||||
const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str());
|
||||
const bool matchedStartPattern = Token::Match(typeStart, container.startPattern2.c_str() + offset);
|
||||
|
||||
if (detect != ContainerOnly && matchedStartPattern && Token::Match(tok->link(), container.itEndPattern.c_str())) {
|
||||
if (isIterator)
|
||||
|
@ -1197,10 +1199,10 @@ const Library::Container* Library::detectIterator(const Token* typeStart) const
|
|||
return detectContainerInternal(typeStart, IteratorOnly);
|
||||
}
|
||||
|
||||
const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator) const
|
||||
const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator, bool withoutStd) const
|
||||
{
|
||||
bool res;
|
||||
const Library::Container* c = detectContainerInternal(typeStart, Both, &res);
|
||||
const Library::Container* c = detectContainerInternal(typeStart, Both, &res, withoutStd);
|
||||
if (c && isIterator)
|
||||
*isIterator = res;
|
||||
return c;
|
||||
|
@ -1627,9 +1629,9 @@ bool Library::isSmartPointer(const Token* tok) const
|
|||
return detectSmartPointer(tok);
|
||||
}
|
||||
|
||||
const Library::SmartPointer* Library::detectSmartPointer(const Token* tok) const
|
||||
const Library::SmartPointer* Library::detectSmartPointer(const Token* tok, bool withoutStd) const
|
||||
{
|
||||
std::string typestr;
|
||||
std::string typestr = withoutStd ? "std::" : "";
|
||||
while (Token::Match(tok, "%name%|::")) {
|
||||
typestr += tok->str();
|
||||
tok = tok->next();
|
||||
|
@ -1666,6 +1668,13 @@ Library::TypeCheck Library::getTypeCheck(std::string check, std::string typeNam
|
|||
return it == mTypeChecks.end() ? TypeCheck::def : it->second;
|
||||
}
|
||||
|
||||
bool Library::hasAnyTypeCheck(const std::string& typeName) const
|
||||
{
|
||||
return std::any_of(mTypeChecks.begin(), mTypeChecks.end(), [&](const std::pair<std::pair<std::string, std::string>, Library::TypeCheck>& tc) {
|
||||
return tc.first.second == typeName;
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Token> createTokenFromExpression(const std::string& returnValue,
|
||||
const Settings* settings,
|
||||
std::unordered_map<nonneg int, const Token*>* lookupVarId)
|
||||
|
|
|
@ -290,7 +290,7 @@ public:
|
|||
std::map<std::string, Container> containers;
|
||||
const Container* detectContainer(const Token* typeStart) const;
|
||||
const Container* detectIterator(const Token* typeStart) const;
|
||||
const Container* detectContainerOrIterator(const Token* typeStart, bool* isIterator = nullptr) const;
|
||||
const Container* detectContainerOrIterator(const Token* typeStart, bool* isIterator = nullptr, bool withoutStd = false) const;
|
||||
|
||||
class ArgumentChecks {
|
||||
public:
|
||||
|
@ -485,7 +485,7 @@ public:
|
|||
|
||||
std::unordered_map<std::string, SmartPointer> smartPointers;
|
||||
bool isSmartPointer(const Token *tok) const;
|
||||
const SmartPointer* detectSmartPointer(const Token* tok) const;
|
||||
const SmartPointer* detectSmartPointer(const Token* tok, bool withoutStd = false) const;
|
||||
|
||||
struct PodType {
|
||||
unsigned int size;
|
||||
|
@ -560,6 +560,7 @@ public:
|
|||
checkFiniteLifetime, // (unusedvar) object has side effects, but immediate destruction is wrong
|
||||
};
|
||||
TypeCheck getTypeCheck(std::string check, std::string typeName) const;
|
||||
bool hasAnyTypeCheck(const std::string& typeName) const;
|
||||
|
||||
private:
|
||||
// load a <function> xml node
|
||||
|
@ -655,7 +656,7 @@ private:
|
|||
}
|
||||
|
||||
enum DetectContainer { ContainerOnly, IteratorOnly, Both };
|
||||
const Library::Container* detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator = nullptr) const;
|
||||
const Library::Container* detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator = nullptr, bool withoutStd = false) const;
|
||||
};
|
||||
|
||||
CPPCHECKLIB const Library::Container * getLibraryContainer(const Token * tok);
|
||||
|
|
|
@ -9415,66 +9415,12 @@ void Tokenizer::simplifyBitfields()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Types and objects in std namespace that are neither functions nor templates
|
||||
static const std::set<std::string> stdTypes = {
|
||||
"string", "wstring", "u16string", "u32string",
|
||||
"iostream", "ostream", "ofstream", "ostringstream",
|
||||
"istream", "ifstream", "istringstream", "fstream", "stringstream",
|
||||
"wstringstream", "wistringstream", "wostringstream", "wstringbuf",
|
||||
"stringbuf", "streambuf", "ios", "filebuf", "ios_base",
|
||||
"exception", "bad_exception", "bad_alloc",
|
||||
"logic_error", "domain_error", "invalid_argument_", "length_error",
|
||||
"out_of_range", "runtime_error", "range_error", "overflow_error", "underflow_error",
|
||||
"locale",
|
||||
"cout", "cerr", "clog", "cin",
|
||||
"wcerr", "wcin", "wclog", "wcout",
|
||||
"endl", "ends", "flush",
|
||||
"boolalpha", "noboolalpha", "showbase", "noshowbase",
|
||||
"showpoint", "noshowpoint", "showpos", "noshowpos",
|
||||
"skipws", "noskipws", "unitbuf", "nounitbuf", "uppercase", "nouppercase",
|
||||
"dec", "hex", "oct",
|
||||
"fixed", "scientific",
|
||||
"internal", "left", "right",
|
||||
"fpos", "streamoff", "streampos", "streamsize"
|
||||
};
|
||||
|
||||
static const std::set<std::string> stdTemplates = {
|
||||
"array", "basic_string", "bitset", "deque", "list", "map", "multimap",
|
||||
"priority_queue", "queue", "set", "multiset", "stack", "vector", "pair",
|
||||
"iterator", "iterator_traits",
|
||||
"unordered_map", "unordered_multimap", "unordered_set", "unordered_multiset",
|
||||
"tuple", "function"
|
||||
};
|
||||
static const std::set<std::string> stdFunctions = {
|
||||
"getline",
|
||||
"for_each", "find", "find_if", "find_end", "find_first_of",
|
||||
"adjacent_find", "count", "count_if", "mismatch", "equal", "search", "search_n",
|
||||
"copy", "copy_backward", "swap", "swap_ranges", "iter_swap", "transform", "replace",
|
||||
"replace_if", "replace_copy", "replace_copy_if", "fill", "fill_n", "generate", "generate_n", "remove",
|
||||
"remove_if", "remove_copy", "remove_copy_if",
|
||||
"unique", "unique_copy", "reverse", "reverse_copy",
|
||||
"rotate", "rotate_copy", "random_shuffle", "partition", "stable_partition",
|
||||
"sort", "stable_sort", "partial_sort", "partial_sort_copy", "nth_element",
|
||||
"lower_bound", "upper_bound", "equal_range", "binary_search", "merge", "inplace_merge", "includes",
|
||||
"set_union", "set_intersection", "set_difference",
|
||||
"set_symmetric_difference", "push_heap", "pop_heap", "make_heap", "sort_heap",
|
||||
"min", "max", "min_element", "max_element", "lexicographical_compare", "next_permutation", "prev_permutation",
|
||||
"advance", "back_inserter", "distance", "front_inserter", "inserter",
|
||||
"make_pair", "make_shared", "make_tuple",
|
||||
"begin", "cbegin", "rbegin", "crbegin",
|
||||
"end", "cend", "rend", "crend"
|
||||
};
|
||||
|
||||
|
||||
// Add std:: in front of std classes, when using namespace std; was given
|
||||
void Tokenizer::simplifyNamespaceStd()
|
||||
{
|
||||
if (!isCPP())
|
||||
return;
|
||||
|
||||
const bool isCPP11 = mSettings->standards.cpp == Standards::CPP11;
|
||||
|
||||
std::set<std::string> userFunctions;
|
||||
|
||||
for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
|
||||
|
@ -9482,39 +9428,40 @@ void Tokenizer::simplifyNamespaceStd()
|
|||
if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
|
||||
skipEnumBody(&tok);
|
||||
}
|
||||
if (!Token::Match(tok->previous(), ".|::|namespace")) {
|
||||
if (Token::Match(tok, "%name% (")) {
|
||||
if (isFunctionHead(tok->next(), "{"))
|
||||
if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId())
|
||||
continue;
|
||||
if (Token::Match(tok->previous(), ".|::|namespace"))
|
||||
continue;
|
||||
if (Token::simpleMatch(tok->next(), "(")) {
|
||||
if (isFunctionHead(tok->next(), "{"))
|
||||
userFunctions.insert(tok->str());
|
||||
else if (isFunctionHead(tok->next(), ";")) {
|
||||
const Token *start = tok;
|
||||
while (Token::Match(start->previous(), "%type%|*|&"))
|
||||
start = start->previous();
|
||||
if (start != tok && start->isName() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
|
||||
userFunctions.insert(tok->str());
|
||||
else if (isFunctionHead(tok->next(), ";")) {
|
||||
const Token *start = tok;
|
||||
while (Token::Match(start->previous(), "%type%|*|&"))
|
||||
start = start->previous();
|
||||
if (start != tok && start->isName() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
|
||||
userFunctions.insert(tok->str());
|
||||
}
|
||||
if (userFunctions.find(tok->str()) == userFunctions.end() && stdFunctions.find(tok->str()) != stdFunctions.end())
|
||||
insert = true;
|
||||
} else if (Token::Match(tok, "%name% <") && stdTemplates.find(tok->str()) != stdTemplates.end())
|
||||
}
|
||||
if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings->library.matchArguments(tok, "std::" + tok->str()))
|
||||
insert = true;
|
||||
else if (tok->isName() && !tok->varId() && !Token::Match(tok->next(), "(|<") && stdTypes.find(tok->str()) != stdTypes.end())
|
||||
insert = true;
|
||||
}
|
||||
} else if (Token::simpleMatch(tok->next(), "<") &&
|
||||
(mSettings->library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true) || mSettings->library.detectSmartPointer(tok, /*withoutStd*/ true)))
|
||||
insert = true;
|
||||
else if (mSettings->library.hasAnyTypeCheck("std::" + tok->str()) ||
|
||||
mSettings->library.podtype("std::" + tok->str()) ||
|
||||
mSettings->library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true))
|
||||
insert = true;
|
||||
|
||||
if (insert) {
|
||||
tok->previous()->insertToken("std");
|
||||
tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
|
||||
tok->previous()->fileIndex(tok->fileIndex());
|
||||
tok->previous()->insertToken("::");
|
||||
} else if (isCPP11 && Token::Match(tok, "!!:: tr1 ::"))
|
||||
tok->next()->str("std");
|
||||
}
|
||||
}
|
||||
|
||||
for (Token* tok = list.front(); tok; tok = tok->next()) {
|
||||
if (isCPP11 && Token::simpleMatch(tok, "std :: tr1 ::"))
|
||||
Token::eraseTokens(tok, tok->tokAt(3));
|
||||
|
||||
else if (Token::simpleMatch(tok, "using namespace std ;")) {
|
||||
if (Token::simpleMatch(tok, "using namespace std ;")) {
|
||||
Token::eraseTokens(tok, tok->tokAt(4));
|
||||
tok->deleteThis();
|
||||
}
|
||||
|
|
|
@ -2063,6 +2063,18 @@ private:
|
|||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("using namespace std;\n" // #10971
|
||||
"struct S { int i = 3; };\n"
|
||||
"unique_ptr<S> g() {\n"
|
||||
" auto tp = make_unique<S>();\n"
|
||||
" return tp;\n"
|
||||
"}\n"
|
||||
"void f() {\n"
|
||||
" const S& s = *g();\n"
|
||||
" (void)s.i;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:9]: (error) Using reference to dangling temporary.\n", errout.str());
|
||||
}
|
||||
|
||||
void testglobalnamespace() {
|
||||
|
|
|
@ -1367,6 +1367,14 @@ private:
|
|||
" delete i;\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
|
||||
|
||||
check("using namespace std;\n" // #9708
|
||||
"void f() {\n"
|
||||
" int* i = new int;\n"
|
||||
" unique_ptr<int> x(i);\n"
|
||||
" delete i;\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:5]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
|
||||
}
|
||||
|
||||
void doublefree9() {
|
||||
|
|
|
@ -309,7 +309,7 @@ private:
|
|||
std::string tok_(const char* file, int line, const char code[], bool debugwarnings = false, cppcheck::Platform::Type type = cppcheck::Platform::Type::Native) {
|
||||
errout.str("");
|
||||
|
||||
const Settings settings1 = settingsBuilder(settings).debugwarnings(debugwarnings).platform(type).build();
|
||||
const Settings settings1 = settingsBuilder(settings).library("std.cfg").debugwarnings(debugwarnings).platform(type).build();
|
||||
Tokenizer tokenizer(&settings1, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
private:
|
||||
// If there are unused templates, keep those
|
||||
const Settings settings0 = settingsBuilder().library("qt.cfg").checkUnusedTemplates().build();
|
||||
const Settings settings1 = settingsBuilder().library("qt.cfg").checkUnusedTemplates().build();
|
||||
const Settings settings1 = settingsBuilder().library("qt.cfg").library("std.cfg").checkUnusedTemplates().build();
|
||||
const Settings settings2 = settingsBuilder().library("qt.cfg").checkUnusedTemplates().build();
|
||||
const Settings settings_windows = settingsBuilder().library("windows.cfg").checkUnusedTemplates().build();
|
||||
|
||||
|
@ -4606,7 +4606,7 @@ private:
|
|||
|
||||
code = "using namespace std;\n"
|
||||
"string<wchar_t> s;"; // That's obviously not std::string
|
||||
ASSERT_EQUALS("string < wchar_t > s ;", tokenizeAndStringify(code));
|
||||
TODO_ASSERT_EQUALS("string < wchar_t > s ;", "std :: string < wchar_t > s ;", tokenizeAndStringify(code));
|
||||
|
||||
code = "using namespace std;\n"
|
||||
"swap s;"; // That's obviously not std::swap
|
||||
|
@ -4616,15 +4616,6 @@ private:
|
|||
"std::string s;";
|
||||
ASSERT_EQUALS("std :: string s ;", tokenizeAndStringify(code));
|
||||
|
||||
code = "using namespace std;\n"
|
||||
"tr1::function <void(int)> f;";
|
||||
ASSERT_EQUALS("tr1 :: function < void ( int ) > f ;", tokenizeAndStringify(code, true, cppcheck::Platform::Type::Native, "test.cpp", Standards::CPP03));
|
||||
ASSERT_EQUALS("std :: function < void ( int ) > f ;", tokenizeAndStringify(code));
|
||||
|
||||
code = "std::tr1::function <void(int)> f;";
|
||||
ASSERT_EQUALS("std :: tr1 :: function < void ( int ) > f ;", tokenizeAndStringify(code, true, cppcheck::Platform::Type::Native, "test.cpp", Standards::CPP03));
|
||||
ASSERT_EQUALS("std :: function < void ( int ) > f ;", tokenizeAndStringify(code));
|
||||
|
||||
// #4042 (Do not add 'std ::' to variables)
|
||||
code = "using namespace std;\n"
|
||||
"const char * string = \"Hi\";";
|
||||
|
@ -4639,7 +4630,12 @@ private:
|
|||
"std :: cout << string << std :: endl ;\n"
|
||||
"return string ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
TODO_ASSERT_EQUALS(expected,
|
||||
"std :: string f ( const char * string ) {\n"
|
||||
"cout << string << endl ;\n"
|
||||
"return string ;\n"
|
||||
"}",
|
||||
tokenizeAndStringify(code));
|
||||
|
||||
code = "using namespace std;\n"
|
||||
"void f() {\n"
|
||||
|
@ -4694,6 +4690,27 @@ private:
|
|||
tokenizeAndStringify("using namespace std; enum E : int ; void foo ( ) { string s ; }"));
|
||||
|
||||
ASSERT_NO_THROW(tokenizeAndStringify("NS_BEGIN(IMAGEIO_2D_DICOM) using namespace std; NS_END")); // #11045
|
||||
|
||||
code = "using namespace std;\n"
|
||||
"void f(const unique_ptr<int>& p) {\n"
|
||||
" if (!p)\n"
|
||||
" throw runtime_error(\"abc\");\n"
|
||||
"}";
|
||||
expected = "void f ( const std :: unique_ptr < int > & p ) {\n"
|
||||
"if ( ! p ) {\n"
|
||||
"throw std :: runtime_error ( \"abc\" ) ; }\n"
|
||||
"}";
|
||||
TODO_ASSERT_EQUALS(expected,
|
||||
"void f ( const std :: unique_ptr < int > & p ) {\n"
|
||||
"if ( ! p ) {\n"
|
||||
"throw runtime_error ( \"abc\" ) ; }\n"
|
||||
"}",
|
||||
tokenizeAndStringify(code));
|
||||
|
||||
code = "using namespace std;\n" // #8454
|
||||
"void f() { string str = to_string(1); }\n";
|
||||
expected = "void f ( ) { std :: string str ; str = std :: to_string ( 1 ) ; }";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void microsoftMemory() {
|
||||
|
|
Loading…
Reference in New Issue