2009-02-10 20:40:21 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-02-10 20:40:21 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-02-10 20:40:21 +01:00
*/
# include "../src/tokenize.h"
# include "../src/checkstl.h"
# include "testsuite.h"
# include <sstream>
extern std : : ostringstream errout ;
class TestStl : public TestFixture
{
public :
TestStl ( ) : TestFixture ( " TestStl " )
{ }
private :
void run ( )
{
TEST_CASE ( iterator1 ) ;
2009-02-10 21:01:39 +01:00
TEST_CASE ( iterator2 ) ;
2009-04-29 17:32:38 +02:00
TEST_CASE ( iterator3 ) ;
2009-09-01 18:49:17 +02:00
TEST_CASE ( iterator4 ) ;
2009-04-29 17:32:38 +02:00
2009-05-03 07:37:39 +02:00
TEST_CASE ( dereference ) ;
2009-07-30 19:49:38 +02:00
TEST_CASE ( dereference_member ) ;
2009-05-03 07:37:39 +02:00
2009-02-10 20:56:00 +01:00
TEST_CASE ( STLSize ) ;
TEST_CASE ( STLSizeNoErr ) ;
2009-02-11 06:08:29 +01:00
TEST_CASE ( erase ) ;
TEST_CASE ( eraseBreak ) ;
2009-02-11 17:20:32 +01:00
TEST_CASE ( eraseReturn ) ;
TEST_CASE ( eraseGoto ) ;
2009-02-11 06:08:29 +01:00
TEST_CASE ( eraseAssign ) ;
2009-05-02 20:39:51 +02:00
TEST_CASE ( eraseErase ) ;
2009-02-18 20:57:43 +01:00
TEST_CASE ( pushback1 ) ;
2009-04-25 16:32:37 +02:00
TEST_CASE ( pushback2 ) ;
TEST_CASE ( pushback3 ) ;
TEST_CASE ( pushback4 ) ;
2009-09-26 11:49:09 +02:00
TEST_CASE ( pushback5 ) ;
2009-09-27 09:59:19 +02:00
TEST_CASE ( pushback6 ) ;
2009-09-27 10:10:21 +02:00
TEST_CASE ( pushback7 ) ;
2009-04-25 16:32:37 +02:00
2009-05-02 20:49:58 +02:00
TEST_CASE ( insert1 ) ;
2009-03-05 22:22:00 +01:00
TEST_CASE ( invalidcode ) ;
2009-04-13 17:48:13 +02:00
TEST_CASE ( stlBoundries1 ) ;
2009-07-28 22:55:23 +02:00
TEST_CASE ( stlBoundries2 ) ;
2009-08-08 21:07:33 +02:00
TEST_CASE ( stlBoundries3 ) ;
2009-02-10 20:40:21 +01:00
}
2009-03-19 19:35:47 +01:00
void check ( const char code [ ] )
{
// Tokenize..
Tokenizer tokenizer ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
2009-04-25 17:14:02 +02:00
tokenizer . setVarId ( ) ;
2009-03-18 22:40:38 +01:00
2009-03-19 19:35:47 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2009-03-18 22:40:38 +01:00
2009-03-19 19:35:47 +01:00
// Check..
CheckStl checkStl ;
2009-03-21 14:02:58 +01:00
checkStl . runSimplifiedChecks ( & tokenizer , ( const Settings * ) 0 , this ) ;
2009-03-19 19:35:47 +01:00
}
void iterator1 ( )
{
2009-04-29 20:16:04 +02:00
check ( " void f() \n "
2009-03-19 19:35:47 +01:00
" { \n "
2009-04-29 20:16:04 +02:00
" list<int> l1; \n "
" list<int> l2; \n "
" for (list<int>::iterator it = l1.begin(); it != l2.end(); ++it) \n "
2009-03-19 19:35:47 +01:00
" { } \n "
" } \n " ) ;
2009-04-29 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) Same iterator is used with both l1 and l2 \n " , errout . str ( ) ) ;
2009-03-19 19:35:47 +01:00
}
void iterator2 ( )
{
check ( " void foo() \n "
" { \n "
2009-04-29 20:16:04 +02:00
" list<int> l1; \n "
" list<int> l2; \n "
" list<int>::iterator it = l1.begin(); \n "
" while (it != l2.end()) \n "
2009-03-19 19:35:47 +01:00
" { \n "
" ++it; \n "
" } \n "
" } \n " ) ;
2009-04-29 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) Same iterator is used with both l1 and l2 \n " , errout . str ( ) ) ;
2009-03-19 19:35:47 +01:00
}
2009-02-10 20:56:00 +01:00
2009-04-29 17:32:38 +02:00
void iterator3 ( )
{
check ( " void foo() \n "
" { \n "
2009-04-29 20:16:04 +02:00
" list<int> l1; \n "
" list<int> l2; \n "
" list<int>::iterator it = l1.begin(); \n "
" l2.insert(it, 0); \n "
2009-04-29 17:32:38 +02:00
" } \n " ) ;
2009-04-29 20:16:04 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) Same iterator is used with both l1 and l2 \n " , errout . str ( ) ) ;
2009-04-29 17:32:38 +02:00
}
2009-09-01 18:49:17 +02:00
void iterator4 ( )
{
check ( " void foo(std::vector<std::string> &test) \n "
" { \n "
" std::set<int> result; \n "
" for (std::vector<std::string>::const_iterator cit = test.begin(); \n "
" cit != test.end(); \n "
" ++cit) \n "
" { \n "
" result.insert(cit->size()); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-02-10 20:56:00 +01:00
2009-05-03 07:37:39 +02:00
// Dereferencing invalid pointer
void dereference ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int> ints; "
" std::vector<int>::iterator iter; \n "
" iter = ints.begin() + 2; \n "
" ints.erase(iter); \n "
" std::cout << (*iter) << std::endl; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Dereferenced iterator 'iter' has been erased \n " , errout . str ( ) ) ;
}
2009-07-30 19:49:38 +02:00
void dereference_member ( )
{
check ( " void f() \n "
" { \n "
" std::map<int, int> ints; "
" std::map<int, int>::iterator iter; \n "
" iter = ints.begin(); \n "
" ints.erase(iter); \n "
" std::cout << iter->first << std::endl; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:6]: (error) Dereferenced iterator 'iter' has been erased \n " , errout . str ( ) ) ;
}
2009-05-03 07:37:39 +02:00
2009-03-19 19:35:47 +01:00
void STLSize ( )
{
check ( " void foo() \n "
" { \n "
" std::vector<int> foo; \n "
" for (unsigned int ii = 0; ii <= foo.size(); ++ii) \n "
" { \n "
" foo[ii] = 0; \n "
" } \n "
" } \n " ) ;
2009-05-31 21:48:55 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (error) When ii==foo.size(), foo[ii] is out of bounds \n " , errout . str ( ) ) ;
2009-10-07 22:38:21 +02:00
check ( " void foo() \n "
" { \n "
" std::vector<int> foo; \n "
" foo.push_back(1); \n "
" for (unsigned int ii = 0; ii <= foo.size(); ++ii) \n "
" { \n "
" } \n "
" int ii = 0; \n "
" foo[ii] = 0; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-03-19 19:35:47 +01:00
}
void STLSizeNoErr ( )
{
2009-02-10 20:56:00 +01:00
{
check ( " void foo() \n "
" { \n "
2009-03-19 19:35:47 +01:00
" std::vector<int> foo; \n "
" for (unsigned int ii = 0; ii < foo.size(); ++ii) \n "
" { \n "
" foo[ii] = 0; \n "
" } \n "
2009-02-10 20:56:00 +01:00
" } \n " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-02-10 20:56:00 +01:00
}
{
check ( " void foo() \n "
" { \n "
2009-03-19 19:35:47 +01:00
" std::vector<int> foo; \n "
" for (unsigned int ii = 0; ii <= foo.size(); ++ii) \n "
2009-02-10 20:56:00 +01:00
" { \n "
" } \n "
" } \n " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-02-10 20:56:00 +01:00
}
2009-03-17 18:54:50 +01:00
{
check ( " void foo() \n "
" { \n "
" std::vector<int> foo; \n "
" for (unsigned int ii = 0; ii <= foo.size(); ++ii) \n "
" { \n "
2009-03-19 19:35:47 +01:00
" if (ii == foo.size()) \n "
" { \n "
" } \n "
" else \n "
" { \n "
" foo[ii] = 0; \n "
" } \n "
2009-03-17 18:54:50 +01:00
" } \n "
" } \n " ) ;
2009-06-05 02:39:36 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-03-18 22:40:38 +01:00
}
2009-03-19 19:35:47 +01:00
}
2009-02-11 06:08:29 +01:00
2009-03-19 19:35:47 +01:00
void erase ( )
{
2009-04-10 13:27:36 +02:00
{
check ( " void f() \n "
" { \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5]: (error) Dangerous usage of erase \n " , errout . str ( ) ) ;
}
{
check ( " for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" } \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Dangerous usage of erase \n [test.cpp:7]: (error) Dangerous usage of erase \n " , errout . str ( ) ) ;
}
2009-03-19 19:35:47 +01:00
}
2009-02-11 17:20:32 +01:00
2009-03-19 19:35:47 +01:00
void eraseBreak ( )
{
check ( " void f() \n "
" { \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" break; \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-03-18 22:40:38 +01:00
2009-03-19 19:35:47 +01:00
void eraseReturn ( )
{
check ( " void f() \n "
" { \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" return; \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-03-18 22:40:38 +01:00
2009-03-19 19:35:47 +01:00
void eraseGoto ( )
{
check ( " void f() \n "
" { \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" goto abc; \n "
" } \n "
" bar: \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-02-11 06:08:29 +01:00
2009-03-19 19:35:47 +01:00
void eraseAssign ( )
{
check ( " void f() \n "
" { \n "
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.erase(it); \n "
" it = foo.begin(); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-02-11 06:08:29 +01:00
2009-05-02 20:39:51 +02:00
void eraseErase ( )
{
check ( " void f(std::vector<ints> &ints) \n "
" { \n "
" std::vector<int>::iterator iter; \n "
" iter = ints.begin() + 2; \n "
" ints.erase(iter); \n "
" ints.erase(iter); \n "
" } \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:6]: (error) Erasing invalid iterator \n " , errout . str ( ) ) ;
}
2009-02-18 20:57:43 +01:00
2009-03-19 19:35:47 +01:00
void pushback1 ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int>::const_iterator it = foo.begin(); \n "
" foo.push_back(123); \n "
" *it; \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:5]: (error) After push_back or push_front, the iterator 'it' may be invalid \n " , errout . str ( ) ) ;
}
2009-03-18 22:40:38 +01:00
2009-04-25 16:32:37 +02:00
void pushback2 ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int>::const_iterator it = foo.begin(); \n "
" foo.push_back(123); \n "
" { \n "
" int *it = &foo[0]; \n "
" *it = 456; \n "
" } \n "
" } \n " ) ;
2009-04-25 17:14:02 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-04-25 16:32:37 +02:00
}
void pushback3 ( )
{
check ( " void f() \n "
" { \n "
2009-07-18 12:06:51 +02:00
" std::vector<int> foo; \n "
" foo.push_back(10); \n "
" std::vector<int>::iterator it; \n "
2009-04-25 16:32:37 +02:00
" for (it = foo.begin(); it != foo.end(); ++it) \n "
" { \n "
" foo.push_back(123); \n "
" } \n "
" } \n " ) ;
2009-07-18 12:06:51 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) After push_back or push_front, the iterator 'it' may be invalid \n " , errout . str ( ) ) ;
2009-04-25 16:32:37 +02:00
}
void pushback4 ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int> ints; \n "
" ints.push_back(1); \n "
" int *first = &ints[0]; \n "
" ints.push_back(2); \n "
" *first; \n "
" } \n " ) ;
2009-04-28 21:18:02 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Invalid pointer 'first' after push_back / push_front \n " , errout . str ( ) ) ;
2009-04-25 16:32:37 +02:00
}
2009-09-26 11:49:09 +02:00
void pushback5 ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int>::const_iterator i; \n "
" \n "
" for (i=v.begin(); i!=v.end(); ++i) \n "
" { \n "
" } \n "
" \n "
" for (i=rhs.v.begin(); i!=rhs.v.end(); ++i) \n "
" { \n "
" v.push_back(*i); \n "
" } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-04-25 16:32:37 +02:00
2009-09-27 09:59:19 +02:00
void pushback6 ( )
{
// ticket #735
check ( " void f() \n "
" { \n "
" vector<int> v; \n "
" vector.push_back(1); \n "
" vector.push_back(2); \n "
" for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) \n "
" { \n "
" if (*it == 1) \n "
" v.push_back(10); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:9]: (error) After push_back or push_front, the iterator 'it' may be invalid \n " , errout . str ( ) ) ;
check ( " void f() \n "
" { \n "
" std::vector<int> v; \n "
" vector.push_back(1); \n "
" vector.push_back(2); \n "
" for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) \n "
" { \n "
" if (*it == 1) \n "
" v.push_back(10); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:9]: (error) After push_back or push_front, the iterator 'it' may be invalid \n " , errout . str ( ) ) ;
}
2009-04-25 16:32:37 +02:00
2009-09-27 10:10:21 +02:00
void pushback7 ( )
{
check ( " void f() \n "
" { \n "
" std::vector<int> foo; \n "
" foo.push_back(10); \n "
" std::vector<int>::iterator it; \n "
" for (it = foo.begin(); it != foo.end(); it++) \n "
" { \n "
" foo.push_back(123); \n "
" } \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:8]: (error) After push_back or push_front, the iterator 'it' may be invalid \n " , errout . str ( ) ) ;
}
2009-05-02 20:49:58 +02:00
void insert1 ( )
{
check ( " void f(std::vector<int> &ints) \n "
" { \n "
" std::vector<int>::iterator iter = ints.begin() + 5; \n "
" ints.insert(ints.begin(), 1); \n "
" ++iter; \n "
" } \n " ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:7]: (error) Invalid iterator 'iter' after insert \n " , errout . str ( ) ) ;
}
2009-03-19 19:35:47 +01:00
void invalidcode ( )
{
2009-05-11 21:52:04 +02:00
errout . str ( " " ) ;
2009-05-07 22:17:29 +02:00
const std : : string src = " void f() \n "
" { \n "
" for ( \n "
" } \n " ;
2009-07-13 19:11:31 +02:00
Tokenizer tokenizer ( 0 , this ) ;
2009-05-07 22:17:29 +02:00
std : : istringstream istr ( src ) ;
ASSERT_EQUALS ( false , tokenizer . tokenize ( istr , " test.cpp " ) ) ;
2009-05-11 21:52:04 +02:00
ASSERT_EQUALS ( " [test.cpp:1]: (error) Invalid number of character ((). Can't process file. \n " , errout . str ( ) ) ;
2009-03-19 19:35:47 +01:00
}
2009-04-13 17:48:13 +02:00
void stlBoundries1 ( )
{
2009-08-07 16:23:28 +02:00
const int STL_CONTAINER_LIST = 9 ;
2009-07-25 00:36:15 +02:00
const std : : string stlCont [ STL_CONTAINER_LIST ] =
2009-08-07 16:23:28 +02:00
{ " deque " , " list " , " set " , " multiset " , " map " ,
2009-07-25 01:23:30 +02:00
" multimap " , " hash_map " , " hash_multimap " , " hash_set "
} ;
2009-05-17 18:58:32 +02:00
2009-07-25 01:23:30 +02:00
for ( int i = 0 ; i < STL_CONTAINER_LIST ; + + i )
2009-07-25 00:36:15 +02:00
{
2009-07-25 01:23:30 +02:00
const std : : string checkStr ( " void f() \n "
" { \n "
" std:: " + stlCont [ i ] + " <int>::iterator it; \n "
" for (it = ab.begin(); it < ab.end(); ++it) \n "
" ; \n "
" } \n " ) ;
check ( checkStr . c_str ( ) ) ;
2009-07-25 00:36:15 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (error) " + stlCont [ i ] + " range check should use != and not < since the order of the pointers isn't guaranteed \n " , errout . str ( ) ) ;
}
2009-04-13 17:48:13 +02:00
}
2009-07-28 22:55:23 +02:00
void stlBoundries2 ( )
{
const std : : string checkStr ( " void f() \n "
" { \n "
" std::vector<std::string> files; \n "
" std::vector<std::string>::const_iterator it; \n "
" for (it = files.begin(); it < files.end(); it++) { } \n "
" for (it = files.begin(); it < files.end(); it++) { }; \n "
" } \n " ) ;
check ( checkStr . c_str ( ) ) ;
2009-08-07 16:23:28 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-28 22:55:23 +02:00
}
2009-07-25 00:36:15 +02:00
2009-08-08 21:07:33 +02:00
void stlBoundries3 ( )
{
const std : : string checkStr ( " void f() \n "
" { \n "
" set<int> files; \n "
" set<int>::const_iterator current; \n "
" for (current = files.begin(); current != files.end(); ++current) \n "
" { \n "
" assert(*current < 100) \n "
" } \n "
" } \n " ) ;
check ( checkStr . c_str ( ) ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-02-10 20:40:21 +01:00
} ;
REGISTER_TEST ( TestStl )