2009-02-10 20:40:21 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2010-04-13 21:23:17 +02:00
* Copyright ( C ) 2007 - 2010 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-03-18 22:40:38 +01:00
# include "token.h"
2010-10-05 20:54:13 +02:00
# include "executionpath.h"
2010-10-10 10:52:41 +02:00
# include <sstream>
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..
2010-04-17 13:37:04 +02:00
void CheckStl : : invalidIteratorError ( const Token * tok , const std : : string & iteratorName )
{
2010-05-13 22:14:29 +02:00
reportError ( tok , Severity : : error , " invalidIterator1 " , " Invalid iterator: " + iteratorName ) ;
2010-04-17 13:37:04 +02:00
}
2009-03-20 20:09:44 +01:00
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 ( )
{
2010-12-30 22:36:25 +01:00
// Using same iterator against different containers.
// for (it = foo.begin(); it != bar.end(); ++it)
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-02-10 20:40:21 +01:00
{
2010-12-30 22:36:25 +01:00
// Locate an iterator..
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " %var% = %var% . begin ( ) ;|+ " ) )
2009-07-28 20:05:00 +02:00
continue ;
2009-02-10 21:01:39 +01:00
2010-12-30 22:36:25 +01:00
// Get variable ids for both the iterator and container
2009-07-28 20:05:00 +02:00
const unsigned int iteratorId ( tok - > varId ( ) ) ;
const unsigned int containerId ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( iteratorId = = 0 | | containerId = = 0 )
2009-07-28 20:05:00 +02:00
continue ;
2010-12-30 22:36:25 +01:00
// the validIterator flag says if the iterator has a valid value or not
2009-07-28 20:05:00 +02:00
bool validIterator = true ;
2010-12-30 22:36:25 +01:00
// counter for { and }
2010-05-15 20:00:41 +02:00
unsigned int indent = 0 ;
2010-12-30 22:36:25 +01:00
// Scan through the rest of the code and see if the iterator is
// used against other containers.
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 7 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-07-28 20:05:00 +02:00
{
2010-12-30 22:36:25 +01:00
// If a { is found then count it and continue
2010-05-15 20:00:41 +02:00
if ( tok2 - > str ( ) = = " { " & & + + indent )
continue ;
2010-12-30 22:36:25 +01:00
// If a } is found then count it. break if indentlevel becomes 0.
2010-05-15 20:00:41 +02:00
if ( tok2 - > str ( ) = = " } " & & - - indent = = 0 )
2009-07-28 20:05:00 +02:00
break ;
2009-07-30 18:49:04 +02:00
2010-12-30 22:36:25 +01:00
// Is iterator compared against different container?
2010-04-02 07:30:58 +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
}
2010-12-30 22:36:25 +01:00
// Is the iterator used in a insert/erase operation?
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %var% . insert|erase ( %varid% )|, " , iteratorId ) )
2009-07-28 20:05:00 +02:00
{
2010-12-30 22:36:25 +01:00
// It is bad to insert/erase an invalid iterator
2010-04-17 13:37:04 +02:00
if ( ! validIterator )
invalidIteratorError ( tok2 , tok2 - > strAt ( 4 ) ) ;
2010-12-30 22:36:25 +01:00
// If insert/erase is used on different container then
// report an error
2010-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) ! = containerId & & tok2 - > tokAt ( 5 ) - > str ( ) ! = " . " )
2010-04-10 10:22:34 +02:00
{
// skip error message if container is a set..
if ( tok2 - > varId ( ) > 0 )
{
const Token * decltok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok2 - > varId ( ) ) ;
while ( decltok & & ! Token : : Match ( decltok , " [;{},(] " ) )
decltok = decltok - > previous ( ) ;
if ( Token : : Match ( decltok , " %any% const| std :: set " ) )
continue ; // No warning
}
// Show error message, mismatching iterator is used.
2009-07-28 20:05:00 +02:00
iteratorsError ( tok2 , tok - > strAt ( 2 ) , tok2 - > str ( ) ) ;
2010-04-10 10:22:34 +02:00
}
2010-12-30 22:36:25 +01:00
// invalidate the iterator if it is erased
2010-04-02 07:30:58 +02:00
else if ( tok2 - > strAt ( 2 ) = = std : : string ( " erase " ) )
2009-07-28 20:05:00 +02:00
validIterator = false ;
2009-07-30 18:57:58 +02:00
2010-12-30 22:36:25 +01:00
// skip the operation
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-07-28 20:05:00 +02:00
}
2010-12-30 22:36:25 +01:00
// it = foo.erase(..
// taking the result of an erase is ok
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok2 , " %varid% = %var% . erase ( " , iteratorId ) )
2009-11-10 17:20:20 +01:00
{
2010-12-30 22:36:25 +01:00
// the returned iterator is valid
2009-11-10 17:20:20 +01:00
validIterator = true ;
2010-12-30 22:36:25 +01:00
// skip the operation
2009-11-10 17:20:20 +01:00
tok2 = tok2 - > tokAt ( 5 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-11-10 17:20:20 +01:00
break ;
}
2010-12-30 22:36:25 +01:00
// Reassign the iterator
2010-08-17 18:56:11 +02:00
else if ( Token : : Match ( tok2 , " %varid% = %var% ; " , iteratorId ) )
{
2010-12-30 22:36:25 +01:00
// Assume that the iterator becomes valid.
2010-12-30 22:41:22 +01:00
// TODO: add checking that checks if the iterator becomes valid or not
2010-08-17 18:56:11 +02:00
validIterator = true ;
2010-12-30 22:36:25 +01:00
// skip ahead
2010-08-17 18:56:11 +02:00
tok2 = tok2 - > tokAt ( 2 ) ;
}
2010-12-30 22:36:25 +01:00
// Dereferencing invalid iterator?
2010-04-02 07:30:58 +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
}
2010-04-02 07:30:58 +02:00
else if ( ! validIterator & & Token : : Match ( tok2 , " %varid% . %var% " , iteratorId ) )
2009-07-30 19:49:38 +02:00
{
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
}
2010-05-15 19:46:42 +02:00
else if ( Token : : Match ( tok2 , " %var% . erase ( * %varid% " , iteratorId ) & & tok2 - > varId ( ) = = containerId )
{
2010-12-24 10:33:48 +01:00
// eraseByValueError(tok2, tok2->strAt(0), tok2->strAt(5));
2010-05-15 19:46:42 +02:00
}
2010-12-30 22:36:25 +01:00
// bailout handling. Assume that the iterator becomes valid if we see return/break.
// TODO: better handling
2010-07-09 10:50:24 +02:00
else if ( Token : : Match ( tok2 , " return|break ; " ) )
{
validIterator = true ;
}
2010-12-30 22:36:25 +01:00
// bailout handling. Assume that the iterator becomes valid if we see else.
// TODO: better handling
2010-09-18 16:46:38 +02:00
else if ( tok2 - > str ( ) = = " else " )
{
validIterator = true ;
}
2009-02-10 21:01:39 +01:00
}
2009-02-10 20:40:21 +01:00
}
}
2009-02-10 20:56:00 +01:00
2009-10-18 18:42:01 +02:00
// Error message for bad iterator usage..
void CheckStl : : mismatchingContainersError ( const Token * tok )
{
reportError ( tok , Severity : : error , " mismatchingContainers " , " mismatching containers " ) ;
}
void CheckStl : : mismatchingContainers ( )
{
2010-12-30 22:36:25 +01:00
// Check if different containers are used in various calls of standard functions
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-10-18 18:42:01 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) ! = " std " )
2009-10-18 18:42:01 +02:00
continue ;
2010-12-30 22:41:22 +01:00
// TODO: If iterator variables are used instead then there are false negatives.
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " std :: find|find_if|count|transform|replace|replace_if|sort ( %var% . begin|rbegin ( ) , %var% . end|rend ( ) , " ) )
2009-10-18 18:42:01 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( 4 ) - > str ( ) ! = tok - > tokAt ( 10 ) - > str ( ) )
2009-10-18 18:42:01 +02:00
{
mismatchingContainersError ( tok ) ;
}
}
}
}
2009-02-10 20:56:00 +01:00
void CheckStl : : stlOutOfBounds ( )
{
2010-10-15 18:21:53 +02:00
// Scan through all tokens..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-02-10 20:56:00 +01:00
{
2010-10-15 18:21:53 +02:00
// only interested in "for" loops
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok , " for ( " ) )
2009-02-10 20:56:00 +01:00
continue ;
2010-10-15 18:21:53 +02:00
// check if the for loop condition is wrong
2009-05-06 21:55:04 +02:00
unsigned int indent = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-02-10 20:56:00 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " ( " )
2009-02-10 20:56:00 +01:00
+ + indent ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " ) " )
2009-02-10 20:56:00 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent = = 0 )
2009-02-10 20:56:00 +01:00
break ;
2009-05-06 21:55:04 +02:00
- - indent ;
2009-02-10 20:56:00 +01:00
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ; %var% <= %var% . size ( ) ; " ) )
2009-02-10 20:56:00 +01:00
{
2009-10-07 22:38:21 +02:00
unsigned int indent2 = 0 ;
2009-10-07 22:53:16 +02:00
unsigned int numId = tok2 - > tokAt ( 1 ) - > varId ( ) ;
2009-10-07 22:49:06 +02:00
unsigned int varId = tok2 - > tokAt ( 3 ) - > varId ( ) ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok2 - > tokAt ( 8 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-05-06 21:55:04 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2009-10-07 22:38:21 +02:00
+ + indent2 ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2009-05-06 21:55:04 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indent2 < = 1 )
2009-05-06 21:55:04 +02:00
break ;
2009-10-07 22:38:21 +02:00
- - indent2 ;
2009-05-06 21:55:04 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( tok3 - > varId ( ) = = varId )
2009-05-06 21:55:04 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok3 - > next ( ) , " . size ( ) " ) )
2009-05-06 21:55:04 +02:00
break ;
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 - > next ( ) , " [ %varid% ] " , numId ) )
2009-10-07 22:53:16 +02:00
stlOutOfBoundsError ( tok3 , tok3 - > tokAt ( 2 ) - > str ( ) , tok3 - > str ( ) ) ;
2009-05-06 21:55:04 +02:00
}
}
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
2010-10-05 20:54:13 +02:00
/**
* @ brief % Check for invalid iterator usage after erase / insert / etc
*/
class EraseCheckLoop : public ExecutionPath
{
public :
static void checkScope ( CheckStl * checkStl , 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 ;
EraseCheckLoop c ( checkStl , it - > varId ( ) ) ;
std : : list < ExecutionPath * > checks ;
checks . push_back ( c . copy ( ) ) ;
ExecutionPath : : checkScope ( tok - > tokAt ( 2 ) , checks ) ;
c . end ( checks , tok - > link ( ) ) ;
while ( ! checks . empty ( ) )
{
delete checks . back ( ) ;
checks . pop_back ( ) ;
}
}
private :
/** Startup constructor */
EraseCheckLoop ( Check * o , unsigned int varid )
: ExecutionPath ( o , varid ) , eraseToken ( 0 )
{
}
/** @brief token where iterator is erased (non-zero => the iterator is invalid) */
const Token * eraseToken ;
/** @brief Copy this check. Called from the ExecutionPath baseclass. */
ExecutionPath * copy ( )
{
return new EraseCheckLoop ( * this ) ;
}
/** @brief is another execution path equal? */
bool is_equal ( const ExecutionPath * e ) const
{
const EraseCheckLoop * c = static_cast < const EraseCheckLoop * > ( e ) ;
return ( eraseToken = = c - > eraseToken ) ;
}
/** @brief no implementation => compiler error if used by accident */
void operator = ( const EraseCheckLoop & ) ;
/** @brief parse tokens */
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const
{
2010-10-15 18:21:53 +02:00
// bail out if there are assignments. We don't check the assignments properly.
2010-10-05 20:54:13 +02:00
if ( Token : : Match ( & tok , " [;{}] %var% = " ) | | Token : : Match ( & tok , " = %var% ; " ) )
{
ExecutionPath : : bailOutVar ( checks , tok . next ( ) - > varId ( ) ) ;
}
2010-10-15 18:21:53 +02:00
// the loop stops here. Bail out all execution checks that reach
// this statement
2010-10-05 20:54:13 +02:00
if ( Token : : Match ( & tok , " [;{}] break ; " ) )
{
ExecutionPath : : bailOut ( checks ) ;
}
2010-10-15 18:21:53 +02:00
// erasing iterator => it is invalidated
2010-10-05 20:54:13 +02:00
if ( Token : : Match ( & tok , " erase ( ++|--| %var% ) " ) )
{
2010-10-15 18:21:53 +02:00
// check if there is a "it = ints.erase(it);" pattern. if so
// the it is not invalidated.
2010-10-05 20:54:13 +02:00
const Token * token = & tok ;
while ( NULL ! = ( token = token ? token - > previous ( ) : 0 ) )
{
if ( Token : : Match ( token , " [;{}] " ) )
break ;
else if ( token - > str ( ) = = " = " )
token = 0 ;
}
2010-10-15 18:21:53 +02:00
// the it is invalidated by the erase..
2010-10-05 20:54:13 +02:00
if ( token )
{
2010-10-15 18:21:53 +02:00
// get variable id for the iterator
2010-10-05 20:54:13 +02:00
unsigned int iteratorId = 0 ;
if ( tok . tokAt ( 2 ) - > isName ( ) )
iteratorId = tok . tokAt ( 2 ) - > varId ( ) ;
else
iteratorId = tok . tokAt ( 3 ) - > varId ( ) ;
2010-10-15 18:21:53 +02:00
// invalidate this iterator in the corresponding checks
2010-10-05 20:54:13 +02:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
EraseCheckLoop * c = dynamic_cast < EraseCheckLoop * > ( * it ) ;
if ( c & & c - > varId = = iteratorId )
{
c - > eraseToken = & tok ;
}
}
}
}
2010-10-15 18:21:53 +02:00
// don't skip any tokens. return the token that we received.
2010-10-05 20:54:13 +02:00
return & tok ;
}
2010-10-09 07:15:34 +02:00
/**
* Parse condition . @ sa ExecutionPath : : parseCondition
* @ param tok first token in condition .
* @ param checks The execution paths . All execution paths in the list are executed in the current scope
* @ return true = > bail out all checking
* */
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks )
{
2010-10-15 18:21:53 +02:00
// no checking of conditions.
2010-10-09 07:15:34 +02:00
( void ) tok ;
( void ) checks ;
return false ;
}
2010-10-05 20:54:13 +02:00
/** @brief going out of scope - all execution paths end */
void end ( const std : : list < ExecutionPath * > & checks , const Token * /*tok*/ ) const
{
2010-10-15 18:21:53 +02:00
// check if there are any invalid iterators. If so there is an error.
2010-10-05 20:54:13 +02:00
for ( std : : list < ExecutionPath * > : : const_iterator it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it )
{
EraseCheckLoop * c = dynamic_cast < EraseCheckLoop * > ( * it ) ;
if ( c & & c - > eraseToken )
{
CheckStl * checkStl = dynamic_cast < CheckStl * > ( c - > owner ) ;
if ( checkStl )
{
checkStl - > eraseError ( c - > eraseToken ) ;
}
}
}
}
} ;
2009-02-11 06:08:29 +01:00
void CheckStl : : erase ( )
{
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-02-11 06:08:29 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) )
2009-02-11 06:08:29 +01:00
{
2010-05-08 20:11:15 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
2009-02-11 06:08:29 +01:00
{
2010-05-08 20:11:15 +02:00
if ( tok2 - > str ( ) = = " ; " )
{
if ( Token : : Match ( tok2 , " ; %var% != " ) )
{
const unsigned int varid = tok2 - > next ( ) - > varId ( ) ;
if ( varid > 0 & & Token : : findmatch ( _tokenizer - > tokens ( ) , " > :: iterator %varid% " , varid ) )
2010-10-05 20:54:13 +02:00
EraseCheckLoop : : checkScope ( this , tok2 - > next ( ) ) ;
2010-05-08 20:11:15 +02:00
}
break ;
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %var% = %var% . begin ( ) ; %var% != %var% . end ( ) " ) & &
tok2 - > str ( ) = = tok2 - > tokAt ( 8 ) - > str ( ) & &
tok2 - > tokAt ( 2 ) - > str ( ) = = tok2 - > tokAt ( 10 ) - > str ( ) )
2009-02-11 06:08:29 +01:00
{
2010-10-05 20:54:13 +02:00
EraseCheckLoop : : checkScope ( this , tok2 ) ;
2009-02-11 06:08:29 +01:00
break ;
}
}
}
2010-05-08 20:11:15 +02:00
if ( Token : : Match ( tok , " while ( %var% != " ) )
2009-02-11 06:08:29 +01:00
{
2010-05-08 20:11:15 +02:00
const unsigned int varid = tok - > tokAt ( 2 ) - > varId ( ) ;
if ( varid > 0 & & Token : : findmatch ( _tokenizer - > tokens ( ) , " > :: iterator %varid% " , varid ) )
2010-10-05 20:54:13 +02:00
EraseCheckLoop : : checkScope ( this , tok - > tokAt ( 2 ) ) ;
2010-07-14 09:42:10 +02:00
}
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-12-21 20:49:16 +01:00
reportError ( tok , Severity : : error , " erase " , " Dangerous iterator usage. After erase the iterator is invalid so dereferencing it or comparing it with another 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..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-04-28 21:18:02 +02:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% = & %var% [ " ) )
2009-04-28 21:18:02 +02:00
{
const unsigned int pointerId ( tok - > varId ( ) ) ;
const unsigned int containerId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( pointerId = = 0 | | containerId = = 0 )
2009-04-28 21:18:02 +02:00
continue ;
int indent = 0 ;
bool invalidPointer = false ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; indent > = 0 & & tok2 ; tok2 = tok2 - > next ( ) )
2009-04-28 21:18:02 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " ( " )
2009-04-28 21:18:02 +02:00
+ + indent ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " ) " )
2009-04-28 21:18:02 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indent = = 0 & & Token : : simpleMatch ( tok2 , " ) { " ) )
2009-04-28 21:18:02 +02:00
tok2 = tok2 - > next ( ) ;
else
- - indent ;
}
// push_back on vector..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% . push_front|push_back " , containerId ) )
2009-04-28 21:18:02 +02:00
invalidPointer = true ;
// Using invalid pointer..
2010-04-02 07:30:58 +02:00
if ( invalidPointer & & tok2 - > varId ( ) = = pointerId )
2009-04-28 21:18:02 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > previous ( ) - > str ( ) = = " * " )
2009-04-28 21:18:02 +02:00
invalidPointerError ( tok2 , tok2 - > str ( ) ) ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > next ( ) - > str ( ) = = " . " )
2009-04-28 21:18:02 +02:00
invalidPointerError ( tok2 , tok2 - > str ( ) ) ;
break ;
}
}
}
}
2010-06-15 19:53:09 +02:00
// Iterator becomes invalid after reserve, push_back or push_front..
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-02-18 20:57:43 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok , " vector < " ) )
2009-10-31 15:27:33 +01:00
continue ;
// if iterator declaration inside for() loop
bool iteratorDeclaredInsideLoop = false ;
2010-04-02 07:30:58 +02:00
if ( ( tok - > tokAt ( - 2 ) & & Token : : simpleMatch ( tok - > tokAt ( - 2 ) , " for ( " ) ) | |
( tok - > tokAt ( - 4 ) & & Token : : simpleMatch ( tok - > tokAt ( - 4 ) , " for ( std :: " ) ) )
2009-10-31 15:27:33 +01:00
{
iteratorDeclaredInsideLoop = true ;
}
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " > " )
2009-10-31 15:27:33 +01:00
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-10-31 15:27:33 +01:00
break ;
2010-04-02 07:30:58 +02:00
if ( ! Token : : Match ( tok , " > :: iterator|const_iterator %var% =|; " ) )
2009-10-31 15:27:33 +01:00
continue ;
const unsigned int iteratorid ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( iteratorid = = 0 )
2009-10-31 15:27:33 +01:00
continue ;
2010-04-02 07:30:58 +02:00
if ( iteratorDeclaredInsideLoop & & tok - > tokAt ( 4 ) - > str ( ) = = " = " )
2009-10-31 15:27:33 +01:00
{
// skip "> :: iterator|const_iterator"
tok = tok - > tokAt ( 3 ) ;
}
2009-11-10 19:07:04 +01:00
unsigned int vectorid = 0 ;
2009-10-31 15:27:33 +01:00
int indent = 0 ;
std : : string invalidIterator ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; indent > = 0 & & tok2 ; tok2 = tok2 - > next ( ) )
2009-02-18 20:57:43 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " ( " )
2009-10-31 15:27:33 +01:00
+ + indent ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " | | tok2 - > str ( ) = = " ) " )
2009-09-27 09:59:19 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indent = = 0 & & Token : : simpleMatch ( tok2 , " ) { " ) )
2009-10-31 15:27:33 +01:00
tok2 = tok2 - > next ( ) ;
else
- - indent ;
2009-09-27 09:59:19 +02:00
}
2009-10-31 15:27:33 +01:00
// Using push_back or push_front inside a loop..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " for ( " ) )
2009-02-18 20:57:43 +01:00
{
2009-10-31 15:27:33 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
}
2009-04-25 17:14:02 +02:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% = %var% . begin ( ) ; %varid% != %var% . end ( ) ; ++| %varid% ++| ) { " , iteratorid ) )
2009-10-31 15:27:33 +01:00
{
2010-04-11 13:49:50 +02:00
const unsigned int varId ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
if ( varId = = 0 )
2009-10-31 15:27:33 +01:00
continue ;
2009-09-27 09:59:19 +02:00
2010-04-11 13:49:50 +02:00
const Token * pushbackTok = 0 ;
2009-10-31 15:27:33 +01:00
unsigned int indent3 = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok3 = tok2 - > tokAt ( 20 ) ; tok3 ; tok3 = tok3 - > next ( ) )
2009-02-18 20:57:43 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok3 - > str ( ) = = " { " )
2009-10-31 15:27:33 +01:00
+ + indent3 ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2009-02-18 20:57:43 +01:00
{
2010-04-02 07:30:58 +02:00
if ( indent3 < = 1 )
2009-10-31 15:27:33 +01:00
break ;
- - indent3 ;
2009-02-18 20:57:43 +01:00
}
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " break " )
2009-09-27 09:59:19 +02:00
{
2010-04-11 13:49:50 +02:00
pushbackTok = 0 ;
2009-10-31 15:27:33 +01:00
break ;
2009-09-27 09:59:19 +02:00
}
2010-06-15 19:53:09 +02:00
else if ( Token : : Match ( tok3 , " %varid% . push_front|push_back|insert|reserve ( " , varId ) )
2009-07-14 12:40:47 +02:00
{
2010-04-11 13:49:50 +02:00
pushbackTok = tok3 - > tokAt ( 2 ) ;
2009-07-14 12:40:47 +02:00
}
2009-10-31 15:27:33 +01:00
}
2009-02-18 20:57:43 +01:00
2010-04-11 13:49:50 +02:00
if ( pushbackTok )
invalidIteratorError ( pushbackTok , pushbackTok - > str ( ) , tok2 - > strAt ( 0 ) ) ;
2009-10-31 15:27:33 +01:00
}
2009-02-18 20:57:43 +01:00
2009-10-31 15:27:33 +01:00
// Assigning iterator..
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% = " , iteratorid ) )
2009-10-31 15:27:33 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 - > tokAt ( 2 ) , " %var% . begin|end|rbegin|rend ( ) " ) )
2009-11-02 21:53:01 +01:00
{
2009-11-10 19:07:04 +01:00
vectorid = tok2 - > tokAt ( 2 ) - > varId ( ) ;
2009-11-02 21:53:01 +01:00
tok2 = tok2 - > tokAt ( 6 ) ;
}
2009-10-31 15:27:33 +01:00
else
2009-11-10 19:07:04 +01:00
{
vectorid = 0 ;
}
2009-10-31 15:27:33 +01:00
invalidIterator = " " ;
}
2009-02-18 20:57:43 +01:00
2009-10-31 15:27:33 +01:00
// push_back on vector..
2010-06-15 19:53:09 +02:00
if ( vectorid > 0 & & Token : : Match ( tok2 , " %varid% . push_front|push_back|insert|reserve ( " , vectorid ) )
2009-10-31 15:27:33 +01:00
{
2010-04-02 07:30:58 +02:00
if ( ! invalidIterator . empty ( ) & & Token : : Match ( tok2 - > tokAt ( 2 ) , " insert ( %varid% , " , iteratorid ) )
2009-11-02 21:53:01 +01:00
{
invalidIteratorError ( tok2 , invalidIterator , tok2 - > strAt ( 4 ) ) ;
break ;
}
2009-10-31 15:27:33 +01:00
invalidIterator = tok2 - > strAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( ! iteratorDeclaredInsideLoop )
2009-10-31 15:27:33 +01:00
{
2009-11-02 21:53:01 +01:00
tok2 = tok2 - > tokAt ( 3 ) - > link ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok2 )
2009-10-31 15:27:33 +01:00
break ;
2009-02-18 20:57:43 +01:00
}
}
2009-10-31 15:27:33 +01:00
2010-04-16 16:56:55 +02:00
else if ( tok2 - > str ( ) = = " return " )
{
invalidIterator . clear ( ) ;
}
2009-10-31 15:27:33 +01:00
// Using invalid iterator..
2010-04-02 07:30:58 +02:00
if ( ! invalidIterator . empty ( ) )
2009-10-31 15:27:33 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " ++|--|*|+|-|(|,|=|!= %varid% " , iteratorid ) )
2009-10-31 15:27:33 +01:00
invalidIteratorError ( tok2 , invalidIterator , tok2 - > strAt ( 1 ) ) ;
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok2 , " %varid% ++|--|+|- " , iteratorid ) )
2009-10-31 15:27:33 +01:00
invalidIteratorError ( tok2 , invalidIterator , tok2 - > str ( ) ) ;
}
2009-02-18 20:57:43 +01:00
}
}
}
2009-03-21 17:58:13 +01:00
// Error message for bad iterator usage..
2009-10-21 20:15:11 +02:00
void CheckStl : : invalidIteratorError ( const Token * tok , const std : : string & func , const std : : string & iterator_name )
2009-03-21 17:58:13 +01:00
{
2010-05-13 22:14:29 +02:00
reportError ( tok , Severity : : error , " invalidIterator2 " , " After " + func + " , 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-10-21 20:15:11 +02:00
reportError ( tok , Severity : : error , " invalidPointer " , " 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 " ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-04-13 17:48:13 +02:00
{
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 ) + " < " ) ;
2010-04-02 07:30:58 +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 ) ) ;
2010-04-02 07:30:58 +02:00
while ( tok & & tok - > str ( ) ! = " > " )
2009-05-17 18:58:32 +02:00
tok = tok - > next ( ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok )
2009-05-17 18:58:32 +02:00
break ;
2010-04-02 07:30:58 +02:00
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 ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( iteratorid = = 0 )
2009-05-17 18:58:32 +02:00
continue ;
// Using "iterator < ..." is not allowed
unsigned int indentlevel = 0 ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok ; tok2 ; tok2 = tok2 - > next ( ) )
2009-04-13 17:48:13 +02:00
{
2010-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " { " )
2009-05-17 18:58:32 +02:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok2 - > str ( ) = = " } " )
2009-05-17 18:58:32 +02:00
{
2010-04-02 07:30:58 +02:00
if ( indentlevel = = 0 )
2009-05-17 18:58:32 +02:00
break ;
- - indentlevel ;
}
2010-04-02 07:30:58 +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
{
2010-12-26 21:02:20 +01:00
reportError ( tok , Severity : : error , " stlBoundries " ,
" Dangerous container iterator compare using < operator for " + container_name + " \n "
" Using < operator with container type iterators is dangerous since the order of "
" the items is not guaranteed. One should use != operator instead when comparing "
" iterators in the container. " ) ;
2009-04-13 17:48:13 +02:00
}
2009-11-02 20:24:38 +01:00
2010-02-27 21:26:11 +01:00
void CheckStl : : if_find ( )
{
2010-04-02 07:30:58 +02:00
if ( ! _settings - > _checkCodingStyle )
2010-02-28 06:56:47 +01:00
return ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2010-02-27 21:26:11 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( !| %var% . find ( %any% ) ) " ) )
2010-02-27 21:26:11 +01:00
{
// goto %var%
tok = tok - > tokAt ( 2 ) ;
2010-04-02 07:30:58 +02:00
if ( ! tok - > isName ( ) )
2010-02-27 21:26:11 +01:00
tok = tok - > next ( ) ;
const unsigned int varid = tok - > varId ( ) ;
2010-04-02 07:30:58 +02:00
if ( varid > 0 )
2010-02-27 21:26:11 +01:00
{
2010-02-28 08:03:22 +01:00
// Is the variable a std::string or STL container?
const Token * decl = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , varid ) ;
2010-04-02 07:30:58 +02:00
while ( decl & & ! Token : : Match ( decl , " [;{}(,] " ) )
2010-02-28 08:03:22 +01:00
decl = decl - > previous ( ) ;
decl = decl - > next ( ) ;
// stl container
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( decl , " const| std :: %var% < %type% > &|*| %varid% " , varid ) )
2010-02-27 21:26:11 +01:00
if_findError ( tok , false ) ;
2010-05-01 21:56:39 +02:00
else if ( Token : : Match ( decl , " const| std :: string &|*| %varid% " , varid ) )
if_findError ( tok , true ) ;
2010-02-27 21:26:11 +01:00
}
}
2010-02-28 07:04:58 +01:00
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " if ( !| std :: find|find_if ( " ) )
2010-02-28 07:04:58 +01:00
{
// goto '(' for the find
tok = tok - > tokAt ( 4 ) ;
2010-04-02 07:30:58 +02:00
if ( tok - > isName ( ) )
2010-02-28 07:04:58 +01:00
tok = tok - > next ( ) ;
// check that result is checked properly
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( tok - > link ( ) , " ) ) " ) )
2010-02-28 07:04:58 +01:00
{
if_findError ( tok , false ) ;
}
}
2010-02-27 21:26:11 +01:00
}
}
void CheckStl : : if_findError ( const Token * tok , bool str )
{
2010-04-02 07:30:58 +02:00
if ( str )
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " stlIfStrFind " , " Suspicious condition. string::find will return 0 if the string is found at position 0. If this is what you want to check then string::compare is a faster alternative because it doesn't scan through the string. " ) ;
2010-02-27 21:26:11 +01:00
else
2010-10-17 14:41:00 +02:00
reportError ( tok , Severity : : warning , " stlIfFind " , " Suspicious condition. The result of find is an iterator, but it is not properly checked. " ) ;
2010-02-27 21:26:11 +01:00
}
2009-12-19 15:24:59 +01:00
bool CheckStl : : isStlContainer ( const Token * tok )
{
// check if this token is defined
2010-04-02 07:30:58 +02:00
if ( tok - > varId ( ) )
2009-12-19 15:24:59 +01:00
{
// find where this token is defined
const Token * type = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% " , tok - > varId ( ) ) ;
// find where this tokens type starts
2010-04-02 07:30:58 +02:00
while ( type - > previous ( ) & & ! Token : : Match ( type - > previous ( ) , " [;{,(] " ) )
2009-12-19 15:24:59 +01:00
type = type - > previous ( ) ;
2010-02-28 08:03:22 +01:00
// ignore "const"
2010-04-02 07:30:58 +02:00
if ( type - > str ( ) = = " const " )
2010-02-28 08:03:22 +01:00
type = type - > next ( ) ;
2009-12-19 15:24:59 +01:00
// discard namespace if supplied
2010-04-02 07:30:58 +02:00
if ( Token : : simpleMatch ( type , " std :: " ) )
2009-12-19 15:24:59 +01:00
type = type - > next ( ) - > next ( ) ;
// all possible stl containers
static const char STL_CONTAINER_LIST [ ] = " bitset|deque|list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|vector " ;
// container template string
2010-01-26 19:37:22 +01:00
const std : : string checkStr ( std : : string ( STL_CONTAINER_LIST ) + " < " ) ;
2009-12-19 15:24:59 +01:00
// check if it's an stl template
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( type , checkStr . c_str ( ) ) )
2009-12-19 15:24:59 +01:00
return true ;
}
return false ;
}
void CheckStl : : size ( )
{
2010-04-21 08:38:25 +02:00
if ( ! _settings - > _checkCodingStyle | | ! _settings - > inconclusive )
return ;
2010-04-02 07:30:58 +02:00
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
2009-12-19 15:24:59 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " %var% . size ( ) " ) )
2009-12-19 15:24:59 +01:00
{
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( 5 ) , " ==|!=|> 0 " ) )
2009-12-19 15:24:59 +01:00
{
2010-04-02 07:30:58 +02:00
if ( isStlContainer ( tok ) )
2009-12-19 15:24:59 +01:00
sizeError ( tok ) ;
}
2010-04-02 07:30:58 +02:00
else if ( ( tok - > tokAt ( 5 ) - > str ( ) = = " ) " | |
tok - > tokAt ( 5 ) - > str ( ) = = " && " | |
tok - > tokAt ( 5 ) - > str ( ) = = " || " | |
tok - > tokAt ( 5 ) - > str ( ) = = " ! " ) & &
( tok - > tokAt ( - 1 ) - > str ( ) = = " ( " | |
tok - > tokAt ( - 1 ) - > str ( ) = = " && " | |
tok - > tokAt ( - 1 ) - > str ( ) = = " || " | |
tok - > tokAt ( - 1 ) - > str ( ) = = " ! " ) )
2009-12-19 15:24:59 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > tokAt ( - 1 ) - > str ( ) = = " ( " & &
tok - > tokAt ( 5 ) - > str ( ) = = " ) " )
2009-12-19 15:24:59 +01:00
{
// check for passing size to function call
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " if|while " ) )
2009-12-19 15:24:59 +01:00
{
2010-04-02 07:30:58 +02:00
if ( isStlContainer ( tok ) )
2009-12-19 15:24:59 +01:00
sizeError ( tok ) ;
}
}
2010-04-02 07:30:58 +02:00
else if ( isStlContainer ( tok ) )
2009-12-19 15:24:59 +01:00
sizeError ( tok ) ;
}
}
}
}
void CheckStl : : sizeError ( const Token * tok )
{
2010-02-06 10:39:16 +01:00
const std : : string varname ( tok ? tok - > str ( ) . c_str ( ) : " list " ) ;
2010-12-04 09:15:48 +01:00
reportError ( tok , Severity : : performance , " stlSize " ,
" Possible inefficient checking for ' " + varname + " ' emptiness. \n "
" Using " + varname + " .empty() instead of " + varname + " .size() can be faster. " +
varname + " .size() can take linear time but " + varname + " .empty() is "
" guaranteed to take constant time. " ) ;
2009-12-19 15:24:59 +01:00
}
2010-09-16 18:49:23 +02:00
void CheckStl : : redundantCondition ( )
{
const char pattern [ ] = " if ( %var% . find ( %any% ) != %var% . end ( ) ) "
" {|{| "
" %var% . remove ( %any% ) ; "
" }|}| " ;
const Token * tok = Token : : findmatch ( _tokenizer - > tokens ( ) , pattern ) ;
while ( tok )
{
bool b ( tok - > tokAt ( 15 ) - > str ( ) = = " { " );
// Get tokens for the fields %var% and %any%
const Token * var1 = tok - > tokAt ( 2 ) ;
const Token * any1 = tok - > tokAt ( 6 ) ;
const Token * var2 = tok - > tokAt ( 9 ) ;
const Token * var3 = tok - > tokAt ( b ? 16 : 15 ) ;
const Token * any2 = tok - > tokAt ( b ? 20 : 19 ) ;
// Check if all the "%var%" fields are the same and if all the "%any%" are the same..
if ( var1 - > str ( ) = = var2 - > str ( ) & &
var2 - > str ( ) = = var3 - > str ( ) & &
any1 - > str ( ) = = any2 - > str ( ) )
{
redundantIfRemoveError ( tok ) ;
}
tok = Token : : findmatch ( tok - > next ( ) , pattern ) ;
}
}
void CheckStl : : redundantIfRemoveError ( const Token * tok )
{
2010-11-29 19:24:08 +01:00
reportError ( tok , Severity : : style , " redundantIfRemove " , " Redundant checking of STL container element. \n "
" The remove method in the STL will not do anything if element doesn't exist " ) ;
2010-09-16 18:49:23 +02:00
}
2010-10-10 10:52:41 +02:00
void CheckStl : : missingComparison ( )
{
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : simpleMatch ( tok , " for ( " ) )
{
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 ; tok2 = tok2 - > next ( ) )
{
if ( tok2 - > str ( ) = = " ; " )
break ;
if ( ! Token : : Match ( tok2 , " %var% = %var% . begin ( ) ; %var% != %var% . end ( ) ; ++| %var% ++| ) { " ) )
continue ;
// same iterator name
if ( tok2 - > str ( ) ! = tok2 - > strAt ( 8 ) )
continue ;
// same container
if ( tok2 - > strAt ( 2 ) ! = tok2 - > strAt ( 10 ) )
continue ;
// increment iterator
if ( ! Token : : simpleMatch ( tok2 - > tokAt ( 16 ) , ( " ++ " + tok2 - > str ( ) + " ) " ) . c_str ( ) ) & &
! Token : : simpleMatch ( tok2 - > tokAt ( 16 ) , ( tok2 - > str ( ) + " ++ ) " ) . c_str ( ) ) )
{
continue ;
}
2010-10-10 14:28:14 +02:00
const unsigned int & iteratorId ( tok2 - > varId ( ) ) ;
2010-10-30 11:22:30 +02:00
if ( iteratorId = = 0 )
continue ;
2010-10-10 10:52:41 +02:00
const Token * incrementToken = 0 ;
unsigned int indentlevel = 0 ;
// Parse loop..
for ( const Token * tok3 = tok2 - > tokAt ( 20 ) ; tok3 ; tok3 = tok3 - > next ( ) )
{
if ( tok3 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok3 - > str ( ) = = " } " )
{
if ( indentlevel = = 0 )
break ;
- - indentlevel ;
}
2010-10-10 14:28:14 +02:00
else if ( tok3 - > varId ( ) = = iteratorId & & Token : : simpleMatch ( tok3 - > next ( ) , " ++ " ) )
2010-10-10 10:52:41 +02:00
incrementToken = tok3 ;
2010-10-10 14:28:14 +02:00
else if ( tok3 - > str ( ) = = " ++ " & & tok3 - > next ( ) & & tok3 - > next ( ) - > varId ( ) = = iteratorId )
2010-10-10 10:52:41 +02:00
incrementToken = tok3 ;
2010-10-10 14:28:14 +02:00
else if ( tok3 - > varId ( ) = = iteratorId & & Token : : Match ( tok3 - > next ( ) , " !=|== " ) )
2010-10-10 10:52:41 +02:00
incrementToken = 0 ;
2010-10-18 20:05:54 +02:00
else if ( tok3 - > str ( ) = = " break " )
incrementToken = 0 ;
2010-10-10 10:52:41 +02:00
}
if ( incrementToken )
missingComparisonError ( incrementToken , tok2 - > tokAt ( 16 ) ) ;
}
}
}
}
void CheckStl : : missingComparisonError ( const Token * incrementToken1 , const Token * incrementToken2 )
{
std : : ostringstream errmsg ;
2010-11-29 19:27:31 +01:00
errmsg < < " Missing bounds check for extra iterator increment in loop. \n "
2010-11-27 09:57:26 +01:00
< < " The iterator incrementing is suspicious - it is incremented at line "
< < incrementToken1 - > linenr ( ) < < " and then at line " < < incrementToken2 - > linenr ( )
< < " The loop might unintentionally skip an element in the container. "
< < " There is no comparison between these increments to prevent that the iterator is "
< < " incremented beyond the end. " ;
2010-10-10 10:52:41 +02:00
2010-10-17 14:41:00 +02:00
reportError ( incrementToken1 , Severity : : warning , " StlMissingComparison " , errmsg . str ( ) ) ;
2010-10-10 10:52:41 +02:00
}
2010-10-17 19:18:46 +02:00
void CheckStl : : string_c_str ( )
{
// Try to detect common problems when using string::c_str()
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
// Locate executable scopes:
if ( Token : : Match ( tok , " ) const| { " ) )
{
std : : set < unsigned int > localvar ;
2010-10-19 20:21:58 +02:00
std : : set < unsigned int > pointers ;
2010-10-17 19:18:46 +02:00
// scan through this executable scope:
unsigned int indentlevel = 0 ;
while ( NULL ! = ( tok = tok - > next ( ) ) )
{
if ( tok - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok - > str ( ) = = " } " )
{
if ( indentlevel < = 1 )
break ;
- - indentlevel ;
}
// Variable declarations..
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } ] std : : % type % % var % ; " ))
localvar . insert ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } ] % type % % var % ; " ))
localvar . insert ( tok - > next ( ) - > varId ( ) ) ;
2010-10-19 20:21:58 +02:00
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } ] % type % * % var % ; " ))
pointers . insert ( tok - > tokAt ( 2 ) - > varId ( ) ) ;
else if ( Token : : Match ( tok - > previous ( ) , " [ ; { } ] % type % % type % * % var % ; " ))
pointers . insert ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2010-10-17 19:18:46 +02:00
// Invalid usage..
else if ( Token : : Match ( tok , " throw %var% . c_str ( ) ; " ) &&
tok - > next ( ) - > varId ( ) > 0 & &
localvar . find ( tok - > next ( ) - > varId ( ) ) ! = localvar . end ( ) )
{
string_c_strError ( tok ) ;
}
2010-10-19 20:21:58 +02:00
else if ( Token : : Match ( tok , " [;{}] %var% = %var% . str ( ) . c_str ( ) ; " ) & &
tok - > next ( ) - > varId ( ) > 0 & &
pointers . find ( tok - > next ( ) - > varId ( ) ) ! = pointers . end ( ) )
{
string_c_strError ( tok ) ;
}
else if ( Token : : Match ( tok , " [;{}] %var% = %var% ( " ) & &
Token : : Match ( tok - > tokAt ( 4 ) - > link ( ) , " ) . c_str ( ) ; " ) & &
tok - > next ( ) - > varId ( ) > 0 & &
pointers . find ( tok - > next ( ) - > varId ( ) ) ! = pointers . end ( ) & &
Token : : findmatch ( _tokenizer - > tokens ( ) , ( " std :: string " + tok - > strAt ( 3 ) + " ( " ) . c_str ( ) ) )
{
string_c_strError ( tok ) ;
}
2010-10-17 19:18:46 +02:00
}
}
}
}
void CheckStl : : string_c_strError ( const Token * tok )
{
reportError ( tok , Severity : : error , " stlcstr " , " Dangerous usage of c_str() " ) ;
}