#6510 False positive performance warning for std::list::size(). Fix this and other similar false positives. Refactoring of Variable::isStlType(), use fail-safe std::set instead of plain array. Run astyle

This commit is contained in:
Alexander Mai 2015-05-17 20:02:41 +02:00
parent 20842fb1fc
commit f0bc300198
9 changed files with 284 additions and 215 deletions

View File

@ -1868,10 +1868,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
if (end->varId()) { if (end->varId()) {
const Variable *var = end->variable(); const Variable *var = end->variable();
// The container contains the STL types whose operator[] is not a const. // The container contains the STL types whose operator[] is not a const.
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_containers = make_container< std::set<std::string> >() << "map" << "unordered_map";
static const char* const stl_containers [] = {
"map", "unordered_map"
};
if (var && var->isStlType(stl_containers)) if (var && var->isStlType(stl_containers))
return false; return false;
} }

View File

@ -1522,16 +1522,12 @@ CheckIO::ArgumentInfo::~ArgumentInfo()
} }
} }
bool CheckIO::ArgumentInfo::isStdVectorOrString() bool CheckIO::ArgumentInfo::isStdVectorOrString()
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_vector = make_container< std::set<std::string> >() << "array" << "vector";
static const char* const stl_vector[] = { static const std::set<std::string> stl_string = make_container< std::set<std::string> >() << "string" << "u16string" << "u32string" << "wstring";
"array", "vector"
};
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_string[] = {
"string", "u16string", "u32string", "wstring"
};
if (variableInfo->isStlType(stl_vector)) { if (variableInfo->isStlType(stl_vector)) {
typeToken = variableInfo->typeStartToken()->tokAt(4); typeToken = variableInfo->typeStartToken()->tokAt(4);
@ -1586,19 +1582,15 @@ bool CheckIO::ArgumentInfo::isStdVectorOrString()
bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok) bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_container = make_container< std::set<std::string> >() <<
static const char* const stl_container[] = { "array" << "bitset" << "deque" << "forward_list" <<
"array", "bitset", "deque", "forward_list", "hash_map" << "hash_multimap" << "hash_set" <<
"hash_map", "hash_multimap", "hash_set", "list" << "map" << "multimap" << "multiset" <<
"list", "map", "multimap", "multiset", "priority_queue" << "queue" << "set" << "stack" <<
"priority_queue", "queue", "set", "stack", "unordered_map" << "unordered_multimap" << "unordered_multiset" << "unordered_set" << "vector"
"unordered_map", "unordered_multimap", "unordered_multiset", "unordered_set", ;
"vector" static const std::set<std::string> stl_string= make_container< std::set<std::string> >() <<
}; "string" << "u16string" << "u32string" << "wstring";
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_string[]= {
"string", "u16string", "u32string", "wstring"
};
if (tok && tok->variable()) { if (tok && tok->variable()) {
const Variable* variable = tok->variable(); const Variable* variable = tok->variable();

View File

@ -148,12 +148,10 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
*/ */
bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_stream = make_container< std::set<std::string> >() <<
static const char* const stl_stream [] = { "fstream" << "ifstream" << "iostream" << "istream" <<
"fstream", "ifstream", "iostream", "istream", "istringstream" << "ofstream" << "ostream" << "ostringstream" <<
"istringstream", "ofstream", "ostream", "ostringstream", "stringstream" << "wistringstream" << "wostringstream" << "wstringstream";
"stringstream", "wistringstream", "wostringstream", "wstringstream"
};
unknown = false; unknown = false;
@ -379,12 +377,9 @@ void CheckNullPointer::nullPointer()
void CheckNullPointer::nullConstantDereference() void CheckNullPointer::nullConstantDereference()
{ {
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
static const std::set<std::string> stl_stream = make_container< std::set<std::string> >() <<
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY "fstream" << "ifstream" << "iostream" << "istream" <<
static const char* const stl_stream[] = { "istringstream" << "stringstream" << "wistringstream" << "wstringstream";
"fstream", "ifstream", "iostream", "istream",
"istringstream", "stringstream", "wistringstream", "wstringstream"
};
const std::size_t functions = symbolDatabase->functionScopes.size(); const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) { for (std::size_t i = 0; i < functions; ++i) {

View File

@ -843,21 +843,12 @@ void CheckStl::if_findError(const Token *tok, bool str)
/** /**
* Is container.size() slow? * Is container.size() slow?
*/ */
static bool isContainerSizeSlow(const Token *tok) static bool isCpp03ContainerSizeSlow(const Token *tok)
{ {
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* stl_size_slow[] = {
"array", "bitset",
"forward_list", "hash_map", "hash_multimap", "hash_set",
"list", "map", "multimap", "multiset",
"priority_queue", "queue", "set", "stack", "unordered_map",
"unordered_multimap", "unordered_multiset", "unordered_set"
};
if (!tok) if (!tok)
return false; return false;
const Variable* var = tok->variable(); const Variable* var = tok->variable();
return var && var->isStlType(stl_size_slow); return var && var->isStlType("list");
} }
void CheckStl::size() void CheckStl::size()
@ -865,6 +856,9 @@ void CheckStl::size()
if (!_settings->isEnabled("performance")) if (!_settings->isEnabled("performance"))
return; return;
if (_settings->standards.cpp == Standards::CPP11)
return;
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size(); const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) { for (std::size_t i = 0; i < functions; ++i) {
@ -883,21 +877,21 @@ void CheckStl::size()
// check for comparison to zero // check for comparison to zero
if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, "==|<=|!=|> 0")) || if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, "==|<=|!=|> 0")) ||
(end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "0 ==|>=|!=|<"))) { (end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "0 ==|>=|!=|<"))) {
if (isContainerSizeSlow(tok1)) if (isCpp03ContainerSizeSlow(tok1))
sizeError(tok1); sizeError(tok1);
} }
// check for comparison to one // check for comparison to one
if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, ">=|< 1") && !end->tokAt(2)->isArithmeticalOp()) || if ((tok->previous() && !tok->previous()->isArithmeticalOp() && Token::Match(end, ">=|< 1") && !end->tokAt(2)->isArithmeticalOp()) ||
(end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "1 <=|>") && !tok->tokAt(-3)->isArithmeticalOp())) { (end->next() && !end->next()->isArithmeticalOp() && Token::Match(tok->tokAt(-2), "1 <=|>") && !tok->tokAt(-3)->isArithmeticalOp())) {
if (isContainerSizeSlow(tok1)) if (isCpp03ContainerSizeSlow(tok1))
sizeError(tok1); sizeError(tok1);
} }
// check for using as boolean expression // check for using as boolean expression
else if ((Token::Match(tok->tokAt(-2), "if|while (") && end->str() == ")") || else if ((Token::Match(tok->tokAt(-2), "if|while (") && end->str() == ")") ||
(tok->previous()->type() == Token::eLogicalOp && Token::Match(end, "&&|)|,|;|%oror%"))) { (tok->previous()->type() == Token::eLogicalOp && Token::Match(end, "&&|)|,|;|%oror%"))) {
if (isContainerSizeSlow(tok1)) if (isCpp03ContainerSizeSlow(tok1))
sizeError(tok1); sizeError(tok1);
} }
} }
@ -1046,14 +1040,10 @@ void CheckStl::string_c_str()
{ {
const bool printInconclusive = _settings->inconclusive; const bool printInconclusive = _settings->inconclusive;
const bool printPerformance = _settings->isEnabled("performance"); const bool printPerformance = _settings->isEnabled("performance");
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_string = make_container< std::set<std::string> >() <<
static const char* const stl_string[] = { "string" << "u16string" << "u32string" << "wstring" ;
"string", "u16string", "u32string", "wstring" static const std::set<std::string> stl_string_stream = make_container< std::set<std::string> >() <<
}; "istringstream" << "ostringstream" << "stringstream" << "wstringstream" ;
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY
static const char* const stl_string_stream[] = {
"istringstream", "ostringstream", "stringstream", "wstringstream"
};
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
@ -1357,17 +1347,13 @@ void CheckStl::uselessCalls()
if (!printPerformance && !printWarning) if (!printPerformance && !printWarning)
return; return;
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY static const std::set<std::string> stl_string = make_container< std::set<std::string> >() <<
static const char* const stl_string[] = { "string" << "u16string" << "u32string" << "wstring";
"string", "u16string", "u32string", "wstring" static const std::set<std::string> stl_containers_with_empty_and_clear = make_container< std::set<std::string> >() <<
}; "deque" << "forward_list" << "list" <<
// THIS ARRAY MUST BE ORDERED ALPHABETICALLY "map" << "multimap" << "multiset" << "set" << "string" <<
static const char* const stl_containers_with_empty_and_clear[] = { "unordered_map" << "unordered_multimap" << "unordered_multiset" <<
"deque", "forward_list", "list", "unordered_set" << "vector" << "wstring";
"map", "multimap", "multiset", "set", "string",
"unordered_map", "unordered_multimap", "unordered_multiset",
"unordered_set", "vector", "wstring"
};
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase(); const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size(); const std::size_t functions = symbolDatabase->functionScopes.size();
@ -1556,8 +1542,10 @@ void CheckStl::readingEmptyStlContainer()
std::set<unsigned int> empty_map; // empty std::map-like instances of STL containers std::set<unsigned int> empty_map; // empty std::map-like instances of STL containers
std::set<unsigned int> empty_nonmap; // empty non-std::map-like instances of STL containers std::set<unsigned int> empty_nonmap; // empty non-std::map-like instances of STL containers
static const char *MAP_STL_CONTAINERS[] = { "map", "multimap", "unordered_map", "unordered_multimap" }; static const std::set<std::string> MAP_STL_CONTAINERS = make_container< std::set<std::string> >() <<
static const char *NONMAP_STL_CONTAINERS[] = { "deque", "forward_list", "list", "multiset", "queue", "set", "stack", "string", "unordered_multiset", "unordered_set", "vector" }; "map" << "multimap" << "unordered_map" << "unordered_multimap" ;
static const std::set<std::string> NONMAP_STL_CONTAINERS = make_container< std::set<std::string> >() <<
"deque" << "forward_list" << "list" << "multiset" << "queue" << "set" << "stack" << "string" << "unordered_multiset" << "unordered_set" << "vector";
const std::list<Scope>& scopeList = _tokenizer->getSymbolDatabase()->scopeList; const std::list<Scope>& scopeList = _tokenizer->getSymbolDatabase()->scopeList;

View File

@ -488,12 +488,25 @@ public:
* ... * ...
* const char *str[] = {"string", "wstring"}; * const char *str[] = {"string", "wstring"};
* sVar->isStlType(str) == true * sVar->isStlType(str) == true
* @param stlTypes array of stl types in alphabetical order * @param stlTypes set of stl types
* @return true if it is an stl type and its type matches any of the types in 'stlTypes' * @return true if it is an stl type and its type matches any of the types in 'stlTypes'
*/ */
template <std::size_t array_length> bool isStlType(const std::string& stlType) const {
bool isStlType(const char* const(&stlTypes)[array_length]) const { return isStlType() && stlType==_start->strAt(2);
return isStlType() && std::binary_search(stlTypes, stlTypes + array_length, _start->strAt(2)); }
/**
* Checks if the variable is of any of the STL types passed as arguments ('std::')
* E.g.:
* std::string s;
* ...
* const std::set<std::string> str = make_container< std::set<std::string> >() << "string" << "wstring";
* sVar->isStlType(str) == true
* @param stlTypes set of stl types
* @return true if it is an stl type and its type matches any of the types in 'stlTypes'
*/
bool isStlType(const std::set<std::string>& stlTypes) const {
return isStlType() && stlTypes.find(_start->strAt(2))!=stlTypes.end();
} }
/** /**
@ -1003,5 +1016,23 @@ private:
/** list for missing types */ /** list for missing types */
std::list<Type> _blankTypes; std::list<Type> _blankTypes;
}; };
template < typename Cont >
class make_container {
public:
typedef make_container< Cont > my_type;
typedef typename Cont::value_type T;
my_type& operator<< (const T& val) {
data_.insert(data_.end(), val);
return *this;
}
operator Cont() const {
return data_;
}
private:
Cont data_;
};
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif // symboldatabaseH #endif // symboldatabaseH

