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 "checkstl.h"
2009-02-11 06:08:29 +01:00
# include "tokenize.h"
2009-03-18 22:40:38 +01:00
# include "token.h"
2009-02-10 20:40:21 +01:00
2009-07-25 00:36:15 +02:00
2009-02-10 20:40:21 +01:00
2009-03-19 21:20:08 +01:00
// Register this check class (by creating a static instance of it)
namespace
{
2009-03-20 17:15:51 +01:00
CheckStl instance ;
2009-03-19 21:20:08 +01:00
}
2009-03-19 19:24:13 +01:00
2009-03-20 20:09:44 +01:00
// Error message for bad iterator usage..
void CheckStl : : iteratorsError ( const Token * tok , const std : : string & container1 , const std : : string & container2 )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " iterators " , " Same iterator is used with both " + container1 + " and " + container2 ) ;
2009-03-20 20:09:44 +01:00
}
2009-05-03 07:37:39 +02:00
// Error message used when dereferencing an iterator that has been erased..
void CheckStl : : dereferenceErasedError ( const Token * tok , const std : : string & itername )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " eraseDereference " , " Dereferenced iterator ' " + itername + " ' has been erased " ) ;
2009-05-03 07:37:39 +02:00
}
2009-03-20 20:09:44 +01:00
2009-02-10 20:40:21 +01:00
void CheckStl : : iterators ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-07-28 20:05:00 +02:00
if ( ! Token : : Match ( tok , " %var% = %var% . begin ( ) ;|+ " ) )
continue ;
2009-02-10 21:01:39 +01:00
2009-07-28 20:05:00 +02:00
const unsigned int iteratorId ( tok - > varId ( ) ) ;
const unsigned int containerId ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
if ( iteratorId = = 0 | | containerId = = 0 )
continue ;
bool validIterator = true ;
2009-07-30 18:57:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 7 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-07-28 20:05:00 +02:00
{
if ( tok2 - > str ( ) = = " } " )
break ;
2009-07-30 18:49:04 +02:00
if ( Token : : Match ( tok2 , " %varid% != %var% . end ( ) " , iteratorId ) & & tok2 - > tokAt ( 2 ) - > varId ( ) ! = containerId )
2009-07-28 20:05:00 +02:00
{
2009-07-30 18:49:04 +02:00
iteratorsError ( tok2 , tok - > strAt ( 2 ) , tok2 - > strAt ( 2 ) ) ;
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > tokAt ( 6 ) ;
2009-07-28 20:05:00 +02:00
}
else if ( Token : : Match ( tok2 , " %var% . insert|erase ( %varid% " , iteratorId ) )
{
2009-09-01 18:49:17 +02:00
if ( tok2 - > varId ( ) ! = containerId & & tok2 - > tokAt ( 5 ) - > str ( ) ! = " . " )
2009-07-28 20:05:00 +02:00
iteratorsError ( tok2 , tok - > strAt ( 2 ) , tok2 - > str ( ) ) ;
else if ( tok2 - > strAt ( 2 ) = = std : : string ( " erase " ) )
validIterator = false ;
2009-07-30 18:57:58 +02:00
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-07-28 20:05:00 +02:00
}
2009-07-30 18:37:39 +02:00
else if ( ! validIterator & & Token : : Match ( tok2 , " * %varid% " , iteratorId ) )
2009-04-29 20:16:04 +02:00
{
2009-07-28 20:05:00 +02:00
dereferenceErasedError ( tok2 , tok2 - > strAt ( 1 ) ) ;
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > next ( ) ;
2009-04-29 20:16:04 +02:00
}
2009-07-30 19:49:38 +02:00
else if ( ! validIterator & & Token : : Match ( tok2 , " %varid% . %var% " , iteratorId ) )
{
dereferenceErasedError ( tok2 , tok2 - > strAt ( 0 ) ) ;
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
2009-07-30 19:49:38 +02:00
}
2009-02-10 21:01:39 +01:00
}
2009-02-10 20:40:21 +01:00
}
}
2009-02-10 20:56:00 +01:00
void CheckStl : : stlOutOfBounds ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( ! Token : : simpleMatch ( tok , " for ( " ) )
continue ;
2009-05-06 21:55:04 +02:00
unsigned int indent = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-02-10 20:56:00 +01:00
{
2009-05-06 21:55:04 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-02-10 20:56:00 +01:00
+ + indent ;
2009-05-06 21:55:04 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-02-10 20:56:00 +01:00
{
if ( indent = = 0 )
break ;
2009-05-06 21:55:04 +02:00
- - indent ;
2009-02-10 20:56:00 +01:00
}
2009-05-06 21:55:04 +02:00
if ( Token : : Match ( tok2 , " ; %var% <= %var% . size ( ) ; " ) )
2009-02-10 20:56:00 +01:00
{
2009-05-06 21:55:04 +02:00
indent = 0 ;
const std : : string num ( tok2 - > strAt ( 1 ) ) ;
const std : : string varname ( tok2 - > strAt ( 3 ) ) ;
for ( const Token * tok3 = tok2 - > tokAt ( 8 ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) = = " { " )
+ + indent ;
else if ( tok3 - > str ( ) = = " } " )
{
if ( indent = = 0 )
break ;
- - indent ;
}
else if ( tok3 - > str ( ) = = varname )
{
if ( Token : : simpleMatch ( tok3 - > next ( ) , " . size ( ) " ) )
break ;
else if ( Token : : simpleMatch ( tok3 - > next ( ) , ( " [ " + num + " ] " ) . c_str ( ) ) )
stlOutOfBoundsError ( tok3 , num , varname ) ;
}
}
break ;
2009-02-10 20:56:00 +01:00
}
}
}
2009-03-21 14:20:10 +01:00
}
2009-02-10 20:56:00 +01:00
2009-03-21 14:20:10 +01:00
// Error message for bad iterator usage..
void CheckStl : : stlOutOfBoundsError ( const Token * tok , const std : : string & num , const std : : string & var )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " stlOutOfBounds " , " When " + num + " == " + var + " .size(), " + var + " [ " + num + " ] is out of bounds " ) ;
2009-02-10 20:56:00 +01:00
}
2009-02-11 06:08:29 +01:00
void CheckStl : : erase ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-05-21 17:55:52 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) )
2009-02-11 06:08:29 +01:00
{
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) )
{
if ( Token : : Match ( tok2 , " %var% = %var% . begin ( ) ; %var% != %var% . end ( ) " ) & &
tok2 - > str ( ) = = tok2 - > tokAt ( 8 ) - > str ( ) & &
tok2 - > tokAt ( 2 ) - > str ( ) = = tok2 - > tokAt ( 10 ) - > str ( ) )
{
eraseCheckLoop ( tok2 ) ;
break ;
}
}
}
if ( Token : : Match ( tok , " while ( %var% != %var% . end ( ) " ) )
{
eraseCheckLoop ( tok - > tokAt ( 2 ) ) ;
}
}
}
void CheckStl : : eraseCheckLoop ( const Token * it )
{
const Token * tok = it ;
// Search for the start of the loop body..
int indentlevel = 1 ;
while ( indentlevel > 0 & & 0 ! = ( tok = tok - > next ( ) ) )
{
if ( tok - > str ( ) = = " ( " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " ) " )
- - indentlevel ;
}
if ( ! Token : : simpleMatch ( tok , " ) { " ) )
return ;
// Parse loop..
// Error if it contains "erase(it)" but neither "break;" nor "it="
indentlevel = 0 ;
const Token * tok2 = 0 ;
while ( 0 ! = ( tok = tok - > next ( ) ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
- - indentlevel ;
2009-04-10 13:27:36 +02:00
if ( indentlevel < = 0 )
2009-02-11 06:08:29 +01:00
break ;
}
2009-02-11 17:20:32 +01:00
else if ( Token : : Match ( tok , " break|return|goto " ) | | Token : : simpleMatch ( tok , ( it - > str ( ) + " = " ) . c_str ( ) ) )
2009-02-11 06:08:29 +01:00
{
tok2 = 0 ;
break ;
}
else if ( Token : : simpleMatch ( tok , ( " erase ( " + it - > str ( ) + " ) " ) . c_str ( ) ) )
tok2 = tok ;
}
// Write error message..
if ( tok2 )
2009-03-21 17:58:13 +01:00
eraseError ( tok2 ) ;
2009-02-11 06:08:29 +01:00
}
2009-03-21 17:58:13 +01:00
// Error message for bad iterator usage..
void CheckStl : : eraseError ( const Token * tok )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " erase " , " Dangerous usage of erase \n After erase has been used the iterator may be invalid so dereferencing it or comparing it with other iterator is invalid. " ) ;
2009-03-21 17:58:13 +01:00
}
2009-02-18 20:57:43 +01:00
void CheckStl : : pushback ( )
{
2009-04-28 21:18:02 +02:00
// Pointer can become invalid after push_back or push_front..
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : Match ( tok , " %var% = & %var% [ " ) )
{
const unsigned int pointerId ( tok - > varId ( ) ) ;
const unsigned int containerId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( pointerId = = 0 | | containerId = = 0 )
continue ;
int indent = 0 ;
bool invalidPointer = false ;
for ( const Token * tok2 = tok ; indent > = 0 & & tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " ( " )
+ + indent ;
else if ( tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " ) " )
{
if ( indent = = 0 & & Token : : simpleMatch ( tok2 , " ) { " ) )
tok2 = tok2 - > next ( ) ;
else
- - indent ;
}
// push_back on vector..
if ( Token : : Match ( tok2 , " %varid% . push_front|push_back " , containerId ) )
invalidPointer = true ;
// Using invalid pointer..
if ( invalidPointer & & tok2 - > varId ( ) = = pointerId )
{
2009-07-27 11:24:24 +02:00
if ( tok2 - > previous ( ) - > str ( ) = = " * " )
2009-04-28 21:18:02 +02:00
invalidPointerError ( tok2 , tok2 - > str ( ) ) ;
2009-07-27 11:24:24 +02:00
else if ( tok2 - > next ( ) - > str ( ) = = " . " )
2009-04-28 21:18:02 +02:00
invalidPointerError ( tok2 , tok2 - > str ( ) ) ;
break ;
}
}
}
}
// Iterator becomes invalid after push_back or push_front..
2009-02-18 20:57:43 +01:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-05-21 17:55:52 +02:00
if ( Token : : simpleMatch ( tok , " vector < " ) )
2009-02-18 20:57:43 +01:00
{
2009-09-27 09:59:19 +02:00
// if iterator declaration inside for() loop
bool iteratorDeclaredInsideLoop = false ;
if ( ( tok - > tokAt ( - 2 ) & & Token : : simpleMatch ( tok - > tokAt ( - 2 ) , " for ( " ) ) | |
( tok - > tokAt ( - 4 ) & & Token : : simpleMatch ( tok - > tokAt ( - 4 ) , " for ( std :: " ) ) )
{
iteratorDeclaredInsideLoop = true ;
}
2009-02-18 20:57:43 +01:00
while ( tok & & tok - > str ( ) ! = " > " )
tok = tok - > next ( ) ;
if ( ! tok )
break ;
if ( Token : : Match ( tok , " > :: iterator|const_iterator %var% =|; " ) )
{
2009-04-25 17:14:02 +02:00
const unsigned int iteratorid ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( iteratorid = = 0 )
continue ;
2009-09-27 09:59:19 +02:00
if ( iteratorDeclaredInsideLoop & & tok - > tokAt ( 4 ) - > str ( ) = = " = " )
{
// skip "> :: iterator|const_iterator"
tok = tok - > tokAt ( 3 ) ;
}
2009-02-18 20:57:43 +01:00
std : : string vectorname ;
int indent = 0 ;
bool invalidIterator = false ;
2009-07-13 15:51:35 +02:00
for ( const Token * tok2 = tok ; indent > = 0 & & tok2 ; tok2 = tok2 - > next ( ) )
2009-02-18 20:57:43 +01:00
{
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " ( " )
+ + indent ;
else if ( tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " ) " )
{
if ( indent = = 0 & & Token : : simpleMatch ( tok2 , " ) { " ) )
tok2 = tok2 - > next ( ) ;
else
- - indent ;
}
2009-07-14 12:40:47 +02:00
// Using push_back or push_front inside a loop..
2009-09-27 09:59:19 +02:00
if ( Token : : Match ( tok2 , " for ( " ) )
{
tok2 = tok2 - > tokAt ( 2 ) ;
}
2009-09-27 10:10:21 +02:00
if ( Token : : Match ( tok2 , " %varid% = %var% . begin ( ) ; %varid% != %var% . end ( ) ; ++| %varid% ++| ) { " , iteratorid ) )
2009-07-14 12:40:47 +02:00
{
2009-09-27 09:59:19 +02:00
const unsigned int vectorid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
2009-07-31 19:39:55 +02:00
if ( vectorid = = 0 )
continue ;
2009-07-14 12:40:47 +02:00
const Token * pushback = 0 ;
2009-09-26 11:49:09 +02:00
unsigned int indent3 = 0 ;
2009-09-27 09:59:19 +02:00
for ( const Token * tok3 = tok2 - > tokAt ( 20 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-07-14 12:40:47 +02:00
{
if ( tok3 - > str ( ) = = " { " )
+ + indent3 ;
else if ( tok3 - > str ( ) = = " } " )
{
2009-09-26 11:49:09 +02:00
if ( indent3 < = 1 )
2009-07-14 12:40:47 +02:00
break ;
- - indent3 ;
}
else if ( tok3 - > str ( ) = = " break " )
{
pushback = 0 ;
break ;
}
else if ( Token : : Match ( tok3 , " %varid% . push_front|push_back ( " , vectorid ) )
{
pushback = tok3 ;
}
}
if ( pushback )
2009-09-27 09:59:19 +02:00
pushbackError ( pushback , tok2 - > strAt ( 0 ) ) ;
2009-07-14 12:40:47 +02:00
}
2009-02-18 20:57:43 +01:00
// Assigning iterator..
2009-09-26 11:49:09 +02:00
if ( Token : : Match ( tok2 , " %varid% = " , iteratorid ) )
2009-02-18 20:57:43 +01:00
{
2009-09-26 11:49:09 +02:00
if ( Token : : Match ( tok2 - > tokAt ( 2 ) , " %var% . begin ( ) " ) )
vectorname = tok2 - > strAt ( 2 ) ;
else
vectorname = " " ;
2009-02-18 20:57:43 +01:00
invalidIterator = false ;
}
// push_back on vector..
if ( vectorname . size ( ) & & Token : : Match ( tok2 , ( vectorname + " . push_front|push_back " ) . c_str ( ) ) )
invalidIterator = true ;
// Using invalid iterator..
if ( invalidIterator )
{
2009-04-25 17:14:02 +02:00
if ( Token : : Match ( tok2 , " ++|--|*|+|-|(|, %varid% " , iteratorid ) )
pushbackError ( tok2 , tok2 - > strAt ( 1 ) ) ;
if ( Token : : Match ( tok2 , " %varid% ++|--|+|- " , iteratorid ) )
pushbackError ( tok2 , tok2 - > str ( ) ) ;
2009-02-18 20:57:43 +01:00
}
}
}
}
}
}
2009-03-21 17:58:13 +01:00
// Error message for bad iterator usage..
void CheckStl : : pushbackError ( const Token * tok , const std : : string & iterator_name )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " pushback " , " After push_back or push_front, the iterator ' " + iterator_name + " ' may be invalid " ) ;
2009-03-21 17:58:13 +01:00
}
2009-03-18 22:40:38 +01:00
2009-04-28 21:18:02 +02:00
// Error message for bad iterator usage..
void CheckStl : : invalidPointerError ( const Token * tok , const std : : string & pointer_name )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " pushback " , " Invalid pointer ' " + pointer_name + " ' after push_back / push_front " ) ;
2009-04-28 21:18:02 +02:00
}
2009-04-13 17:48:13 +02:00
void CheckStl : : stlBoundries ( )
{
2009-08-07 16:23:28 +02:00
// containers (not the vector)..
static const char STL_CONTAINER_LIST [ ] = " bitset|deque|list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set " ;
2009-04-13 17:48:13 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
2009-05-17 18:58:32 +02:00
// Declaring iterator..
2009-07-25 00:36:15 +02:00
const std : : string checkStr = ( std : : string ( STL_CONTAINER_LIST ) + " < " ) ;
2009-07-25 01:23:30 +02:00
if ( Token : : Match ( tok , checkStr . c_str ( ) ) )
2009-04-13 17:48:13 +02:00
{
2009-07-25 01:23:30 +02:00
const std : : string container_name ( tok - > strAt ( 0 ) ) ;
2009-05-17 18:58:32 +02:00
while ( tok & & tok - > str ( ) ! = " > " )
tok = tok - > next ( ) ;
if ( ! tok )
break ;
if ( Token : : Match ( tok , " > :: iterator|const_iterator %var% =|; " ) )
2009-04-13 17:48:13 +02:00
{
2009-05-17 18:58:32 +02:00
const unsigned int iteratorid ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
if ( iteratorid = = 0 )
continue ;
// Using "iterator < ..." is not allowed
unsigned int indentlevel = 0 ;
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-04-13 17:48:13 +02:00
{
2009-05-17 18:58:32 +02:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " )
{
if ( indentlevel = = 0 )
break ;
- - indentlevel ;
}
2009-08-08 21:07:33 +02:00
else if ( Token : : Match ( tok2 , " !!* %varid% < " , iteratorid ) )
2009-05-17 18:58:32 +02:00
{
2009-07-25 00:36:15 +02:00
stlBoundriesError ( tok2 , container_name ) ;
2009-05-17 18:58:32 +02:00
}
2009-04-13 17:48:13 +02:00
}
}
}
}
}
// Error message for bad boundry usage..
2009-07-25 00:36:15 +02:00
void CheckStl : : stlBoundriesError ( const Token * tok , const std : : string & container_name )
2009-04-13 17:48:13 +02:00
{
2009-07-25 00:36:15 +02:00
reportError ( tok , Severity : : error , " stlBoundries " , container_name + " range check should use != and not < since the order of the pointers isn't guaranteed " ) ;
2009-04-13 17:48:13 +02:00
}