2009-01-24 20:28:30 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 Cppcheck team .
2009-01-24 20:28:30 +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-01-24 20:28:30 +01:00
*/
# include "preprocessor.h"
2010-07-21 16:00:12 +02:00
# include "path.h"
2010-07-24 22:12:56 +02:00
# include "errorlogger.h"
2010-07-26 22:05:17 +02:00
# include "settings.h"
2016-07-20 12:21:00 +02:00
# include "simplecpp.h"
2009-01-24 20:28:30 +01:00
# include <algorithm>
# include <sstream>
# include <cstdlib>
# include <cctype>
2009-04-05 20:14:02 +02:00
# include <vector>
2009-07-22 18:47:50 +02:00
# include <set>
2009-01-24 20:28:30 +01:00
2015-12-07 19:54:41 +01:00
/**
* Remove heading and trailing whitespaces from the input parameter .
* If string is all spaces / tabs , return empty string .
* @ param s The string to trim .
*/
static std : : string trim ( const std : : string & s )
{
const std : : string : : size_type beg = s . find_first_not_of ( " \t " ) ;
if ( beg = = std : : string : : npos )
return " " ;
const std : : string : : size_type end = s . find_last_not_of ( " \t " ) ;
return s . substr ( beg , end - beg + 1 ) ;
}
Directive : : Directive ( const std : : string & _file , const int _linenr , const std : : string & _str ) :
file ( _file ) ,
linenr ( _linenr ) ,
str ( _str )
{
str = trim ( str ) ;
}
2011-05-02 14:58:16 +02:00
bool Preprocessor : : missingIncludeFlag ;
2014-05-03 19:31:15 +02:00
bool Preprocessor : : missingSystemIncludeFlag ;
2011-05-02 14:58:16 +02:00
2012-03-27 19:35:41 +02:00
char Preprocessor : : macroChar = char ( 1 ) ;
2015-07-24 13:30:41 +02:00
Preprocessor : : Preprocessor ( Settings & settings , ErrorLogger * errorLogger ) : _settings ( settings ) , _errorLogger ( errorLogger )
2009-06-26 13:19:55 +02:00
{
2016-07-20 12:21:00 +02:00
}
2009-06-26 13:19:55 +02:00
2016-07-20 12:21:00 +02:00
Preprocessor : : ~ Preprocessor ( )
{
for ( std : : map < std : : string , simplecpp : : TokenList * > : : iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it )
delete it - > second ;
2009-06-26 13:19:55 +02:00
}
2009-01-24 20:28:30 +01:00
2016-07-21 07:57:23 +02:00
static void inlineSuppressions ( const simplecpp : : TokenList & tokens , Settings & _settings )
2012-01-02 15:52:19 +01:00
{
2016-07-20 12:21:00 +02:00
std : : list < std : : string > suppressionIDs ;
2012-01-02 15:52:19 +01:00
2016-07-29 08:51:57 +02:00
for ( const simplecpp : : Token * tok = tokens . cfront ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( tok - > comment ) {
std : : istringstream iss ( tok - > str . substr ( 2 ) ) ;
std : : string word ;
iss > > word ;
if ( word ! = " cppcheck-suppress " )
continue ;
iss > > word ;
if ( iss )
suppressionIDs . push_back ( word ) ;
continue ;
2010-04-15 18:37:51 +02:00
}
2013-11-15 19:21:21 +01:00
2016-07-20 12:21:00 +02:00
if ( suppressionIDs . empty ( ) )
continue ;
2013-06-19 17:42:55 +02:00
2016-07-20 12:21:00 +02:00
// Relative filename
std : : string relativeFilename ( tok - > location . file ( ) ) ;
if ( _settings . relativePaths ) {
for ( std : : size_t j = 0U ; j < _settings . basePaths . size ( ) ; + + j ) {
const std : : string bp = _settings . basePaths [ j ] + " / " ;
if ( relativeFilename . compare ( 0 , bp . size ( ) , bp ) = = 0 ) {
relativeFilename = relativeFilename . substr ( bp . size ( ) ) ;
2013-06-19 17:42:55 +02:00
}
}
}
2016-07-20 12:21:00 +02:00
// Add the suppressions.
for ( std : : list < std : : string > : : const_iterator it = suppressionIDs . begin ( ) ; it ! = suppressionIDs . end ( ) ; + + it ) {
_settings . nomsg . addSuppression ( * it , relativeFilename , tok - > location . line ) ;
}
suppressionIDs . clear ( ) ;
}
2013-06-19 17:42:55 +02:00
}
2016-07-21 07:57:23 +02:00
void Preprocessor : : inlineSuppressions ( const simplecpp : : TokenList & tokens )
{
if ( ! _settings . inlineSuppressions )
return ;
: : inlineSuppressions ( tokens , _settings ) ;
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
if ( it - > second )
: : inlineSuppressions ( * it - > second , _settings ) ;
}
}
2016-07-24 14:02:21 +02:00
void Preprocessor : : setDirectives ( const simplecpp : : TokenList & tokens1 )
{
// directive list..
directives . clear ( ) ;
std : : list < const simplecpp : : TokenList * > list ;
list . push_back ( & tokens1 ) ;
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
list . push_back ( it - > second ) ;
}
for ( std : : list < const simplecpp : : TokenList * > : : const_iterator it = list . begin ( ) ; it ! = list . end ( ) ; + + it ) {
2016-07-29 08:51:57 +02:00
for ( const simplecpp : : Token * tok = ( * it ) - > cfront ( ) ; tok ; tok = tok ? tok - > next : nullptr ) {
2016-07-24 14:02:21 +02:00
if ( ( tok - > op ! = ' # ' ) | | ( tok - > previous & & tok - > previous - > location . line = = tok - > location . line ) )
continue ;
if ( tok - > next & & tok - > next - > str = = " endfile " )
continue ;
Directive directive ( tok - > location . file ( ) , tok - > location . line , " " ) ;
for ( const simplecpp : : Token * tok2 = tok ; tok2 & & tok2 - > location . line = = directive . linenr ; tok2 = tok2 - > next ) {
if ( tok2 - > comment )
continue ;
if ( ! directive . str . empty ( ) & & ( tok2 - > location . col > tok2 - > previous - > location . col + tok2 - > previous - > str . size ( ) ) )
directive . str + = ' ' ;
if ( directive . str = = " # " & & tok2 - > str = = " file " )
directive . str + = " include " ;
else
directive . str + = tok2 - > str ;
}
directives . push_back ( directive ) ;
}
}
}
2016-07-21 19:11:49 +02:00
static bool sameline ( const simplecpp : : Token * tok1 , const simplecpp : : Token * tok2 )
{
return tok1 & & tok2 & & tok1 - > location . sameline ( tok2 - > location ) ;
}
2016-08-21 15:01:04 +02:00
static std : : string readcondition ( const simplecpp : : Token * iftok , const std : : set < std : : string > & defined , const std : : set < std : : string > & undefined )
2009-01-24 20:28:30 +01:00
{
2016-07-20 12:21:00 +02:00
const simplecpp : : Token * cond = iftok - > next ;
2016-07-21 19:11:49 +02:00
if ( ! sameline ( iftok , cond ) )
2013-07-24 13:06:59 +02:00
return " " ;
2016-07-21 19:11:49 +02:00
const simplecpp : : Token * next1 = cond - > next ;
const simplecpp : : Token * next2 = next1 ? next1 - > next : nullptr ;
const simplecpp : : Token * next3 = next2 ? next2 - > next : nullptr ;
unsigned int len = 1 ;
if ( sameline ( iftok , next1 ) )
len = 2 ;
if ( sameline ( iftok , next2 ) )
len = 3 ;
if ( sameline ( iftok , next3 ) )
len = 4 ;
if ( len = = 1 & & cond - > str = = " 0 " )
2016-07-20 12:21:00 +02:00
return " 0 " ;
2009-05-13 21:18:02 +02:00
2016-07-21 19:11:49 +02:00
if ( len = = 1 & & cond - > name ) {
2016-07-20 12:21:00 +02:00
if ( defined . find ( cond - > str ) = = defined . end ( ) )
return cond - > str ;
2009-05-13 21:18:02 +02:00
}
2011-02-11 06:30:42 +01:00
2016-07-21 19:11:49 +02:00
if ( len = = 3 & & cond - > op = = ' ( ' & & next1 - > name & & next2 - > op = = ' ) ' ) {
2016-08-21 15:01:04 +02:00
if ( defined . find ( next1 - > str ) = = defined . end ( ) & & undefined . find ( next1 - > str ) = = undefined . end ( ) )
2016-07-21 19:11:49 +02:00
return next1 - > str ;
2016-07-20 12:21:00 +02:00
}
2011-02-11 06:30:42 +01:00
2016-07-21 19:11:49 +02:00
if ( len = = 3 & & cond - > name & & next1 - > str = = " == " & & next2 - > number ) {
2016-07-20 12:21:00 +02:00
if ( defined . find ( cond - > str ) = = defined . end ( ) )
return cond - > str + ' = ' + cond - > next - > next - > str ;
}
2011-03-01 07:50:17 +01:00
2016-07-20 12:21:00 +02:00
std : : set < std : : string > configset ;
2016-07-21 19:11:49 +02:00
for ( ; sameline ( iftok , cond ) ; cond = cond - > next ) {
2016-07-20 12:21:00 +02:00
if ( cond - > op = = ' ! ' )
break ;
2016-07-21 19:11:49 +02:00
if ( cond - > str ! = " defined " )
continue ;
const simplecpp : : Token * dtok = cond - > next ;
if ( ! dtok )
break ;
if ( dtok - > op = = ' ( ' )
dtok = dtok - > next ;
2016-08-21 15:01:04 +02:00
if ( sameline ( iftok , dtok ) & & dtok - > name & & defined . find ( dtok - > str ) = = defined . end ( ) & & undefined . find ( dtok - > str ) = = undefined . end ( ) )
2016-07-21 19:11:49 +02:00
configset . insert ( dtok - > str ) ;
2016-07-20 12:21:00 +02:00
}
std : : string cfg ;
for ( std : : set < std : : string > : : const_iterator it = configset . begin ( ) ; it ! = configset . end ( ) ; + + it ) {
if ( ! cfg . empty ( ) )
cfg + = ' ; ' ;
cfg + = * it ;
}
return cfg ;
2011-02-11 06:30:42 +01:00
}
2016-08-21 13:53:44 +02:00
static bool hasDefine ( const std : : string & userDefines , const std : : string & cfg )
{
std : : string : : size_type pos = 0 ;
while ( pos < userDefines . size ( ) ) {
pos = userDefines . find ( cfg , pos ) ;
if ( pos = = std : : string : : npos )
break ;
const std : : string : : size_type pos2 = pos + cfg . size ( ) ;
if ( ( pos = = 0 | | userDefines [ pos - 1U ] = = ' ; ' ) & & ( pos2 = = userDefines . size ( ) | | userDefines [ pos2 ] = = ' = ' ) )
return true ;
pos = pos2 ;
}
return false ;
}
static std : : string cfg ( const std : : vector < std : : string > & configs , const std : : string & userDefines )
2016-07-20 12:21:00 +02:00
{
std : : set < std : : string > configs2 ( configs . begin ( ) , configs . end ( ) ) ;
std : : string ret ;
for ( std : : set < std : : string > : : const_iterator it = configs2 . begin ( ) ; it ! = configs2 . end ( ) ; + + it ) {
if ( it - > empty ( ) )
continue ;
if ( * it = = " 0 " )
return " " ;
2016-08-21 13:53:44 +02:00
if ( hasDefine ( userDefines , * it ) )
continue ;
2016-07-20 12:21:00 +02:00
if ( ! ret . empty ( ) )
ret + = ' ; ' ;
ret + = * it ;
}
return ret ;
}
2013-09-01 07:13:48 +02:00
2016-08-21 07:45:15 +02:00
static bool isUndefined ( const std : : string & cfg , const std : : set < std : : string > & undefined )
{
for ( std : : string : : size_type pos1 = 0U ; pos1 < cfg . size ( ) ; ) {
const std : : string : : size_type pos2 = cfg . find ( " ; " , pos1 ) ;
const std : : string def = ( pos2 = = std : : string : : npos ) ? cfg . substr ( pos1 ) : cfg . substr ( pos1 , pos2 - pos1 ) ;
std : : string : : size_type eq = def . find ( " = " ) ;
if ( eq = = std : : string : : npos & & undefined . find ( def ) ! = undefined . end ( ) )
return true ;
if ( eq ! = std : : string : : npos & & undefined . find ( def . substr ( 0 , eq ) ) ! = undefined . end ( ) & & def . substr ( eq ) ! = " =0 " )
return true ;
pos1 = ( pos2 = = std : : string : : npos ) ? pos2 : pos2 + 1U ;
}
return false ;
}
2016-08-21 13:53:44 +02:00
static bool getConfigsElseIsFalse ( const std : : vector < std : : string > & configs_if , const std : : string & userDefines )
{
for ( unsigned int i = 0 ; i < configs_if . size ( ) ; + + i ) {
if ( hasDefine ( userDefines , configs_if [ i ] ) )
return true ;
}
return false ;
}
static const simplecpp : : Token * gotoEndIf ( const simplecpp : : Token * cmdtok )
{
int level = 0 ;
while ( nullptr ! = ( cmdtok = cmdtok - > next ) ) {
if ( cmdtok - > op = = ' # ' & & ! sameline ( cmdtok - > previous , cmdtok ) & & sameline ( cmdtok , cmdtok - > next ) ) {
if ( cmdtok - > next - > str . compare ( 0 , 2 , " if " ) = = 0 )
+ + level ;
else if ( cmdtok - > next - > str = = " endif " ) {
- - level ;
if ( level < 0 )
return cmdtok ;
}
}
}
return nullptr ;
}
static void getConfigs ( const simplecpp : : TokenList & tokens , std : : set < std : : string > & defined , const std : : string & userDefines , const std : : set < std : : string > & undefined , std : : set < std : : string > & ret )
2013-09-01 07:13:48 +02:00
{
2016-07-20 12:21:00 +02:00
std : : vector < std : : string > configs_if ;
std : : vector < std : : string > configs_ifndef ;
2016-07-29 08:51:57 +02:00
for ( const simplecpp : : Token * tok = tokens . cfront ( ) ; tok ; tok = tok - > next ) {
2016-07-21 19:11:49 +02:00
if ( tok - > op ! = ' # ' | | sameline ( tok - > previous , tok ) )
2013-09-01 07:13:48 +02:00
continue ;
2016-07-21 19:11:49 +02:00
const simplecpp : : Token * cmdtok = tok - > next ;
if ( ! sameline ( tok , cmdtok ) )
2016-07-20 12:21:00 +02:00
continue ;
2016-07-21 19:11:49 +02:00
if ( cmdtok - > str = = " ifdef " | | cmdtok - > str = = " ifndef " | | cmdtok - > str = = " if " ) {
2016-07-20 12:21:00 +02:00
std : : string config ;
2016-07-21 19:11:49 +02:00
if ( cmdtok - > str = = " ifdef " | | cmdtok - > str = = " ifndef " ) {
const simplecpp : : Token * expr1 = cmdtok - > next ;
if ( sameline ( tok , expr1 ) & & expr1 - > name & & ! sameline ( tok , expr1 - > next ) )
config = expr1 - > str ;
2016-07-20 12:21:00 +02:00
if ( defined . find ( config ) ! = defined . end ( ) )
config . clear ( ) ;
2016-07-21 19:11:49 +02:00
} else if ( cmdtok - > str = = " if " ) {
2016-08-21 15:01:04 +02:00
config = readcondition ( cmdtok , defined , undefined ) ;
2016-07-20 12:21:00 +02:00
}
2016-08-21 07:45:15 +02:00
// skip undefined configurations..
if ( isUndefined ( config , undefined ) )
2016-07-28 19:22:59 +02:00
config . clear ( ) ;
2016-08-21 07:45:15 +02:00
2016-07-21 19:11:49 +02:00
configs_if . push_back ( ( cmdtok - > str = = " ifndef " ) ? std : : string ( ) : config ) ;
configs_ifndef . push_back ( ( cmdtok - > str = = " ifndef " ) ? config : std : : string ( ) ) ;
2016-08-21 13:53:44 +02:00
ret . insert ( cfg ( configs_if , userDefines ) ) ;
} else if ( cmdtok - > str = = " elif " | | cmdtok - > str = = " else " ) {
if ( getConfigsElseIsFalse ( configs_if , userDefines ) ) {
tok = gotoEndIf ( tok ) ;
if ( ! tok )
break ;
tok = tok - > previous ;
continue ;
}
2016-07-20 20:39:03 +02:00
if ( ! configs_if . empty ( ) )
configs_if . pop_back ( ) ;
2016-08-21 13:53:44 +02:00
if ( cmdtok - > str = = " elif " ) {
2016-08-21 15:01:04 +02:00
std : : string config = readcondition ( cmdtok , defined , undefined ) ;
2016-08-21 13:53:44 +02:00
if ( isUndefined ( config , undefined ) )
config . clear ( ) ;
configs_if . push_back ( config ) ;
ret . insert ( cfg ( configs_if , userDefines ) ) ;
} else if ( ! configs_ifndef . empty ( ) ) {
2016-07-23 14:40:01 +02:00
configs_if . push_back ( configs_ifndef . back ( ) ) ;
2016-08-21 13:53:44 +02:00
ret . insert ( cfg ( configs_if , userDefines ) ) ;
2016-07-23 14:40:01 +02:00
}
2016-07-21 19:11:49 +02:00
} else if ( cmdtok - > str = = " endif " & & ! sameline ( tok , cmdtok - > next ) ) {
2016-07-20 12:21:00 +02:00
if ( ! configs_if . empty ( ) )
configs_if . pop_back ( ) ;
if ( ! configs_ifndef . empty ( ) )
configs_ifndef . pop_back ( ) ;
2016-07-21 19:11:49 +02:00
} else if ( cmdtok - > str = = " define " & & sameline ( tok , cmdtok - > next ) & & cmdtok - > next - > name ) {
defined . insert ( cmdtok - > next - > str ) ;
2016-07-20 12:21:00 +02:00
}
}
}
std : : set < std : : string > Preprocessor : : getConfigs ( const simplecpp : : TokenList & tokens ) const
{
std : : set < std : : string > ret ;
ret . insert ( " " ) ;
2016-07-29 08:51:57 +02:00
if ( ! tokens . cfront ( ) )
2016-07-20 12:21:00 +02:00
return ret ;
std : : set < std : : string > defined ;
defined . insert ( " __cplusplus " ) ;
2016-08-21 13:53:44 +02:00
: : getConfigs ( tokens , defined , _settings . userDefines , _settings . userUndefs , ret ) ;
2016-07-20 12:21:00 +02:00
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it )
2016-08-21 13:53:44 +02:00
: : getConfigs ( * ( it - > second ) , defined , _settings . userDefines , _settings . userUndefs , ret ) ;
2013-09-01 07:13:48 +02:00
2016-07-20 12:21:00 +02:00
return ret ;
2013-09-01 07:13:48 +02:00
}
2009-05-13 21:18:02 +02:00
2016-07-20 12:21:00 +02:00
void Preprocessor : : preprocess ( std : : istream & istr , std : : map < std : : string , std : : string > & result , const std : : string & filename , const std : : list < std : : string > & includePaths )
2009-10-04 07:25:30 +02:00
{
2016-07-20 12:21:00 +02:00
( void ) includePaths ;
2009-10-04 07:25:30 +02:00
2016-07-20 12:21:00 +02:00
simplecpp : : OutputList outputList ;
std : : vector < std : : string > files ;
const simplecpp : : TokenList tokens1 ( istr , files , filename , & outputList ) ;
2009-10-04 07:25:30 +02:00
2009-09-11 21:22:41 +02:00
2016-07-20 12:21:00 +02:00
const std : : set < std : : string > configs = getConfigs ( tokens1 ) ;
2009-09-11 21:22:41 +02:00
2016-07-20 12:21:00 +02:00
for ( std : : set < std : : string > : : const_iterator it = configs . begin ( ) ; it ! = configs . end ( ) ; + + it ) {
2015-07-24 13:30:41 +02:00
if ( _settings . userUndefs . find ( * it ) = = _settings . userUndefs . end ( ) ) {
2016-07-20 12:21:00 +02:00
result [ * it ] = getcode ( tokens1 , * it , files , false ) ;
2013-06-08 16:46:54 +02:00
}
2011-11-30 20:24:01 +01:00
}
2009-01-24 20:28:30 +01:00
}
std : : string Preprocessor : : removeSpaceNearNL ( const std : : string & str )
{
std : : string tmp ;
2015-03-12 21:16:54 +01:00
char prev = ' \n ' ; // treat start of file as newline
2014-07-07 21:25:30 +02:00
for ( std : : size_t i = 0 ; i < str . size ( ) ; i + + ) {
2010-04-02 07:30:58 +02:00
if ( str [ i ] = = ' ' & &
2015-03-12 21:16:54 +01:00
( prev = = ' \n ' | |
i + 1 > = str . size ( ) | | // treat end of file as newline
str [ i + 1 ] = = ' \n '
2010-04-02 07:30:58 +02:00
)
2011-10-13 20:53:06 +02:00
) {
2009-01-24 20:28:30 +01:00
// Ignore space that has new line in either side of it
2011-10-13 20:53:06 +02:00
} else {
2009-01-24 20:28:30 +01:00
tmp . append ( 1 , str [ i ] ) ;
2010-08-06 19:38:21 +02:00
prev = str [ i ] ;
2009-01-24 20:28:30 +01:00
}
}
return tmp ;
}
2010-04-15 22:45:38 +02:00
void Preprocessor : : preprocessWhitespaces ( std : : string & processedFile )
2009-01-24 20:28:30 +01:00
{
// Replace all tabs with spaces..
std : : replace ( processedFile . begin ( ) , processedFile . end ( ) , ' \t ' , ' ' ) ;
// Remove space characters that are after or before new line character
processedFile = removeSpaceNearNL ( processedFile ) ;
2010-04-15 22:45:38 +02:00
}
void Preprocessor : : preprocess ( std : : istream & srcCodeStream , std : : string & processedFile , std : : list < std : : string > & resultConfigurations , const std : : string & filename , const std : : list < std : : string > & includePaths )
{
2016-07-20 12:21:00 +02:00
( void ) includePaths ;
2012-12-27 16:52:31 +01:00
2010-09-03 13:30:49 +02:00
if ( file0 . empty ( ) )
file0 = filename ;
2016-07-20 12:21:00 +02:00
simplecpp : : OutputList outputList ;
std : : vector < std : : string > files ;
const simplecpp : : TokenList tokens1 ( srcCodeStream , files , filename , & outputList ) ;
2012-12-27 16:52:31 +01:00
2016-07-20 12:21:00 +02:00
const std : : set < std : : string > configs = getConfigs ( tokens1 ) ;
for ( std : : set < std : : string > : : const_iterator it = configs . begin ( ) ; it ! = configs . end ( ) ; + + it )
resultConfigurations . push_back ( * it ) ;
2012-12-27 16:52:31 +01:00
2016-07-20 12:21:00 +02:00
processedFile = tokens1 . stringify ( ) ;
}
2015-07-24 13:30:41 +02:00
2016-07-20 12:21:00 +02:00
static void splitcfg ( const std : : string & cfg , std : : list < std : : string > & defines , const std : : string & defaultValue )
{
2016-08-23 17:27:07 +02:00
for ( std : : string : : size_type defineStartPos = 0U ; defineStartPos < cfg . size ( ) ; ) {
const std : : string : : size_type defineEndPos = cfg . find ( " ; " , defineStartPos ) ;
std : : string def = ( defineEndPos = = std : : string : : npos ) ? cfg . substr ( defineStartPos ) : cfg . substr ( defineStartPos , defineEndPos - defineStartPos ) ;
2016-07-20 12:21:00 +02:00
if ( ! defaultValue . empty ( ) & & def . find ( " = " ) = = std : : string : : npos )
def + = ' = ' + defaultValue ;
defines . push_back ( def ) ;
2016-08-23 17:27:07 +02:00
if ( defineEndPos = = std : : string : : npos )
break ;
defineStartPos = defineEndPos + 1U ;
2015-07-24 13:30:41 +02:00
}
2016-07-20 12:21:00 +02:00
}
2015-07-24 13:30:41 +02:00
2016-08-06 09:15:09 +02:00
static simplecpp : : DUI createDUI ( const Settings & _settings , const std : : string & cfg , const std : : string & filename )
2016-07-20 12:21:00 +02:00
{
simplecpp : : DUI dui ;
2012-12-27 16:52:31 +01:00
2016-07-20 12:21:00 +02:00
splitcfg ( _settings . userDefines , dui . defines , " 1 " ) ;
2016-08-06 09:15:09 +02:00
if ( ! cfg . empty ( ) )
splitcfg ( cfg , dui . defines , " " ) ;
2016-07-20 12:21:00 +02:00
for ( std : : vector < std : : string > : : const_iterator it = _settings . library . defines . begin ( ) ; it ! = _settings . library . defines . end ( ) ; + + it ) {
if ( it - > compare ( 0 , 8 , " #define " ) ! = 0 )
continue ;
std : : string s = it - > substr ( 8 ) ;
std : : string : : size_type pos = s . find_first_of ( " ( " ) ;
if ( pos = = std : : string : : npos ) {
dui . defines . push_back ( s ) ;
continue ;
}
if ( s [ pos ] = = ' ' ) {
s [ pos ] = ' = ' ;
} else {
s [ s . find ( " ) " ) + 1 ] = ' = ' ;
2009-07-22 20:11:27 +02:00
}
2016-07-20 12:21:00 +02:00
dui . defines . push_back ( s ) ;
2009-07-22 20:11:27 +02:00
}
2016-07-20 12:21:00 +02:00
if ( Path : : isCPP ( filename ) )
dui . defines . push_back ( " __cplusplus " ) ;
2011-10-24 20:59:46 +02:00
2016-08-06 09:15:09 +02:00
dui . undefined = _settings . userUndefs ; // -U
dui . includePaths = _settings . includePaths ; // -I
dui . includes = _settings . userIncludes ; // --include
return dui ;
}
2016-08-06 10:22:58 +02:00
static bool hasErrors ( const simplecpp : : OutputList & outputList )
2016-08-06 09:15:09 +02:00
{
for ( simplecpp : : OutputList : : const_iterator it = outputList . begin ( ) ; it ! = outputList . end ( ) ; + + it ) {
switch ( it - > type ) {
case simplecpp : : Output : : ERROR :
case simplecpp : : Output : : INCLUDE_NESTED_TOO_DEEPLY :
case simplecpp : : Output : : SYNTAX_ERROR :
return true ;
case simplecpp : : Output : : WARNING :
case simplecpp : : Output : : MISSING_HEADER :
2016-09-03 12:29:45 +02:00
case simplecpp : : Output : : PORTABILITY_BACKSLASH :
2016-08-06 09:15:09 +02:00
break ;
} ;
}
return false ;
}
2009-01-24 20:28:30 +01:00
2016-08-06 09:15:09 +02:00
void Preprocessor : : loadFiles ( const simplecpp : : TokenList & rawtokens , std : : vector < std : : string > & files )
{
const simplecpp : : DUI dui = createDUI ( _settings , " " , files [ 0 ] ) ;
2009-01-24 20:28:30 +01:00
2016-07-20 12:21:00 +02:00
simplecpp : : OutputList outputList ;
2012-07-18 20:57:00 +02:00
2016-07-20 12:21:00 +02:00
tokenlists = simplecpp : : load ( rawtokens , files , dui , & outputList ) ;
2009-01-24 20:28:30 +01:00
}
2016-07-21 07:48:17 +02:00
void Preprocessor : : removeComments ( )
{
for ( std : : map < std : : string , simplecpp : : TokenList * > : : iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
if ( it - > second )
it - > second - > removeComments ( ) ;
}
}
2016-07-25 14:52:23 +02:00
void Preprocessor : : setPlatformInfo ( simplecpp : : TokenList * tokens ) const
{
tokens - > sizeOfType [ " bool " ] = _settings . sizeof_bool ;
tokens - > sizeOfType [ " short " ] = _settings . sizeof_short ;
tokens - > sizeOfType [ " int " ] = _settings . sizeof_int ;
tokens - > sizeOfType [ " long " ] = _settings . sizeof_long ;
tokens - > sizeOfType [ " long long " ] = _settings . sizeof_long_long ;
tokens - > sizeOfType [ " float " ] = _settings . sizeof_float ;
tokens - > sizeOfType [ " double " ] = _settings . sizeof_double ;
tokens - > sizeOfType [ " long double " ] = _settings . sizeof_long_double ;
tokens - > sizeOfType [ " bool * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " short * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " int * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " long * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " long long * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " float * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " double * " ] = _settings . sizeof_pointer ;
tokens - > sizeOfType [ " long double * " ] = _settings . sizeof_pointer ;
}
2016-07-20 12:21:00 +02:00
std : : string Preprocessor : : getcode ( const simplecpp : : TokenList & tokens1 , const std : : string & cfg , std : : vector < std : : string > & files , const bool writeLocations )
2012-07-18 20:57:00 +02:00
{
2016-07-20 12:21:00 +02:00
const std : : string filename ( files [ 0 ] ) ;
2009-01-24 20:28:30 +01:00
2016-08-06 09:15:09 +02:00
const simplecpp : : DUI dui = createDUI ( _settings , cfg , filename ) ;
2009-01-24 20:28:30 +01:00
2016-07-20 12:21:00 +02:00
simplecpp : : OutputList outputList ;
std : : list < simplecpp : : MacroUsage > macroUsage ;
2016-07-21 19:42:26 +02:00
simplecpp : : TokenList tokens2 ( files ) ;
simplecpp : : preprocess ( tokens2 , tokens1 , files , tokenlists , dui , & outputList , & macroUsage ) ;
2009-01-24 20:28:30 +01:00
2016-07-20 12:21:00 +02:00
bool showerror = ( ! _settings . userDefines . empty ( ) & & ! _settings . force ) ;
2016-08-06 09:15:09 +02:00
reportOutput ( outputList , showerror ) ;
if ( hasErrors ( outputList ) )
return " " ;
2009-06-26 13:19:55 +02:00
2016-07-20 12:21:00 +02:00
// ensure that guessed define macros without value are not used in the code
2016-08-01 20:09:41 +02:00
if ( ! validateCfg ( cfg , macroUsage ) )
return " " ;
2012-01-21 12:51:54 +01:00
2016-07-20 12:21:00 +02:00
// assembler code locations..
std : : set < simplecpp : : Location > assemblerLocations ;
for ( std : : list < Directive > : : const_iterator dirIt = directives . begin ( ) ; dirIt ! = directives . end ( ) ; + + dirIt ) {
const Directive & d1 = * dirIt ;
if ( d1 . str . compare ( 0 , 11 , " #pragma asm " ) ! = 0 )
continue ;
std : : list < Directive > : : const_iterator dirIt2 = dirIt ;
+ + dirIt2 ;
if ( dirIt2 = = directives . end ( ) )
continue ;
2011-12-09 21:57:06 +01:00
2016-07-20 12:21:00 +02:00
const Directive & d2 = * dirIt2 ;
if ( d2 . str . compare ( 0 , 14 , " #pragma endasm " ) ! = 0 | | d1 . file ! = d2 . file )
continue ;
2011-10-17 20:12:46 +02:00
2016-07-20 12:21:00 +02:00
simplecpp : : Location loc ( files ) ;
loc . fileIndex = ~ 0U ;
loc . col = 0U ;
for ( unsigned int i = 0 ; i < files . size ( ) ; + + i ) {
if ( files [ i ] = = d1 . file ) {
loc . fileIndex = i ;
break ;
2011-10-24 19:51:00 +02:00
}
2016-07-20 12:21:00 +02:00
}
2011-10-24 19:51:00 +02:00
2016-07-20 12:21:00 +02:00
for ( unsigned int linenr = d1 . linenr + 1U ; linenr < d2 . linenr ; linenr + + ) {
loc . line = linenr ;
assemblerLocations . insert ( loc ) ;
}
}
2011-11-03 19:05:48 +01:00
2016-07-20 12:21:00 +02:00
unsigned int prevfile = 0 ;
unsigned int line = 1 ;
std : : ostringstream ret ;
2016-07-29 08:51:57 +02:00
for ( const simplecpp : : Token * tok = tokens2 . cfront ( ) ; tok ; tok = tok - > next ) {
2016-07-20 12:21:00 +02:00
if ( writeLocations & & tok - > location . fileIndex ! = prevfile ) {
ret < < " \n #line " < < tok - > location . line < < " \" " < < tok - > location . file ( ) < < " \" \n " ;
prevfile = tok - > location . fileIndex ;
line = tok - > location . line ;
}
2011-11-03 19:05:48 +01:00
2016-07-20 12:21:00 +02:00
if ( tok - > previous & & line = = tok - > location . line )
ret < < ' ' ;
bool newline = false ;
while ( tok - > location . line > line ) {
ret < < ' \n ' ;
line + + ;
newline = true ;
}
if ( newline ) {
simplecpp : : Location loc = tok - > location ;
loc . col = 0U ;
if ( assemblerLocations . find ( loc ) ! = assemblerLocations . end ( ) ) {
ret < < " asm(); " ;
while ( assemblerLocations . find ( loc ) ! = assemblerLocations . end ( ) ) {
loc . line + + ;
}
while ( tok & & tok - > location . line < loc . line )
tok = tok - > next ;
if ( ! tok )
break ;
while ( line < tok - > location . line ) {
ret < < ' \n ' ;
+ + line ;
2011-11-03 19:05:48 +01:00
}
2016-07-20 12:21:00 +02:00
}
}
if ( ! tok - > macro . empty ( ) )
ret < < Preprocessor : : macroChar ;
ret < < tok - > str ;
}
2011-11-03 19:05:48 +01:00
2016-07-20 12:21:00 +02:00
return ret . str ( ) ;
}
2011-11-03 19:05:48 +01:00
2016-07-20 12:21:00 +02:00
std : : string Preprocessor : : getcode ( const std : : string & filedata , const std : : string & cfg , const std : : string & filename )
{
simplecpp : : OutputList outputList ;
std : : vector < std : : string > files ;
2013-08-18 18:04:06 +02:00
2016-07-20 12:21:00 +02:00
std : : istringstream istr ( filedata ) ;
2016-07-24 14:02:21 +02:00
simplecpp : : TokenList tokens1 ( istr , files , Path : : simplifyPath ( filename ) , & outputList ) ;
2016-07-20 12:21:00 +02:00
inlineSuppressions ( tokens1 ) ;
2016-07-24 14:02:21 +02:00
tokens1 . removeComments ( ) ;
removeComments ( ) ;
setDirectives ( tokens1 ) ;
2011-11-03 19:05:48 +01:00
2016-08-06 09:15:09 +02:00
reportOutput ( outputList , true ) ;
2016-08-06 13:28:24 +02:00
2016-08-06 09:15:09 +02:00
if ( hasErrors ( outputList ) )
return " " ;
return getcode ( tokens1 , cfg , files , filedata . find ( " #file " ) ! = std : : string : : npos ) ;
}
void Preprocessor : : reportOutput ( const simplecpp : : OutputList & outputList , bool showerror )
{
2016-07-20 12:21:00 +02:00
for ( simplecpp : : OutputList : : const_iterator it = outputList . begin ( ) ; it ! = outputList . end ( ) ; + + it ) {
2016-07-21 12:47:00 +02:00
switch ( it - > type ) {
case simplecpp : : Output : : ERROR :
2016-08-06 09:15:09 +02:00
if ( it - > msg . compare ( 0 , 6 , " #error " ) ! = 0 | | showerror )
error ( it - > location . file ( ) , it - > location . line , it - > msg ) ;
break ;
2016-07-21 12:47:00 +02:00
case simplecpp : : Output : : WARNING :
2016-09-03 12:29:45 +02:00
case simplecpp : : Output : : PORTABILITY_BACKSLASH :
2016-07-21 12:47:00 +02:00
break ;
2016-07-31 12:10:30 +02:00
case simplecpp : : Output : : MISSING_HEADER : {
2016-07-21 12:47:00 +02:00
const std : : string : : size_type pos1 = it - > msg . find_first_of ( " < \" " ) ;
const std : : string : : size_type pos2 = it - > msg . find_first_of ( " > \" " , pos1 + 1U ) ;
if ( pos1 < pos2 & & pos2 ! = std : : string : : npos )
missingInclude ( it - > location . file ( ) , it - > location . line , it - > msg . substr ( pos1 + 1 , pos2 - pos1 - 1 ) , it - > msg [ pos1 ] = = ' \" ' ? UserHeader : SystemHeader ) ;
2011-10-17 20:12:46 +02:00
}
2016-07-21 12:47:00 +02:00
break ;
2016-08-06 09:15:09 +02:00
case simplecpp : : Output : : INCLUDE_NESTED_TOO_DEEPLY :
case simplecpp : : Output : : SYNTAX_ERROR :
error ( it - > location . file ( ) , it - > location . line , it - > msg ) ;
break ;
2016-07-21 12:47:00 +02:00
} ;
2011-10-17 20:12:46 +02:00
}
}
2016-07-20 12:21:00 +02:00
void Preprocessor : : error ( const std : : string & filename , unsigned int linenr , const std : : string & msg )
2009-01-24 20:28:30 +01:00
{
2016-07-20 12:21:00 +02:00
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locationList ;
if ( ! filename . empty ( ) ) {
ErrorLogger : : ErrorMessage : : FileLocation loc ( filename , linenr ) ;
locationList . push_back ( loc ) ;
2015-01-03 18:22:52 +01:00
}
2016-07-20 12:21:00 +02:00
_errorLogger - > reportErr ( ErrorLogger : : ErrorMessage ( locationList ,
2016-07-26 16:27:55 +02:00
file0 ,
2016-07-20 12:21:00 +02:00
Severity : : error ,
msg ,
" preprocessorErrorDirective " ,
false ) ) ;
}
2011-01-06 20:01:09 +01:00
2010-12-29 12:43:29 +01:00
// Report that include is missing
2013-03-13 06:48:33 +01:00
void Preprocessor : : missingInclude ( const std : : string & filename , unsigned int linenr , const std : : string & header , HeaderTypes headerType )
2010-12-29 12:43:29 +01:00
{
2014-05-03 19:31:15 +02:00
const std : : string fname = Path : : fromNativeSeparators ( filename ) ;
2015-07-24 13:30:41 +02:00
if ( _settings . nomsg . isSuppressed ( " missingInclude " , fname , linenr ) )
2014-05-03 19:31:15 +02:00
return ;
2015-07-24 13:30:41 +02:00
if ( headerType = = SystemHeader & & _settings . nomsg . isSuppressed ( " missingIncludeSystem " , fname , linenr ) )
2014-05-03 19:31:15 +02:00
return ;
2013-03-13 06:48:33 +01:00
2014-05-03 19:31:15 +02:00
if ( headerType = = SystemHeader )
missingSystemIncludeFlag = true ;
else
missingIncludeFlag = true ;
2015-07-24 13:30:41 +02:00
if ( _errorLogger & & _settings . checkConfiguration ) {
2014-05-03 19:31:15 +02:00
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locationList ;
if ( ! filename . empty ( ) ) {
ErrorLogger : : ErrorMessage : : FileLocation loc ;
loc . line = linenr ;
loc . setfile ( Path : : toNativeSeparators ( filename ) ) ;
locationList . push_back ( loc ) ;
}
2016-07-26 16:27:55 +02:00
ErrorLogger : : ErrorMessage errmsg ( locationList , file0 , Severity : : information ,
2014-05-03 19:31:15 +02:00
( headerType = = SystemHeader ) ?
" Include file: < " + header + " > not found. Please note: Cppcheck does not need standard library headers to get proper results. " :
" Include file: \" " + header + " \" not found. " ,
( headerType = = SystemHeader ) ? " missingIncludeSystem " : " missingInclude " ,
false ) ;
_errorLogger - > reportInfo ( errmsg ) ;
2010-12-29 12:43:29 +01:00
}
}
2016-08-01 20:09:41 +02:00
bool Preprocessor : : validateCfg ( const std : : string & cfg , const std : : list < simplecpp : : MacroUsage > & macroUsageList )
2012-07-10 20:29:04 +02:00
{
2016-08-01 20:09:41 +02:00
bool ret = true ;
std : : list < std : : string > defines ;
splitcfg ( cfg , defines , std : : string ( ) ) ;
for ( std : : list < std : : string > : : const_iterator defineIt = defines . begin ( ) ; defineIt ! = defines . end ( ) ; + + defineIt ) {
if ( defineIt - > find ( " = " ) ! = std : : string : : npos )
continue ;
const std : : string macroName ( defineIt - > substr ( 0 , defineIt - > find ( " ( " ) ) ) ;
for ( std : : list < simplecpp : : MacroUsage > : : const_iterator usageIt = macroUsageList . begin ( ) ; usageIt ! = macroUsageList . end ( ) ; + + usageIt ) {
const simplecpp : : MacroUsage & mu = * usageIt ;
if ( mu . macroName ! = macroName )
continue ;
bool directiveLocation = false ;
for ( std : : list < Directive > : : const_iterator dirIt = directives . begin ( ) ; dirIt ! = directives . end ( ) ; + + dirIt ) {
if ( mu . useLocation . file ( ) = = dirIt - > file & & mu . useLocation . line = = dirIt - > linenr ) {
directiveLocation = true ;
break ;
2012-07-11 18:29:33 +02:00
}
}
2016-08-01 20:09:41 +02:00
if ( ! directiveLocation ) {
if ( _settings . isEnabled ( " information " ) )
validateCfgError ( mu . useLocation . file ( ) , mu . useLocation . line , cfg , macroName ) ;
ret = false ;
2012-07-11 18:29:33 +02:00
}
2012-07-10 20:29:04 +02:00
}
}
2016-08-01 20:09:41 +02:00
return ret ;
2012-07-10 20:29:04 +02:00
}
2016-08-01 20:09:41 +02:00
void Preprocessor : : validateCfgError ( const std : : string & file , const unsigned int line , const std : : string & cfg , const std : : string & macro )
2012-07-10 20:29:04 +02:00
{
const std : : string id = " ConfigurationNotChecked " ;
2012-11-03 11:25:40 +01:00
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > locationList ;
2016-08-01 20:09:41 +02:00
ErrorLogger : : ErrorMessage : : FileLocation loc ( file , line ) ;
2012-11-03 11:25:40 +01:00
locationList . push_back ( loc ) ;
2016-07-26 16:27:55 +02:00
ErrorLogger : : ErrorMessage errmsg ( locationList , file0 , Severity : : information , " Skipping configuration ' " + cfg + " ' since the value of ' " + macro + " ' is unknown. Use -D if you want to check it. You can use -U to skip it explicitly. " , id , false ) ;
2012-07-10 20:29:04 +02:00
_errorLogger - > reportInfo ( errmsg ) ;
}
2010-12-29 12:43:29 +01:00
void Preprocessor : : getErrorMessages ( ErrorLogger * errorLogger , const Settings * settings )
2010-09-03 13:30:49 +02:00
{
2010-12-29 12:43:29 +01:00
Settings settings2 ( * settings ) ;
2015-07-24 13:30:41 +02:00
Preprocessor preprocessor ( settings2 , errorLogger ) ;
2013-03-13 19:50:50 +01:00
settings2 . checkConfiguration = true ;
2013-03-13 06:48:33 +01:00
preprocessor . missingInclude ( " " , 1 , " " , UserHeader ) ;
preprocessor . missingInclude ( " " , 1 , " " , SystemHeader ) ;
2016-08-01 20:09:41 +02:00
preprocessor . validateCfgError ( " " , 1 , " X " , " X " ) ;
2010-12-29 12:43:29 +01:00
preprocessor . error ( " " , 1 , " #error message " ) ; // #error ..
2010-09-03 13:30:49 +02:00
}
2015-12-07 19:54:41 +01:00
void Preprocessor : : dump ( std : : ostream & out ) const
{
// Create a xml directive dump.
// The idea is not that this will be readable for humans. It's a
// data dump that 3rd party tools could load and get useful info from.
std : : list < Directive > : : const_iterator it ;
out < < " <directivelist> " < < std : : endl ;
for ( it = directives . begin ( ) ; it ! = directives . end ( ) ; + + it ) {
out < < " <directive "
< < " file= \" " < < it - > file < < " \" "
< < " linenr= \" " < < it - > linenr < < " \" "
// str might contain characters such as '"', '<' or '>' which
// could result in invalid XML, so run it through toxml().
< < " str= \" " < < ErrorLogger : : toxml ( it - > str ) < < " \" /> " < < std : : endl ;
}
out < < " </directivelist> " < < std : : endl ;
}