View File

@ -9327,7 +9327,7 @@ void Tokenizer::simplifyKeyword()
//if (Token::Match(tok, ") override [{;]")) //if (Token::Match(tok, ") override [{;]"))
if (Token::Match(tok, ") const|override|final")) { if (Token::Match(tok, ") const|override|final")) {
Token* specifier = tok->tokAt(2); Token* specifier = tok->tokAt(2);
while(specifier && Token::Match(specifier, "const|override|final")) while (specifier && Token::Match(specifier, "const|override|final"))
specifier=specifier->next(); specifier=specifier->next();
if (specifier && Token::Match(specifier, "[{;]")) { if (specifier && Token::Match(specifier, "[{;]")) {
specifier=tok->next(); specifier=tok->next();

View File

@ -130,7 +130,7 @@ private:
TEST_CASE(readingEmptyStlContainer); TEST_CASE(readingEmptyStlContainer);
} }
void check(const char code[], const bool inconclusive=false) { void check(const char code[], const bool inconclusive=false, const Standards::cppstd_t cppstandard=Standards::CPP11) {
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");
@ -138,6 +138,7 @@ private:
settings.addEnabled("style"); settings.addEnabled("style");
settings.addEnabled("performance"); settings.addEnabled("performance");
settings.inconclusive = inconclusive; settings.inconclusive = inconclusive;
settings.standards.cpp = cppstandard;
// Tokenize.. // Tokenize..
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
@ -1651,106 +1652,148 @@ private:
void size1() { void size1() {
check("struct Fred {\n" const char* code = "struct Fred {\n"
" void foo();\n" " void foo();\n"
" std::list<int> x;\n" " std::list<int> x;\n"
"};\n" "};\n"
"void Fred::foo()\n" "void Fred::foo()\n"
"{\n" "{\n"
" if (x.size() == 0) {}\n" " if (x.size() == 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:7]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:7]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("std::list<int> x;\n" code = "std::list<int> x;\n"
"void f()\n" "void f()\n"
"{\n" "{\n"
" if (x.size() == 0) {}\n" " if (x.size() == 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size() == 0) {}\n" " if (x.size() == 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (0 == x.size()) {}\n" " if (0 == x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size() != 0) {}\n" " if (x.size() != 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (0 != x.size()) {}\n" " if (0 != x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size() > 0) {}\n" " if (x.size() > 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (0 < x.size()) {}\n" " if (0 < x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size() >= 1) {}\n" " if (x.size() >= 1) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size() < 1) {}\n" " if (x.size() < 1) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (1 <= x.size()) {}\n" " if (1 <= x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (1 > x.size()) {}\n" " if (1 > x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (x.size()) {}\n" " if (x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" if (!x.size()) {}\n" " if (!x.size()) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
@ -1759,19 +1802,25 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f()\n" code ="void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" fun(!x.size());\n" " fun(!x.size());\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f()\n" code = "void f()\n"
"{\n" "{\n"
" std::list<int> x;\n" " std::list<int> x;\n"
" fun(a && x.size());\n" " fun(a && x.size());\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
check("void f() {\n" // #4039 check("void f() {\n" // #4039
" std::list<int> x;\n" " std::list<int> x;\n"
@ -1793,7 +1842,7 @@ private:
} }
void size2() { void size2() {
check("struct Fred {\n" const char* code = "struct Fred {\n"
" std::list<int> x;\n" " std::list<int> x;\n"
"};\n" "};\n"
"struct Wilma {\n" "struct Wilma {\n"
@ -1803,12 +1852,15 @@ private:
"void Wilma::foo()\n" "void Wilma::foo()\n"
"{\n" "{\n"
" if (f.x.size() == 0) {}\n" " if (f.x.size() == 0) {}\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
} }
void size3() { void size3() {
check("namespace N {\n" const char* code = "namespace N {\n"
" class Zzz {\n" " class Zzz {\n"
" public:\n" " public:\n"
" std::list<int> x;\n" " std::list<int> x;\n"
@ -1818,10 +1870,11 @@ private:
"Zzz * zzz;\n" "Zzz * zzz;\n"
"int main() {\n" "int main() {\n"
" if (zzz->x.size() > 0) { }\n" " if (zzz->x.size() > 0) { }\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check("namespace N {\n" code = "namespace N {\n"
" class Zzz {\n" " class Zzz {\n"
" public:\n" " public:\n"
" std::list<int> x;\n" " std::list<int> x;\n"
@ -1831,8 +1884,11 @@ private:
"int main() {\n" "int main() {\n"
" Zzz * zzz;\n" " Zzz * zzz;\n"
" if (zzz->x.size() > 0) { }\n" " if (zzz->x.size() > 0) { }\n"
"}"); "}";
check(code, false, Standards::CPP03);
ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str()); ASSERT_EQUALS("[test.cpp:10]: (performance) Possible inefficient checking for 'x' emptiness.\n", errout.str());
check(code);
ASSERT_EQUALS("", errout.str());
} }
void size4() { // #2652 - don't warn about vector/deque void size4() { // #2652 - don't warn about vector/deque
@ -1845,6 +1901,11 @@ private:
" if (v.size() > 0U) {}\n" " if (v.size() > 0U) {}\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f(std::array<int,3> &a) {\n"
" if (a.size() > 0U) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
} }
void redundantCondition1() { void redundantCondition1() {

View File

@ -659,8 +659,10 @@ private:
bool result = si.isVariableDeclaration(list.front(), vartok, typetok); bool result = si.isVariableDeclaration(list.front(), vartok, typetok);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library); Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library);
const char* types[] = { "string", "wstring" }; static const std::set<std::string> types = make_container< std::set<std::string> >() <<
const char* no_types[] = { "set" }; "string" << "wstring" ;
static const std::set<std::string> no_types = make_container< std::set<std::string> >() <<
"set" ;
ASSERT_EQUALS(true, v.isStlType()); ASSERT_EQUALS(true, v.isStlType());
ASSERT_EQUALS(true, v.isStlType(types)); ASSERT_EQUALS(true, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlType(no_types)); ASSERT_EQUALS(false, v.isStlType(no_types));
@ -675,8 +677,10 @@ private:
bool result = si.isVariableDeclaration(list.front(), vartok, typetok); bool result = si.isVariableDeclaration(list.front(), vartok, typetok);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library); Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library);
const char* types[] = { "bitset", "set", "vector", "wstring" }; static const std::set<std::string> types = make_container< std::set<std::string> >() <<
const char* no_types[] = { "bitset", "map", "set" }; "bitset" << "set" << "vector" << "wstring" ;
static const std::set<std::string> no_types = make_container< std::set<std::string> >() <<
"bitset" << "map" << "set" ;
ASSERT_EQUALS(true, v.isStlType()); ASSERT_EQUALS(true, v.isStlType());
ASSERT_EQUALS(true, v.isStlType(types)); ASSERT_EQUALS(true, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlType(no_types)); ASSERT_EQUALS(false, v.isStlType(no_types));
@ -690,7 +694,8 @@ private:
bool result = si.isVariableDeclaration(list.front(), vartok, typetok); bool result = si.isVariableDeclaration(list.front(), vartok, typetok);
ASSERT_EQUALS(true, result); ASSERT_EQUALS(true, result);
Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library); Variable v(vartok, list.front(), list.back(), 0, Public, 0, 0, &settings.library);
const char* types[] = { "bitset", "set", "vector" }; static const std::set<std::string> types = make_container< std::set<std::string> >() <<
"bitset" << "set" << "vector" ;
ASSERT_EQUALS(false, v.isStlType()); ASSERT_EQUALS(false, v.isStlType());
ASSERT_EQUALS(false, v.isStlType(types)); ASSERT_EQUALS(false, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlStringType()); ASSERT_EQUALS(false, v.isStlStringType());