2009-02-10 20:40:21 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2011-01-09 20:33:36 +01:00
* Copyright ( C ) 2007 - 2011 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"
2010-10-05 20:54:13 +02:00
# include "executionpath.h"
2011-03-08 01:49:43 +01:00
# include "symboldatabase.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 )
{
2011-03-13 08:48:38 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const Variable * variableInfo = symbolDatabase - > getVariableFromVarId ( tok2 - > varId ( ) ) ;
const Token * decltok = variableInfo ? variableInfo - > typeStartToken ( ) : NULL ;
if ( Token : : Match ( decltok , " const| std :: set " ) )
2010-04-10 10:22:34 +02:00
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
2011-06-14 07:26:59 +02:00
else if ( Token : : Match ( tok2 , " return|break " ) )
2010-07-09 10:50:24 +02:00
{
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
{
2011-01-06 12:20:54 +01:00
// Count { and } for tok3
unsigned int indent3 = 0 ;
// variable id for loop variable.
2009-10-07 22:53:16 +02:00
unsigned int numId = tok2 - > tokAt ( 1 ) - > varId ( ) ;
2011-01-06 12:20:54 +01:00
// variable id for the container variable
2009-10-07 22:49:06 +02:00
unsigned int varId = tok2 - > tokAt ( 3 ) - > varId ( ) ;
2011-01-06 12:20:54 +01:00
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 ( ) = = " { " )
2011-01-06 12:20:54 +01:00
+ + indent3 ;
2010-04-02 07:30:58 +02:00
else if ( tok3 - > str ( ) = = " } " )
2009-05-06 21:55:04 +02:00
{
2011-01-06 12:20:54 +01:00
if ( indent3 < = 1 )
2009-05-06 21:55:04 +02:00
break ;
2011-01-06 12:20:54 +01:00
- - indent3 ;
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 ( ) = = " ( " )
2011-01-20 20:48:35 +01:00
tok = tok - > link ( ) ;
2010-10-05 20:54:13 +02:00
else if ( tok - > str ( ) = = " ) " )
2011-01-20 20:48:35 +01:00
break ;
// reassigning iterator in loop head
else if ( Token : : Match ( tok , " %var% = " ) & & tok - > str ( ) = = it - > str ( ) )
break ;
2010-10-05 20:54:13 +02:00
}
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% != " ) )
{
2011-03-13 09:48:53 +01:00
// Get declaration token for var..
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
const Variable * variableInfo = symbolDatabase - > getVariableFromVarId ( tok2 - > next ( ) - > varId ( ) ) ;
const Token * decltok = variableInfo ? variableInfo - > typeEndToken ( ) : NULL ;
// Is variable an iterator?
bool isIterator = false ;
if ( decltok & & Token : : Match ( decltok - > tokAt ( - 2 ) , " > :: iterator %varid% " , tok2 - > next ( ) - > varId ( ) ) )
isIterator = true ;
// If tok2->next() is an iterator, check scope
if ( isIterator )
2010-10-05 20:54:13 +02:00
EraseCheckLoop : : checkScope ( this , tok2 - > next ( ) ) ;
2010-05-08 20:11:15 +02:00
}
break ;
}
2011-02-02 16:41:43 +01:00
if ( Token : : Match ( tok2 , " %var% = %var% . begin ( ) ; %var% != %var% . end ( ) " ) & &
2010-04-02 07:30:58 +02:00
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 )
{
2011-01-04 21:06:41 +01:00
reportError ( tok , Severity : : error , " erase " ,
" Dangerous iterator usage after erase()-method. \n "
" The iterator is invalid after it has been used in erase() function. "
" Dereferencing or comparing it with another iterator is invalid operation. " ) ;
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
{
2011-01-06 12:20:54 +01:00
// Variable id for pointer
2009-04-28 21:18:02 +02:00
const unsigned int pointerId ( tok - > varId ( ) ) ;
2011-01-06 12:20:54 +01:00
// Variable id for the container variable
2009-04-28 21:18:02 +02:00
const unsigned int containerId ( tok - > tokAt ( 3 ) - > varId ( ) ) ;
2011-01-06 12:20:54 +01:00
2010-04-02 07:30:58 +02:00
if ( pointerId = = 0 | | containerId = = 0 )
2009-04-28 21:18:02 +02:00
continue ;
2011-03-30 16:45:31 +02:00
// Count { , } and parentheses for tok2
2009-04-28 21:18:02 +02:00
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 ) ;
}
2011-01-06 12:20:54 +01:00
// the variable id for the vector
2009-11-10 19:07:04 +01:00
unsigned int vectorid = 0 ;
2011-01-06 12:20:54 +01:00
2011-03-30 16:45:31 +02:00
// count { , } and parentheses for tok2
2009-10-31 15:27:33 +01:00
int indent = 0 ;
2011-01-06 12:20:54 +01:00
2009-10-31 15:27:33 +01:00
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..
2011-02-02 16:48:00 +01:00
if ( Token : : simpleMatch ( 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
{
2011-01-06 12:20:54 +01:00
// variable id for the loop iterator
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 ;
2011-01-06 12:20:54 +01:00
// Count { and } for tok3
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
}
2011-01-20 19:26:52 +01:00
else if ( tok3 - > str ( ) = = " break " | | tok3 - > str ( ) = = " return " )
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 ) ;
2011-01-20 19:26:52 +01:00
tok2 = tok2 - > tokAt ( 3 ) - > link ( ) ;
2009-02-18 20:57:43 +01:00
}
2009-10-31 15:27:33 +01:00
2011-05-22 17:17:24 +02:00
// TODO: instead of bail out for 'else' try to check all execution paths.
else if ( tok2 - > str ( ) = = " return " | | tok2 - > str ( ) = = " break " | | tok2 - > str ( ) = = " else " )
2010-04-16 16:56:55 +02:00
{
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..
2011-01-15 22:38:05 +01:00
if ( tok - > str ( ) = = " < " & & Token : : Match ( tok - > previous ( ) , STL_CONTAINER_LIST ) )
2009-04-13 17:48:13 +02:00
{
2011-01-15 22:38:05 +01:00
const std : : string container_name ( tok - > strAt ( - 1 ) ) ;
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 "
2011-02-04 10:10:24 +01:00
" Container ' " + container_name + " ' iterator compared with < operator. "
2010-12-26 21:02:20 +01:00
" 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 )
2011-01-04 22:04:01 +01:00
reportError ( tok , Severity : : warning , " stlIfStrFind " ,
" Suspicious checking of string::find() return value. \n "
2011-02-04 10:10:24 +01:00
" Checking of string::find() return value looks Suspicious. "
2011-01-04 22:04:01 +01:00
" string::find will return 0 if the string is found at position 0. "
" If that is wanted 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
}
2011-03-29 01:31:23 +02:00
bool CheckStl : : isStlContainer ( unsigned int varid )
2009-12-19 15:24:59 +01:00
{
// check if this token is defined
2011-03-29 01:31:23 +02:00
if ( varid )
2009-12-19 15:24:59 +01:00
{
// find where this token is defined
2011-03-29 01:31:23 +02:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( varid ) ;
2011-03-08 01:49:43 +01:00
if ( ! var )
return false ;
2009-12-19 15:24:59 +01:00
// find where this tokens type starts
2011-03-08 01:49:43 +01:00
const Token * type = var - > typeStartToken ( ) ;
2009-12-19 15:24:59 +01:00
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
2011-05-05 20:57:17 +02:00
static const char STL_CONTAINER_LIST [ ] = " bitset|deque|list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|vector " ;
2009-12-19 15:24:59 +01:00
// 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 ( )
{
2011-03-08 01:49:43 +01:00
if ( ! _settings - > _checkCodingStyle )
2010-04-21 08:38:25 +02:00
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
{
2011-03-29 01:31:23 +02:00
if ( Token : : Match ( tok , " %var% . size ( ) " ) | |
Token : : Match ( tok , " %var% . %var% . size ( ) " ) )
2009-12-19 15:24:59 +01:00
{
2011-03-29 01:31:23 +02:00
int offset = 5 ;
const Token * tok1 = tok ;
unsigned int varid = 0 ;
// get the variable id
if ( tok - > strAt ( 2 ) ! = " size " )
2009-12-19 15:24:59 +01:00
{
2011-03-29 01:31:23 +02:00
offset = 7 ;
tok1 = tok1 - > tokAt ( 2 ) ;
// found a.b.size(), lookup class/struct variable
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok - > varId ( ) ) ;
if ( var & & var - > type ( ) )
{
// get class/struct variable type
const Scope * type = var - > type ( ) ;
// lookup variable member
std : : list < Variable > : : const_iterator it ;
for ( it = type - > varlist . begin ( ) ; it ! = type - > varlist . end ( ) ; + + it )
{
if ( it - > name ( ) = = tok1 - > str ( ) )
{
// found member variable, save varid
varid = it - > varId ( ) ;
break ;
}
}
}
2009-12-19 15:24:59 +01:00
}
2011-03-29 01:31:23 +02:00
else
varid = tok1 - > varId ( ) ;
2011-03-08 01:49:43 +01:00
2011-03-29 01:31:23 +02:00
if ( varid )
2009-12-19 15:24:59 +01:00
{
2011-03-29 01:31:23 +02:00
// check for comparison to zero
if ( Token : : Match ( tok - > tokAt ( offset ) , " ==|!=|> 0 " ) | |
Token : : Match ( tok - > tokAt ( - 2 ) , " 0 ==|!=|< " ) )
{
if ( isStlContainer ( varid ) )
sizeError ( tok1 ) ;
}
// check for using as boolean expression
else if ( ( Token : : Match ( tok - > tokAt ( - 2 ) , " if|while ( " ) | |
Token : : Match ( tok - > tokAt ( - 3 ) , " if|while ( ! " ) ) & &
tok - > strAt ( offset ) = = " ) " )
{
if ( isStlContainer ( varid ) )
sizeError ( tok1 ) ;
}
2009-12-19 15:24:59 +01:00
}
}
}
}
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 "
2011-02-04 10:10:24 +01:00
" Checking for ' " + varname + " ' emptiness might be inefficient. "
2010-12-04 09:15:48 +01:00
" 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 )
{
2011-02-04 10:10:24 +01:00
reportError ( tok , Severity : : style , " redundantIfRemove " ,
" Redundant checking of STL container element. \n "
" Redundant checking of STL container element existence before removing it. "
2010-11-29 19:24:08 +01:00
" 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 ;
2011-01-06 12:20:54 +01:00
// Count { and } for tok3
2010-10-10 10:52:41 +02:00
unsigned int indentlevel = 0 ;
2011-01-06 12:20:54 +01:00
2010-10-10 10:52:41 +02:00
// 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 ;
}
2011-01-14 19:50:07 +01:00
else if ( Token : : Match ( tok3 , " %varid% ++ " , iteratorId ) )
2010-10-10 10:52:41 +02:00
incrementToken = tok3 ;
2011-01-14 19:50:07 +01:00
else if ( Token : : Match ( tok3 - > previous ( ) , " ++ %varid% !!. " , iteratorId ) )
2010-10-10 10:52:41 +02:00
incrementToken = tok3 ;
2011-01-14 19:50:07 +01:00
else if ( Token : : Match ( tok3 , " %varid% !=|== " , iteratorId ) )
2010-10-10 10:52:41 +02:00
incrementToken = 0 ;
2011-01-13 20:57:44 +01:00
else if ( tok3 - > str ( ) = = " break " | | tok3 - > str ( ) = = " return " )
2010-10-18 20:05:54 +02:00
incrementToken = 0 ;
2011-03-12 20:29:54 +01:00
else if ( Token : : Match ( tok3 , " %varid% = %var% . insert ( ++| %varid% ++| , " , iteratorId ) )
{
// skip insertion..
tok3 = tok3 - > tokAt ( 6 ) - > link ( ) ;
if ( ! tok3 )
break ;
}
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% ( " ) & &
2011-02-02 17:12:46 +01:00
Token : : simpleMatch ( tok - > tokAt ( 4 ) - > link ( ) , " ) . c_str ( ) ; " ) & &
2010-10-19 20:21:58 +02:00
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() " ) ;
}
2011-06-16 20:26:00 +02:00
//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
void CheckStl : : checkAutoPointer ( )
{
std : : set < int > autoPtrVarId ;
std : : set < int > : : const_iterator iter ;
static const char STL_CONTAINER_LIST [ ] = " bitset|deque|list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|vector " ;
for ( const Token * tok = _tokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) )
{
if ( Token : : simpleMatch ( tok , " auto_ptr < " ) )
{
2011-06-17 21:09:27 +02:00
if ( ( tok - > previous ( ) - > str ( ) = = " < " & & Token : : Match ( tok - > tokAt ( - 2 ) , STL_CONTAINER_LIST ) ) | | ( Token : : Match ( tok - > tokAt ( - 3 ) , " < std :: auto_ptr " ) & & Token : : Match ( tok - > tokAt ( - 4 ) , STL_CONTAINER_LIST ) ) )
2011-06-16 20:26:00 +02:00
{
autoPointerContainerError ( tok ) ;
}
else
{
const Token * tok2 = tok - > next ( ) - > next ( ) ;
while ( tok2 )
{
if ( Token : : Match ( tok2 , " > %var% " ) )
{
const Token * tok3 = tok2 - > next ( ) - > next ( ) ;
2011-06-17 21:09:27 +02:00
while ( tok3 & & tok3 - > str ( ) ! = " ; " )
2011-06-16 20:26:00 +02:00
{
tok3 = tok3 - > next ( ) ;
}
2011-06-17 21:09:27 +02:00
tok3 = tok3 - > previous ( ) - > previous ( ) ;
2011-06-20 23:02:05 +02:00
if ( Token : : Match ( tok3 - > previous ( ) , " [ ] ) " ) )
2011-06-16 20:26:00 +02:00
{
autoPointerArrayError ( tok2 - > next ( ) ) ;
}
2011-06-17 21:09:27 +02:00
else if ( tok3 - > varId ( ) )
2011-06-16 20:26:00 +02:00
{
2011-06-17 21:09:27 +02:00
const Token * decltok = Token : : findmatch ( _tokenizer - > tokens ( ) , " %varid% = new %type% [ " , tok3 - > varId ( ) ) ;
2011-06-16 20:26:00 +02:00
if ( decltok )
{
autoPointerArrayError ( tok2 - > next ( ) ) ;
}
}
2011-07-20 08:11:35 +02:00
if ( tok2 - > next ( ) - > varId ( ) )
{
autoPtrVarId . insert ( tok2 - > next ( ) - > varId ( ) ) ;
}
2011-06-16 20:26:00 +02:00
break ;
}
tok2 = tok2 - > next ( ) ;
}
}
}
else
{
if ( Token : : Match ( tok , " %var% = %var% ; " ) )
{
if ( _settings - > _checkCodingStyle )
{
iter = autoPtrVarId . find ( tok - > next ( ) - > next ( ) - > varId ( ) ) ;
if ( iter ! = autoPtrVarId . end ( ) )
{
autoPointerError ( tok - > next ( ) - > next ( ) ) ;
}
}
}
else if ( Token : : Match ( tok , " %var% = new %type% [ " ) | | Token : : Match ( tok , " %var% . reset ( new %type% [ " ) )
{
iter = autoPtrVarId . find ( tok - > varId ( ) ) ;
if ( iter ! = autoPtrVarId . end ( ) )
{
autoPointerArrayError ( tok ) ;
}
}
}
}
}
void CheckStl : : autoPointerError ( const Token * tok )
{
reportError ( tok , Severity : : style , " useAutoPointerCopy " ,
" Copy 'auto_ptr' pointer to another do not create two equal objects since one has lost its ownership of the pointer. \n "
" The auto_ptr has semantics of strict ownership, meaning that the auto_ptr instance is the sole entity responsible for the object's lifetime. If an auto_ptr is copied, the source loses the reference. "
) ;
}
void CheckStl : : autoPointerContainerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " useAutoPointerContainer " ,
" You can randomly lose access to pointers if you store 'auto_ptr' pointers in a container because the copy-semantics of 'auto_ptr' are not compatible with containers. \n "
" An element of container must be able to be copied but 'auto_ptr' does not fulfill this requirement. You should consider to use 'shared_ptr' or 'unique_ptr'. It is suitable for use in containers, because they no longer copy their values, they move them. "
) ;
}
void CheckStl : : autoPointerArrayError ( const Token * tok )
{
reportError ( tok , Severity : : error , " useAutoPointerArray " ,
" Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with operator 'new[]'. \n "
" Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. This means that you should only use 'auto_ptr' for pointers obtained with operator 'new'. This excludes arrays, which are allocated by operator 'new[]' and must be deallocated by operator 'delete[]'. "
) ;
}