2009-02-10 20:40:21 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2009-05-30 07:48:12 +02:00
* Copyright ( C ) 2007 - 2009 Daniel Marjamäki and Cppcheck team .
2009-02-10 20:40:21 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-02-10 20:40:21 +01:00
*/
# include "checkstl.h"
2009-02-11 06:08:29 +01:00
# include "tokenize.h"
2009-03-18 22:40:38 +01:00
# include "token.h"
2009-02-10 20:40:21 +01:00
2009-07-25 00:36:15 +02:00
2009-02-10 20:40:21 +01:00
2009-03-19 21:20:08 +01:00
// Register this check class (by creating a static instance of it)
namespace
{
2009-03-20 17:15:51 +01:00
CheckStl instance ;
2009-03-19 21:20:08 +01:00
}
2009-03-19 19:24:13 +01:00
2009-03-20 20:09:44 +01:00
// Error message for bad iterator usage..
void CheckStl : : iteratorsError ( const Token * tok , const std : : string & container1 , const std : : string & container2 )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " iterators " , " Same iterator is used with both " + container1 + " and " + container2 ) ;
2009-03-20 20:09:44 +01:00
}
2009-05-03 07:37:39 +02:00
// Error message used when dereferencing an iterator that has been erased..
void CheckStl : : dereferenceErasedError ( const Token * tok , const std : : string & itername )
{
2009-07-13 10:16:31 +02:00
reportError ( tok , Severity : : error , " eraseDereference " , " Dereferenced iterator ' " + itername + " ' has been erased " ) ;
2009-05-03 07:37:39 +02:00
}
2009-03-20 20:09:44 +01:00
2009-02-10 20:40:21 +01:00
void CheckStl : : iterators ( )
{
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-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
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 ;
bool validIterator = true ;
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-04-02 07:30:58 +02:00
if ( tok2 - > str ( ) = = " } " )
2009-07-28 20:05:00 +02:00
break ;
2009-07-30 18:49:04 +02:00
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-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-04-02 07:30:58 +02:00
if ( tok2 - > varId ( ) ! = containerId & & tok2 - > tokAt ( 5 ) - > str ( ) ! = " . " )
2009-07-28 20:05:00 +02:00
iteratorsError ( tok2 , tok - > strAt ( 2 ) , tok2 - > str ( ) ) ;
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
2009-08-01 16:37:24 +02:00
tok2 = tok2 - > tokAt ( 4 ) ;
2009-07-28 20:05:00 +02:00
}
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
{
validIterator = true ;
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-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
}
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-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-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-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-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok , " for ( " ) )
2009-02-10 20:56:00 +01:00
continue ;
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
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-04-02 07:30:58 +02:00
for ( const Token * tok2 = tok - > tokAt ( 2 ) ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) )
2009-02-11 06:08:29 +01:00
{
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
{
eraseCheckLoop ( tok2 ) ;
break ;
}
}
}
2010-04-02 07:30:58 +02:00
if ( Token : : Match ( tok , " while ( %var% != %var% . end ( ) " ) )
2009-02-11 06:08:29 +01:00
{
eraseCheckLoop ( tok - > tokAt ( 2 ) ) ;
}
}
}
void CheckStl : : eraseCheckLoop ( const Token * it )
{
const Token * tok = it ;
// Search for the start of the loop body..
int indentlevel = 1 ;
2010-04-02 07:30:58 +02:00
while ( indentlevel > 0 & & 0 ! = ( tok = tok - > next ( ) ) )
2009-02-11 06:08:29 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " ( " )
2009-02-11 06:08:29 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " ) " )
2009-02-11 06:08:29 +01:00
- - indentlevel ;
}
2010-04-02 07:30:58 +02:00
if ( ! Token : : simpleMatch ( tok , " ) { " ) )
2009-02-11 06:08:29 +01:00
return ;
// Parse loop..
2009-12-18 20:55:51 +01:00
// Error if it contains "erase(it)" but neither "break;", "=it" nor "it="
2009-02-11 06:08:29 +01:00
indentlevel = 0 ;
const Token * tok2 = 0 ;
2010-04-02 07:30:58 +02:00
while ( 0 ! = ( tok = tok - > next ( ) ) )
2009-02-11 06:08:29 +01:00
{
2010-04-02 07:30:58 +02:00
if ( tok - > str ( ) = = " { " )
2009-02-11 06:08:29 +01:00
+ + indentlevel ;
2010-04-02 07:30:58 +02:00
else if ( tok - > str ( ) = = " } " )
2009-02-11 06:08:29 +01:00
{
- - indentlevel ;
2010-04-02 07:30:58 +02:00
if ( indentlevel < = 0 )
2009-02-11 06:08:29 +01:00
break ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok , " break|return|goto " ) | |
Token : : simpleMatch ( tok , ( it - > str ( ) + " = " ) . c_str ( ) ) | |
Token : : simpleMatch ( tok , ( " = " + it - > str ( ) ) . c_str ( ) ) )
2009-02-11 06:08:29 +01:00
{
tok2 = 0 ;
break ;
}
2010-04-02 07:30:58 +02:00
else if ( Token : : simpleMatch ( tok , ( " erase ( " + it - > str ( ) + " ) " ) . c_str ( ) ) )
2009-02-11 06:08:29 +01:00
tok2 = tok ;
}
// Write error message..
2010-04-02 07:30:58 +02:00
if ( tok2 )
2009-03-21 17:58:13 +01:00
eraseError ( tok2 ) ;
2009-02-11 06:08:29 +01:00
}
2009-03-21 17:58:13 +01:00
// Error message for bad iterator usage..
void CheckStl : : eraseError ( const Token * tok )
{
2009-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 ;
}
}
}
}
// Iterator becomes 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-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
{
const unsigned int vectorid ( tok2 - > tokAt ( 2 ) - > varId ( ) ) ;
2010-04-02 07:30:58 +02:00
if ( vectorid = = 0 )
2009-10-31 15:27:33 +01:00
continue ;
2009-09-27 09:59:19 +02:00
2009-10-31 15:27:33 +01:00
const Token * pushback = 0 ;
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
{
2009-10-31 15:27:33 +01:00
pushback = 0 ;
break ;
2009-09-27 09:59:19 +02:00
}
2010-04-02 07:30:58 +02:00
else if ( Token : : Match ( tok3 , " %varid% . push_front|push_back|insert ( " , vectorid ) )
2009-07-14 12:40:47 +02:00
{
2009-10-31 15:27:33 +01:00
pushback = 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-02 07:30:58 +02:00
if ( pushback )
2009-10-31 15:27:33 +01:00
invalidIteratorError ( pushback , pushback - > str ( ) , tok2 - > strAt ( 0 ) ) ;
}
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-04-02 07:30:58 +02:00
if ( vectorid > 0 & & Token : : Match ( tok2 , " %varid% . push_front|push_back|insert ( " , 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
// 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
{
2009-10-21 20:15:11 +02:00
reportError ( tok , Severity : : error , " invalidIterator " , " 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
{
2009-07-25 00:36:15 +02:00
reportError ( tok , Severity : : error , " stlBoundries " , container_name + " range check should use != and not < since the order of the pointers isn't guaranteed " ) ;
2009-04-13 17:48:13 +02:00
}
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-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-02-27 21:26:11 +01:00
reportError ( tok , Severity : : possibleStyle , " 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. " ) ;
else
reportError ( tok , Severity : : style , " stlIfFind " , " Suspicious condition. The result of find is an iterator, but it is not properly checked. " ) ;
}
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-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-02-06 19:45:56 +01:00
const bool verbose ( _settings ? _settings - > _verbose : true ) ;
reportError ( tok , Severity : : possibleStyle , " stlSize " , " Use " + varname + " .empty() instead of " + varname + " .size() to guarantee fast code. " + ( verbose ? " size() can take linear time but empty() is guaranteed to take constant time. " : " " ) ) ;
2009-12-19 15:24:59 +01:00
}