2009-01-24 20:28:30 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2018-01-14 15:37:52 +01:00
* Copyright ( C ) 2007 - 2017 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"
2017-05-27 04:33:47 +02:00
2010-07-24 22:12:56 +02:00
# include "errorlogger.h"
2017-05-27 04:33:47 +02:00
# include "library.h"
# include "path.h"
2010-07-26 22:05:17 +02:00
# include "settings.h"
2017-05-27 04:33:47 +02:00
# include "simplecpp.h"
# include "suppressions.h"
2009-01-24 20:28:30 +01:00
# include <algorithm>
2016-10-29 15:55:03 +02:00
# include <cstdint>
2017-05-27 04:33:47 +02:00
# include <cstring>
# include <utility>
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 ) ,
2017-03-26 11:40:53 +02:00
linenr ( _linenr ) ,
str ( trim ( _str ) )
2015-12-07 19:54:41 +01:00
{
}
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
}
2018-04-11 08:18:00 +02:00
namespace {
struct BadInlineSuppression {
BadInlineSuppression ( const simplecpp : : Location & l , const std : : string & msg ) : location ( l ) , errmsg ( msg ) { }
simplecpp : : Location location ;
std : : string errmsg ;
} ;
}
2009-01-24 20:28:30 +01:00
2018-04-11 08:18:00 +02:00
static void inlineSuppressions ( const simplecpp : : TokenList & tokens , Settings & _settings , std : : list < BadInlineSuppression > * bad )
2012-01-02 15:52:19 +01:00
{
2018-04-09 11:50:59 +02:00
std : : list < Suppressions : : Suppression > inlineSuppressions ;
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 ) {
2018-04-09 11:50:59 +02:00
Suppressions : : Suppression s ;
2018-04-11 08:18:00 +02:00
std : : string errmsg ;
2018-05-14 13:00:22 +02:00
if ( ! s . parseComment ( tok - > str ( ) , & errmsg ) )
2018-04-09 11:50:59 +02:00
continue ;
2018-04-11 08:18:00 +02:00
if ( ! errmsg . empty ( ) )
bad - > push_back ( BadInlineSuppression ( tok - > location , errmsg ) ) ;
if ( ! s . errorId . empty ( ) )
inlineSuppressions . push_back ( s ) ;
2016-07-20 12:21:00 +02:00
continue ;
2010-04-15 18:37:51 +02:00
}
2013-11-15 19:21:21 +01:00
2018-04-09 11:50:59 +02:00
if ( inlineSuppressions . empty ( ) )
2016-07-20 12:21:00 +02:00
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
}
}
}
2018-04-09 11:50:59 +02:00
relativeFilename = Path : : simplifyPath ( relativeFilename ) ;
2013-06-19 17:42:55 +02:00
2016-07-20 12:21:00 +02:00
// Add the suppressions.
2018-04-09 11:50:59 +02:00
for ( Suppressions : : Suppression & suppr : inlineSuppressions ) {
suppr . fileName = relativeFilename ;
suppr . lineNumber = tok - > location . line ;
_settings . nomsg . addSuppression ( suppr ) ;
2016-07-20 12:21:00 +02:00
}
2018-04-09 11:50:59 +02:00
inlineSuppressions . clear ( ) ;
2016-07-20 12:21:00 +02:00
}
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 ;
2018-04-11 08:18:00 +02:00
std : : list < BadInlineSuppression > err ;
: : inlineSuppressions ( tokens , _settings , & err ) ;
2016-07-21 07:57:23 +02:00
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
if ( it - > second )
2018-04-11 08:18:00 +02:00
: : inlineSuppressions ( * it - > second , _settings , & err ) ;
}
for ( const BadInlineSuppression & bad : err ) {
error ( bad . location . file ( ) , bad . location . line , bad . errmsg ) ;
2016-07-21 07:57:23 +02:00
}
}
lib: fix a bunch of warnings about differing function arguments in definition and declaration.
[lib/token.h:72] -> [lib/token.cpp:36]: (style, inconclusive) Function 'Token' argument 1 names different: declaration 'tokensBack' definition 't'.
[lib/token.h:445] -> [lib/token.cpp:497]: (style, inconclusive) Function 'multiCompare' argument 1 names different: declaration 'needle' definition 'tok'.
[lib/checkio.h:73] -> [lib/checkio.cpp:1385]: (style, inconclusive) Function 'ArgumentInfo' argument 3 names different: declaration 'isCPP' definition '_isCPP'.
[lib/checkother.h:216] -> [lib/checkother.cpp:2136]: (style, inconclusive) Function 'checkComparisonFunctionIsAlwaysTrueOrFalseError' argument 2 names different: declaration 'strFunctionName' definition 'functionName'.
[lib/errorlogger.h:214] -> [lib/errorlogger.cpp:51]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/errorlogger.h:215] -> [lib/errorlogger.cpp:65]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/library.h:327] -> [lib/library.cpp:1043]: (style, inconclusive) Function 'ignorefunction' argument 1 names different: declaration 'function' definition 'functionName'.
[lib/mathlib.h:112] -> [lib/mathlib.cpp:1275]: (style, inconclusive) Function 'isNullValue' argument 1 names different: declaration 'tok' definition 'str'.
[lib/preprocessor.h:91] -> [lib/preprocessor.cpp:122]: (style, inconclusive) Function 'setDirectives' argument 1 names different: declaration 'tokens' definition 'tokens1'.
[lib/symboldatabase.h:860] -> [lib/symboldatabase.cpp:1801]: (style, inconclusive) Function 'argsMatch' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1171] -> [lib/symboldatabase.cpp:2048]: (style, inconclusive) Function 'addClassFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1174] -> [lib/symboldatabase.cpp:2208]: (style, inconclusive) Function 'addNewFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1090] -> [lib/symboldatabase.cpp:3648]: (style, inconclusive) Function 'findVariableType' argument 2 names different: declaration 'type' definition 'typeTok'.
[lib/symboldatabase.h:1101] -> [lib/symboldatabase.cpp:4308]: (style, inconclusive) Function 'findType' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1176] -> [lib/symboldatabase.cpp:4349]: (style, inconclusive) Function 'findTypeInNested' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1193] -> [lib/symboldatabase.cpp:4501]: (style, inconclusive) Function 'setValueType' argument 2 names different: declaration 'enumerators' definition 'enumerator'.
[lib/path.h:159] -> [lib/path.cpp:247]: (style, inconclusive) Function 'isCPP' argument 1 names different: declaration 'extensionInLowerCase' definition 'path'.
[lib/path.h:145] -> [lib/path.cpp:266]: (style, inconclusive) Function 'acceptFile' argument 1 names different: declaration 'filename' definition 'path'.
2017-04-03 00:06:46 +02:00
void Preprocessor : : setDirectives ( const simplecpp : : TokenList & tokens )
2016-07-24 14:02:21 +02:00
{
// directive list..
directives . clear ( ) ;
2016-12-05 17:30:06 +01:00
std : : vector < const simplecpp : : TokenList * > list ;
list . reserve ( 1U + tokenlists . size ( ) ) ;
lib: fix a bunch of warnings about differing function arguments in definition and declaration.
[lib/token.h:72] -> [lib/token.cpp:36]: (style, inconclusive) Function 'Token' argument 1 names different: declaration 'tokensBack' definition 't'.
[lib/token.h:445] -> [lib/token.cpp:497]: (style, inconclusive) Function 'multiCompare' argument 1 names different: declaration 'needle' definition 'tok'.
[lib/checkio.h:73] -> [lib/checkio.cpp:1385]: (style, inconclusive) Function 'ArgumentInfo' argument 3 names different: declaration 'isCPP' definition '_isCPP'.
[lib/checkother.h:216] -> [lib/checkother.cpp:2136]: (style, inconclusive) Function 'checkComparisonFunctionIsAlwaysTrueOrFalseError' argument 2 names different: declaration 'strFunctionName' definition 'functionName'.
[lib/errorlogger.h:214] -> [lib/errorlogger.cpp:51]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/errorlogger.h:215] -> [lib/errorlogger.cpp:65]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/library.h:327] -> [lib/library.cpp:1043]: (style, inconclusive) Function 'ignorefunction' argument 1 names different: declaration 'function' definition 'functionName'.
[lib/mathlib.h:112] -> [lib/mathlib.cpp:1275]: (style, inconclusive) Function 'isNullValue' argument 1 names different: declaration 'tok' definition 'str'.
[lib/preprocessor.h:91] -> [lib/preprocessor.cpp:122]: (style, inconclusive) Function 'setDirectives' argument 1 names different: declaration 'tokens' definition 'tokens1'.
[lib/symboldatabase.h:860] -> [lib/symboldatabase.cpp:1801]: (style, inconclusive) Function 'argsMatch' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1171] -> [lib/symboldatabase.cpp:2048]: (style, inconclusive) Function 'addClassFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1174] -> [lib/symboldatabase.cpp:2208]: (style, inconclusive) Function 'addNewFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1090] -> [lib/symboldatabase.cpp:3648]: (style, inconclusive) Function 'findVariableType' argument 2 names different: declaration 'type' definition 'typeTok'.
[lib/symboldatabase.h:1101] -> [lib/symboldatabase.cpp:4308]: (style, inconclusive) Function 'findType' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1176] -> [lib/symboldatabase.cpp:4349]: (style, inconclusive) Function 'findTypeInNested' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1193] -> [lib/symboldatabase.cpp:4501]: (style, inconclusive) Function 'setValueType' argument 2 names different: declaration 'enumerators' definition 'enumerator'.
[lib/path.h:159] -> [lib/path.cpp:247]: (style, inconclusive) Function 'isCPP' argument 1 names different: declaration 'extensionInLowerCase' definition 'path'.
[lib/path.h:145] -> [lib/path.cpp:266]: (style, inconclusive) Function 'acceptFile' argument 1 names different: declaration 'filename' definition 'path'.
2017-04-03 00:06:46 +02:00
list . push_back ( & tokens ) ;
2016-07-24 14:02:21 +02:00
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
list . push_back ( it - > second ) ;
}
2018-04-09 08:00:11 +02:00
for ( const simplecpp : : TokenList * tokenList : list ) {
for ( const simplecpp : : Token * tok = tokenList - > cfront ( ) ; tok ; tok = tok - > next ) {
2016-07-24 14:02:21 +02:00
if ( ( tok - > op ! = ' # ' ) | | ( tok - > previous & & tok - > previous - > location . line = = tok - > location . line ) )
continue ;
2018-05-14 13:00:22 +02:00
if ( tok - > next & & tok - > next - > str ( ) = = " endfile " )
2016-07-24 14:02:21 +02:00
continue ;
2017-03-01 10:50:50 +01:00
Directive directive ( tok - > location . file ( ) , tok - > location . line , emptyString ) ;
2016-07-24 14:02:21 +02:00
for ( const simplecpp : : Token * tok2 = tok ; tok2 & & tok2 - > location . line = = directive . linenr ; tok2 = tok2 - > next ) {
if ( tok2 - > comment )
continue ;
2018-05-14 13:00:22 +02:00
if ( ! directive . str . empty ( ) & & ( tok2 - > location . col > tok2 - > previous - > location . col + tok2 - > previous - > str ( ) . size ( ) ) )
2016-07-24 14:02:21 +02:00
directive . str + = ' ' ;
2018-05-14 13:00:22 +02:00
if ( directive . str = = " # " & & tok2 - > str ( ) = = " file " )
2016-07-24 14:02:21 +02:00
directive . str + = " include " ;
else
2018-05-14 13:00:22 +02:00
directive . str + = tok2 - > str ( ) ;
2016-07-24 14:02:21 +02:00
}
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 ;
2018-05-14 13:00:22 +02:00
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 ) {
2018-05-14 13:00:22 +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
2017-04-22 12:44:57 +02:00
if ( len = = 2 & & cond - > op = = ' ! ' & & next1 - > name ) {
2018-05-14 13:00:22 +02:00
if ( defined . find ( next1 - > str ( ) ) = = defined . end ( ) )
return next1 - > str ( ) + " =0 " ;
2017-04-22 12:44:57 +02:00
}
2016-07-21 19:11:49 +02:00
if ( len = = 3 & & cond - > op = = ' ( ' & & next1 - > name & & next2 - > op = = ' ) ' ) {
2018-05-14 13:00:22 +02:00
if ( defined . find ( next1 - > str ( ) ) = = defined . end ( ) & & undefined . find ( next1 - > str ( ) ) = = undefined . end ( ) )
return next1 - > str ( ) ;
2016-07-20 12:21:00 +02:00
}
2011-02-11 06:30:42 +01:00
2018-05-14 13:00:22 +02:00
if ( len = = 3 & & cond - > name & & next1 - > str ( ) = = " == " & & next2 - > number ) {
if ( defined . find ( cond - > str ( ) ) = = defined . end ( ) )
return cond - > str ( ) + ' = ' + cond - > next - > next - > str ( ) ;
2016-07-20 12:21:00 +02:00
}
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 ) {
2017-04-02 09:03:43 +02:00
if ( cond - > op = = ' ! ' ) {
if ( ! sameline ( iftok , cond - > next ) | | ! cond - > next - > name )
break ;
2018-05-14 13:00:22 +02:00
if ( cond - > next - > str ( ) = = " defined " )
2017-04-02 09:03:43 +02:00
continue ;
2018-05-14 13:00:22 +02:00
configset . insert ( cond - > next - > str ( ) + " =0 " ) ;
2017-04-02 09:03:43 +02:00
continue ;
}
2018-05-14 13:00:22 +02:00
if ( cond - > str ( ) ! = " defined " )
2016-07-21 19:11:49 +02:00
continue ;
const simplecpp : : Token * dtok = cond - > next ;
if ( ! dtok )
break ;
if ( dtok - > op = = ' ( ' )
dtok = dtok - > next ;
2018-05-14 13:00:22 +02:00
if ( sameline ( iftok , dtok ) & & dtok - > name & & defined . find ( dtok - > str ( ) ) = = defined . end ( ) & & undefined . find ( dtok - > str ( ) ) = = undefined . end ( ) )
configset . insert ( dtok - > str ( ) ) ;
2016-07-20 12:21:00 +02:00
}
std : : string cfg ;
2018-04-09 08:00:11 +02:00
for ( const std : : string & s : configset ) {
2016-07-20 12:21:00 +02:00
if ( ! cfg . empty ( ) )
cfg + = ' ; ' ;
2018-04-09 08:00:11 +02:00
cfg + = s ;
2016-07-20 12:21:00 +02:00
}
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 )
{
2016-10-11 18:46:46 +02:00
if ( cfg . empty ( ) ) {
return false ;
}
2016-08-21 13:53:44 +02:00
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 ;
2018-04-09 08:00:11 +02:00
for ( const std : : string & cfg : configs2 ) {
if ( cfg . empty ( ) )
2016-07-20 12:21:00 +02:00
continue ;
2018-04-09 08:00:11 +02:00
if ( cfg = = " 0 " )
2016-07-20 12:21:00 +02:00
return " " ;
2018-04-09 08:00:11 +02:00
if ( hasDefine ( userDefines , cfg ) )
2016-08-21 13:53:44 +02:00
continue ;
2016-07-20 12:21:00 +02:00
if ( ! ret . empty ( ) )
ret + = ' ; ' ;
2018-04-09 08:00:11 +02:00
ret + = cfg ;
2016-07-20 12:21:00 +02:00
}
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 ( ) ; ) {
2016-11-30 12:01:22 +01:00
const std : : string : : size_type pos2 = cfg . find ( ' ; ' , pos1 ) ;
2016-08-21 07:45:15 +02:00
const std : : string def = ( pos2 = = std : : string : : npos ) ? cfg . substr ( pos1 ) : cfg . substr ( pos1 , pos2 - pos1 ) ;
2018-04-04 21:51:31 +02:00
const std : : string : : size_type eq = def . find ( ' = ' ) ;
2016-08-21 07:45:15 +02:00
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 ) ) {
2018-05-14 13:00:22 +02:00
if ( cmdtok - > next - > str ( ) . compare ( 0 , 2 , " if " ) = = 0 )
2016-08-21 13:53:44 +02:00
+ + level ;
2018-05-14 13:00:22 +02:00
else if ( cmdtok - > next - > str ( ) = = " endif " ) {
2016-08-21 13:53:44 +02:00
- - 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 ;
2017-03-22 10:53:21 +01:00
std : : string elseError ;
2016-07-20 12:21:00 +02:00
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 ;
2018-05-14 13:00:22 +02:00
if ( cmdtok - > str ( ) = = " ifdef " | | cmdtok - > str ( ) = = " ifndef " | | cmdtok - > str ( ) = = " if " ) {
2016-07-20 12:21:00 +02:00
std : : string config ;
2018-05-14 13:00:22 +02:00
if ( cmdtok - > str ( ) = = " ifdef " | | cmdtok - > str ( ) = = " ifndef " ) {
2016-07-21 19:11:49 +02:00
const simplecpp : : Token * expr1 = cmdtok - > next ;
if ( sameline ( tok , expr1 ) & & expr1 - > name & & ! sameline ( tok , expr1 - > next ) )
2018-05-14 13:00:22 +02:00
config = expr1 - > str ( ) ;
2016-07-20 12:21:00 +02:00
if ( defined . find ( config ) ! = defined . end ( ) )
config . clear ( ) ;
2018-05-14 13:00:22 +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
2018-05-14 13:00:22 +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 ) ) ;
2018-05-14 13:00:22 +02:00
} else if ( cmdtok - > str ( ) = = " elif " | | cmdtok - > str ( ) = = " else " ) {
2016-08-21 13:53:44 +02:00
if ( getConfigsElseIsFalse ( configs_if , userDefines ) ) {
tok = gotoEndIf ( tok ) ;
if ( ! tok )
break ;
tok = tok - > previous ;
continue ;
}
2018-05-14 13:00:22 +02:00
if ( cmdtok - > str ( ) = = " else " & &
2017-03-22 10:53:21 +01:00
cmdtok - > next & &
! sameline ( cmdtok , cmdtok - > next ) & &
sameline ( cmdtok - > next , cmdtok - > next - > next ) & &
cmdtok - > next - > op = = ' # ' & &
2018-05-14 13:00:22 +02:00
cmdtok - > next - > next - > str ( ) = = " error " ) {
2017-05-24 11:16:41 +02:00
const std : : string & ifcfg = cfg ( configs_if , userDefines ) ;
if ( ! ifcfg . empty ( ) ) {
if ( ! elseError . empty ( ) )
elseError + = ' ; ' ;
elseError + = ifcfg ;
}
2017-03-22 10:53:21 +01:00
}
2016-07-20 20:39:03 +02:00
if ( ! configs_if . empty ( ) )
configs_if . pop_back ( ) ;
2018-05-14 13:00:22 +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
}
2018-05-14 13:00:22 +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 ( ) ;
2018-05-14 13:00:22 +02:00
} else if ( cmdtok - > str ( ) = = " error " ) {
2016-12-03 11:59:48 +01:00
if ( ! configs_ifndef . empty ( ) & & ! configs_ifndef . back ( ) . empty ( ) ) {
2017-04-02 12:15:53 +02:00
if ( configs_ifndef . size ( ) = = 1U )
ret . erase ( " " ) ;
2016-12-03 11:59:48 +01:00
std : : vector < std : : string > configs ( configs_if ) ;
configs . push_back ( configs_ifndef . back ( ) ) ;
2017-04-22 12:44:57 +02:00
ret . erase ( cfg ( configs , userDefines ) ) ;
if ( ! elseError . empty ( ) )
elseError + = ' ; ' ;
elseError + = cfg ( configs_ifndef , userDefines ) ;
2016-12-03 11:59:48 +01:00
}
2017-04-02 10:06:39 +02:00
if ( ! configs_if . empty ( ) & & ! configs_if . back ( ) . empty ( ) ) {
const std : : string & last = configs_if . back ( ) ;
if ( last . size ( ) > 2U & & last . compare ( last . size ( ) - 2U , 2 , " =0 " ) = = 0 ) {
std : : vector < std : : string > configs ( configs_if ) ;
2017-04-02 12:15:53 +02:00
ret . erase ( cfg ( configs , userDefines ) ) ;
2017-04-02 10:06:39 +02:00
configs [ configs . size ( ) - 1U ] = last . substr ( 0 , last . size ( ) - 2U ) ;
2017-04-02 12:15:53 +02:00
if ( configs . size ( ) = = 1U )
ret . erase ( " " ) ;
2017-04-22 12:44:57 +02:00
if ( ! elseError . empty ( ) )
elseError + = ' ; ' ;
elseError + = cfg ( configs , userDefines ) ;
2017-04-02 10:06:39 +02:00
}
}
2018-05-14 13:00:22 +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
}
}
2017-03-22 10:53:21 +01:00
if ( ! elseError . empty ( ) )
ret . insert ( elseError ) ;
2016-07-20 12:21:00 +02:00
}
std : : set < std : : string > Preprocessor : : getConfigs ( const simplecpp : : TokenList & tokens ) const
{
2018-04-11 09:44:35 +02:00
std : : set < std : : string > ret = { " " } ;
2016-07-29 08:51:57 +02:00
if ( ! tokens . cfront ( ) )
2016-07-20 12:21:00 +02:00
return ret ;
2018-04-11 09:44:35 +02:00
std : : set < std : : string > defined = { " __cplusplus " } ;
2016-07-20 12:21:00 +02:00
2016-08-21 13:53:44 +02:00
: : getConfigs ( tokens , defined , _settings . userDefines , _settings . userUndefs , ret ) ;
2016-07-20 12:21:00 +02:00
2016-09-30 08:00:06 +02:00
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
if ( ! _settings . configurationExcluded ( it - > first ) )
: : 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
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 ( ) ; ) {
2016-11-30 12:01:22 +01:00
const std : : string : : size_type defineEndPos = cfg . find ( ' ; ' , defineStartPos ) ;
2016-08-23 17:27:07 +02:00
std : : string def = ( defineEndPos = = std : : string : : npos ) ? cfg . substr ( defineStartPos ) : cfg . substr ( defineStartPos , defineEndPos - defineStartPos ) ;
2016-11-30 12:01:22 +01:00
if ( ! defaultValue . empty ( ) & & def . find ( ' = ' ) = = std : : string : : npos )
2016-07-20 12:21:00 +02:00
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 ( ) )
2017-03-01 10:50:50 +01:00
splitcfg ( cfg , dui . defines , emptyString ) ;
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 ) ;
2018-04-04 21:51:31 +02:00
const std : : string : : size_type pos = s . find_first_of ( " ( " ) ;
2016-07-20 12:21:00 +02:00
if ( pos = = std : : string : : npos ) {
dui . defines . push_back ( s ) ;
continue ;
}
if ( s [ pos ] = = ' ' ) {
s [ pos ] = ' = ' ;
} else {
2016-11-30 12:01:22 +01:00
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 :
2017-09-12 22:42:10 +02:00
case simplecpp : : Output : : UNHANDLED_CHAR_ERROR :
2016-08-06 09:15:09 +02:00
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 )
{
2017-03-01 10:50:50 +01:00
const simplecpp : : DUI dui = createDUI ( _settings , emptyString , files [ 0 ] ) ;
2009-01-24 20:28:30 +01:00
2017-11-29 08:29:19 +01:00
tokenlists = simplecpp : : load ( rawtokens , files , dui , nullptr ) ;
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 ;
}
2018-05-28 14:11:59 +02:00
simplecpp : : TokenList Preprocessor : : preprocess ( const simplecpp : : TokenList & tokens1 , const std : : string & cfg , std : : vector < std : : string > & files , bool throwError )
2012-07-18 20:57:00 +02:00
{
2016-12-05 17:30:06 +01:00
const simplecpp : : DUI dui = createDUI ( _settings , cfg , files [ 0 ] ) ;
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
2018-04-04 21:51:31 +02:00
const bool showerror = ( ! _settings . userDefines . empty ( ) & & ! _settings . force ) ;
2016-08-06 09:15:09 +02:00
reportOutput ( outputList , showerror ) ;
2018-05-28 14:11:59 +02:00
if ( throwError & & hasErrors ( outputList ) ) {
2018-05-15 15:42:54 +02:00
for ( const simplecpp : : Output & output : outputList ) {
switch ( output . type ) {
case simplecpp : : Output : : ERROR :
case simplecpp : : Output : : INCLUDE_NESTED_TOO_DEEPLY :
case simplecpp : : Output : : SYNTAX_ERROR :
case simplecpp : : Output : : UNHANDLED_CHAR_ERROR :
throw output ;
case simplecpp : : Output : : WARNING :
case simplecpp : : Output : : MISSING_HEADER :
case simplecpp : : Output : : PORTABILITY_BACKSLASH :
break ;
} ;
}
}
2009-06-26 13:19:55 +02:00
2017-05-02 22:18:24 +02:00
tokens2 . removeComments ( ) ;
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 ) )
2017-05-17 10:25:37 +02:00
return simplecpp : : TokenList ( files ) ;
2011-10-17 20:12:46 +02:00
2017-05-17 10:25:37 +02:00
return tokens2 ;
}
2011-11-03 19:05:48 +01:00
2017-05-17 10:25:37 +02:00
std : : string Preprocessor : : getcode ( const simplecpp : : TokenList & tokens1 , const std : : string & cfg , std : : vector < std : : string > & files , const bool writeLocations )
{
2018-05-28 14:11:59 +02:00
simplecpp : : TokenList tokens2 = preprocess ( tokens1 , cfg , files , false ) ;
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
2017-03-05 16:46:43 +01:00
if ( tok - > previous & & line > = tok - > location . line ) // #7912
2016-07-20 12:21:00 +02:00
ret < < ' ' ;
while ( tok - > location . line > line ) {
ret < < ' \n ' ;
line + + ;
}
if ( ! tok - > macro . empty ( ) )
ret < < Preprocessor : : macroChar ;
2018-05-14 13:00:22 +02:00
ret < < tok - > str ( ) ;
2016-07-20 12:21:00 +02:00
}
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 " " ;
2018-05-15 15:42:54 +02:00
std : : string ret ;
try {
ret = getcode ( tokens1 , cfg , files , filedata . find ( " #file " ) ! = std : : string : : npos ) ;
2018-05-29 13:18:07 +02:00
} catch ( const simplecpp : : Output & ) {
2018-05-15 15:42:54 +02:00
ret . clear ( ) ;
}
return ret ;
2016-08-06 09:15:09 +02:00
}
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 :
2017-09-12 22:42:10 +02:00
case simplecpp : : Output : : UNHANDLED_CHAR_ERROR :
2016-08-06 09:15:09 +02:00
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 ( ) ) {
2018-04-04 21:51:31 +02:00
const ErrorLogger : : ErrorMessage : : FileLocation loc ( filename , linenr ) ;
2016-07-20 12:21:00 +02:00
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 ) ;
2018-04-09 06:43:48 +02:00
Suppressions : : ErrorMessage errorMessage ;
errorMessage . errorId = " missingInclude " ;
errorMessage . setFileName ( fname ) ;
errorMessage . lineNumber = linenr ;
if ( _settings . nomsg . isSuppressed ( errorMessage ) )
2014-05-03 19:31:15 +02:00
return ;
2018-04-09 06:43:48 +02:00
errorMessage . errorId = " missingIncludeSystem " ;
if ( headerType = = SystemHeader & & _settings . nomsg . isSuppressed ( errorMessage ) )
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 ;
2016-12-05 17:30:06 +01:00
splitcfg ( cfg , defines , emptyString ) ;
2016-08-01 20:09:41 +02:00
for ( std : : list < std : : string > : : const_iterator defineIt = defines . begin ( ) ; defineIt ! = defines . end ( ) ; + + defineIt ) {
2016-12-01 17:54:45 +01:00
if ( defineIt - > find ( ' = ' ) ! = std : : string : : npos )
2016-08-01 20:09:41 +02:00
continue ;
2016-12-01 17:54:45 +01:00
const std : : string macroName ( defineIt - > substr ( 0 , defineIt - > find ( ' ( ' ) ) ) ;
2016-08-01 20:09:41 +02:00
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 ) {
2017-04-11 11:49:09 +02:00
if ( _settings . isEnabled ( Settings : : INFORMATION ) )
2016-08-01 20:09:41 +02:00
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 ;
2018-04-04 21:51:31 +02:00
const ErrorLogger : : ErrorMessage : : FileLocation loc ( file , line ) ;
2012-11-03 11:25:40 +01:00
locationList . push_back ( loc ) ;
2018-04-04 21:51:31 +02:00
const 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 ;
2017-03-01 10:50:50 +01:00
preprocessor . missingInclude ( emptyString , 1 , emptyString , UserHeader ) ;
preprocessor . missingInclude ( emptyString , 1 , emptyString , SystemHeader ) ;
preprocessor . validateCfgError ( emptyString , 1 , " X " , " X " ) ;
preprocessor . error ( emptyString , 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.
out < < " <directivelist> " < < std : : endl ;
2016-12-05 17:30:06 +01:00
for ( std : : list < Directive > : : const_iterator it = directives . begin ( ) ; it ! = directives . end ( ) ; + + it ) {
2015-12-07 19:54:41 +01:00
out < < " <directive "
2018-04-25 18:28:04 +02:00
< < " file= \" " < < ErrorLogger : : toxml ( it - > file ) < < " \" "
2015-12-07 19:54:41 +01:00
< < " 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 ;
}
2016-10-29 12:18:11 +02:00
2016-10-29 15:35:31 +02:00
static const std : : uint32_t crc32Table [ ] = {
0x00000000 , 0x77073096 , 0xee0e612c , 0x990951ba , 0x076dc419 , 0x706af48f ,
0xe963a535 , 0x9e6495a3 , 0x0edb8832 , 0x79dcb8a4 , 0xe0d5e91e , 0x97d2d988 ,
0x09b64c2b , 0x7eb17cbd , 0xe7b82d07 , 0x90bf1d91 , 0x1db71064 , 0x6ab020f2 ,
0xf3b97148 , 0x84be41de , 0x1adad47d , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 ,
0x136c9856 , 0x646ba8c0 , 0xfd62f97a , 0x8a65c9ec , 0x14015c4f , 0x63066cd9 ,
0xfa0f3d63 , 0x8d080df5 , 0x3b6e20c8 , 0x4c69105e , 0xd56041e4 , 0xa2677172 ,
0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0xa50ab56b , 0x35b5a8fa , 0x42b2986c ,
0xdbbbc9d6 , 0xacbcf940 , 0x32d86ce3 , 0x45df5c75 , 0xdcd60dcf , 0xabd13d59 ,
0x26d930ac , 0x51de003a , 0xc8d75180 , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 ,
0xcfba9599 , 0xb8bda50f , 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0xb10be924 ,
0x2f6f7c87 , 0x58684c11 , 0xc1611dab , 0xb6662d3d , 0x76dc4190 , 0x01db7106 ,
0x98d220bc , 0xefd5102a , 0x71b18589 , 0x06b6b51f , 0x9fbfe4a5 , 0xe8b8d433 ,
0x7807c9a2 , 0x0f00f934 , 0x9609a88e , 0xe10e9818 , 0x7f6a0dbb , 0x086d3d2d ,
0x91646c97 , 0xe6635c01 , 0x6b6b51f4 , 0x1c6c6162 , 0x856530d8 , 0xf262004e ,
0x6c0695ed , 0x1b01a57b , 0x8208f4c1 , 0xf50fc457 , 0x65b0d9c6 , 0x12b7e950 ,
0x8bbeb8ea , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x8cd37cf3 , 0xfbd44c65 ,
0x4db26158 , 0x3ab551ce , 0xa3bc0074 , 0xd4bb30e2 , 0x4adfa541 , 0x3dd895d7 ,
0xa4d1c46d , 0xd3d6f4fb , 0x4369e96a , 0x346ed9fc , 0xad678846 , 0xda60b8d0 ,
0x44042d73 , 0x33031de5 , 0xaa0a4c5f , 0xdd0d7cc9 , 0x5005713c , 0x270241aa ,
0xbe0b1010 , 0xc90c2086 , 0x5768b525 , 0x206f85b3 , 0xb966d409 , 0xce61e49f ,
0x5edef90e , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0x59b33d17 , 0x2eb40d81 ,
0xb7bd5c3b , 0xc0ba6cad , 0xedb88320 , 0x9abfb3b6 , 0x03b6e20c , 0x74b1d29a ,
0xead54739 , 0x9dd277af , 0x04db2615 , 0x73dc1683 , 0xe3630b12 , 0x94643b84 ,
0x0d6d6a3e , 0x7a6a5aa8 , 0xe40ecf0b , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 ,
0xf00f9344 , 0x8708a3d2 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x806567cb ,
0x196c3671 , 0x6e6b06e7 , 0xfed41b76 , 0x89d32be0 , 0x10da7a5a , 0x67dd4acc ,
0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0x60b08ed5 , 0xd6d6a3e8 , 0xa1d1937e ,
0x38d8c2c4 , 0x4fdff252 , 0xd1bb67f1 , 0xa6bc5767 , 0x3fb506dd , 0x48b2364b ,
0xd80d2bda , 0xaf0a1b4c , 0x36034af6 , 0x41047a60 , 0xdf60efc3 , 0xa867df55 ,
0x316e8eef , 0x4669be79 , 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0x5268e236 ,
0xcc0c7795 , 0xbb0b4703 , 0x220216b9 , 0x5505262f , 0xc5ba3bbe , 0xb2bd0b28 ,
0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 , 0xb5d0cf31 , 0x2cd99e8b , 0x5bdeae1d ,
0x9b64c2b0 , 0xec63f226 , 0x756aa39c , 0x026d930a , 0x9c0906a9 , 0xeb0e363f ,
0x72076785 , 0x05005713 , 0x95bf4a82 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 ,
0x92d28e9b , 0xe5d5be0d , 0x7cdcefb7 , 0x0bdbdf21 , 0x86d3d2d4 , 0xf1d4e242 ,
0x68ddb3f8 , 0x1fda836e , 0x81be16cd , 0xf6b9265b , 0x6fb077e1 , 0x18b74777 ,
0x88085ae6 , 0xff0f6a70 , 0x66063bca , 0x11010b5c , 0x8f659eff , 0xf862ae69 ,
0x616bffd3 , 0x166ccf45 , 0xa00ae278 , 0xd70dd2ee , 0x4e048354 , 0x3903b3c2 ,
0xa7672661 , 0xd06016f7 , 0x4969474d , 0x3e6e77db , 0xaed16a4a , 0xd9d65adc ,
0x40df0b66 , 0x37d83bf0 , 0xa9bcae53 , 0xdebb9ec5 , 0x47b2cf7f , 0x30b5ffe9 ,
0xbdbdf21c , 0xcabac28a , 0x53b39330 , 0x24b4a3a6 , 0xbad03605 , 0xcdd70693 ,
0x54de5729 , 0x23d967bf , 0xb3667a2e , 0xc4614ab8 , 0x5d681b02 , 0x2a6f2b94 ,
0xb40bbe37 , 0xc30c8ea1 , 0x5a05df1b , 0x2d02ef8d
} ;
static std : : uint32_t crc32 ( const std : : string & data )
{
std : : uint32_t crc = ~ 0U ;
for ( std : : string : : const_iterator c = data . begin ( ) ; c ! = data . end ( ) ; + + c ) {
crc = crc32Table [ ( crc ^ ( unsigned char ) ( * c ) ) & 0xFF ] ^ ( crc > > 8 ) ;
}
return crc ^ ~ 0U ;
}
2016-10-29 22:40:44 +02:00
unsigned int Preprocessor : : calculateChecksum ( const simplecpp : : TokenList & tokens1 , const std : : string & toolinfo ) const
2016-10-29 12:18:11 +02:00
{
std : : ostringstream ostr ;
2016-10-29 22:40:44 +02:00
ostr < < toolinfo < < ' \n ' ;
2016-10-29 12:18:11 +02:00
for ( const simplecpp : : Token * tok = tokens1 . cfront ( ) ; tok ; tok = tok - > next ) {
if ( ! tok - > comment )
2018-05-14 13:00:22 +02:00
ostr < < tok - > str ( ) ;
2016-10-29 12:18:11 +02:00
}
for ( std : : map < std : : string , simplecpp : : TokenList * > : : const_iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
for ( const simplecpp : : Token * tok = it - > second - > cfront ( ) ; tok ; tok = tok - > next ) {
if ( ! tok - > comment )
2018-05-14 13:00:22 +02:00
ostr < < tok - > str ( ) ;
2016-10-29 12:18:11 +02:00
}
}
2016-10-29 15:35:31 +02:00
return crc32 ( ostr . str ( ) ) ;
2016-10-29 12:18:11 +02:00
}
2017-05-17 10:25:37 +02:00
void Preprocessor : : simplifyPragmaAsm ( simplecpp : : TokenList * tokenList )
2017-05-17 21:58:46 +02:00
{
Preprocessor : : simplifyPragmaAsmPrivate ( tokenList ) ;
for ( std : : map < std : : string , simplecpp : : TokenList * > : : iterator it = tokenlists . begin ( ) ; it ! = tokenlists . end ( ) ; + + it ) {
Preprocessor : : simplifyPragmaAsmPrivate ( it - > second ) ;
}
}
void Preprocessor : : simplifyPragmaAsmPrivate ( simplecpp : : TokenList * tokenList )
2017-05-17 10:25:37 +02:00
{
// assembler code..
for ( simplecpp : : Token * tok = tokenList - > front ( ) ; tok ; tok = tok - > next ) {
if ( tok - > op ! = ' # ' )
continue ;
if ( sameline ( tok , tok - > previousSkipComments ( ) ) )
continue ;
const simplecpp : : Token * const tok2 = tok - > nextSkipComments ( ) ;
2018-05-14 13:00:22 +02:00
if ( ! tok2 | | ! sameline ( tok , tok2 ) | | tok2 - > str ( ) ! = " pragma " )
2017-05-17 10:25:37 +02:00
continue ;
const simplecpp : : Token * const tok3 = tok2 - > nextSkipComments ( ) ;
2018-05-14 13:00:22 +02:00
if ( ! tok3 | | ! sameline ( tok , tok3 ) | | tok3 - > str ( ) ! = " asm " )
2017-05-17 10:25:37 +02:00
continue ;
const simplecpp : : Token * endasm = tok3 ;
2017-08-09 20:00:26 +02:00
while ( ( endasm = endasm - > next ) ! = nullptr ) {
2017-05-17 10:25:37 +02:00
if ( endasm - > op ! = ' # ' | | sameline ( endasm , endasm - > previousSkipComments ( ) ) )
continue ;
const simplecpp : : Token * const endasm2 = endasm - > nextSkipComments ( ) ;
2018-05-14 13:00:22 +02:00
if ( ! endasm2 | | ! sameline ( endasm , endasm2 ) | | endasm2 - > str ( ) ! = " pragma " )
2017-05-17 10:25:37 +02:00
continue ;
const simplecpp : : Token * const endasm3 = endasm2 - > nextSkipComments ( ) ;
2018-05-14 13:00:22 +02:00
if ( ! endasm3 | | ! sameline ( endasm2 , endasm3 ) | | endasm3 - > str ( ) ! = " endasm " )
2017-05-17 10:25:37 +02:00
continue ;
while ( sameline ( endasm , endasm3 ) )
endasm = endasm - > next ;
break ;
}
const simplecpp : : Token * const tok4 = tok3 - > next ;
tok - > setstr ( " asm " ) ;
const_cast < simplecpp : : Token * > ( tok2 ) - > setstr ( " ( " ) ;
const_cast < simplecpp : : Token * > ( tok3 ) - > setstr ( " ) " ) ;
const_cast < simplecpp : : Token * > ( tok4 ) - > setstr ( " ; " ) ;
while ( tok4 - > next ! = endasm )
tokenList - > deleteToken ( tok4 - > next ) ;
}
}