2013-07-02 07:18:19 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2013-07-02 07:18:19 +02: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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2013-07-08 18:26:18 +02:00
# include "library.h"
2017-05-27 04:33:47 +02:00
# include "astutils.h"
# include "mathlib.h"
2013-07-20 17:12:56 +02:00
# include "path.h"
2017-05-27 04:33:47 +02:00
# include "symboldatabase.h"
2013-12-23 10:06:45 +01:00
# include "token.h"
2017-05-27 04:33:47 +02:00
# include "tokenlist.h"
2017-04-01 18:14:18 +02:00
# include "utils.h"
2022-01-27 19:03:20 +01:00
# include "valueflow.h"
2023-01-26 22:23:22 +01:00
# include "vfvalue.h"
2013-07-02 07:18:19 +02:00
2023-03-02 21:50:14 +01:00
# include <algorithm>
2017-05-27 04:33:47 +02:00
# include <cctype>
2022-01-27 19:03:20 +01:00
# include <climits>
2017-05-27 04:33:47 +02:00
# include <cstdlib>
# include <cstring>
# include <list>
2022-01-27 19:03:20 +01:00
# include <memory>
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
2022-04-13 12:24:00 +02:00
# include <stack>
2020-04-03 13:16:57 +02:00
# include <string>
2013-07-20 17:12:56 +02:00
2022-01-27 19:03:20 +01:00
# include <tinyxml2.h>
2015-11-15 15:24:10 +01:00
static std : : vector < std : : string > getnames ( const char * names )
{
std : : vector < std : : string > ret ;
while ( const char * p = std : : strchr ( names , ' , ' ) ) {
2018-04-11 09:44:35 +02:00
ret . emplace_back ( names , p - names ) ;
2015-11-15 15:24:10 +01:00
names = p + 1 ;
}
2019-09-25 15:25:19 +02:00
ret . emplace_back ( names ) ;
2015-11-15 15:24:10 +01:00
return ret ;
}
2018-07-15 22:47:56 +02:00
static void gettokenlistfromvalid ( const std : : string & valid , TokenList & tokenList )
{
std : : istringstream istr ( valid + ' , ' ) ;
tokenList . createTokens ( istr ) ;
for ( Token * tok = tokenList . front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " - %num% " ) ) {
tok - > str ( " - " + tok - > strAt ( 1 ) ) ;
tok - > deleteNext ( ) ;
}
}
}
2022-04-11 07:30:55 +02:00
Library : : Library ( ) : mAllocId ( 0 )
2021-08-07 20:51:18 +02:00
{ }
2013-07-02 07:18:19 +02:00
2014-05-26 17:00:41 +02:00
Library : : Error Library : : load ( const char exename [ ] , const char path [ ] )
2013-07-02 07:18:19 +02:00
{
2014-02-15 08:41:17 +01:00
if ( std : : strchr ( path , ' , ' ) ! = nullptr ) {
2013-07-20 10:21:05 +02:00
std : : string p ( path ) ;
2015-08-27 10:19:51 +02:00
for ( ; ; ) {
const std : : string : : size_type pos = p . find ( ' , ' ) ;
if ( pos = = std : : string : : npos )
break ;
2014-05-26 17:00:41 +02:00
const Error & e = load ( exename , p . substr ( 0 , pos ) . c_str ( ) ) ;
2021-01-08 10:29:01 +01:00
if ( e . errorcode ! = ErrorCode : : OK )
2014-05-26 17:00:41 +02:00
return e ;
2013-07-20 10:21:05 +02:00
p = p . substr ( pos + 1 ) ;
}
if ( ! p . empty ( ) )
2014-05-26 17:00:41 +02:00
return load ( exename , p . c_str ( ) ) ;
return Error ( ) ;
2013-07-20 10:21:05 +02:00
}
2014-10-19 07:34:40 +02:00
std : : string absolute_path ;
2013-07-20 17:12:56 +02:00
// open file..
2013-10-27 17:32:38 +01:00
tinyxml2 : : XMLDocument doc ;
2014-03-01 14:09:03 +01:00
tinyxml2 : : XMLError error = doc . LoadFile ( path ) ;
2018-12-24 08:37:33 +01:00
if ( error = = tinyxml2 : : XML_ERROR_FILE_READ_ERROR & & Path : : getFilenameExtension ( path ) . empty ( ) )
// Reading file failed, try again...
error = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND ;
2013-10-27 17:32:38 +01:00
if ( error = = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND ) {
2013-07-20 17:12:56 +02:00
// failed to open file.. is there no extension?
std : : string fullfilename ( path ) ;
2017-06-02 20:38:00 +02:00
if ( Path : : getFilenameExtension ( fullfilename ) . empty ( ) ) {
2013-07-20 17:12:56 +02:00
fullfilename + = " .cfg " ;
2014-03-01 14:09:03 +01:00
error = doc . LoadFile ( fullfilename . c_str ( ) ) ;
2014-10-19 07:34:40 +02:00
if ( error ! = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND )
2015-12-03 14:19:17 +01:00
absolute_path = Path : : getAbsoluteFilePath ( fullfilename ) ;
2013-07-20 10:21:05 +02:00
}
2013-07-20 17:12:56 +02:00
2016-08-01 12:58:33 +02:00
std : : list < std : : string > cfgfolders ;
2019-08-17 10:53:07 +02:00
# ifdef FILESDIR
2019-09-25 15:25:19 +02:00
cfgfolders . emplace_back ( FILESDIR " /cfg " ) ;
2013-12-26 18:41:51 +01:00
# endif
2016-08-01 12:58:33 +02:00
if ( exename ) {
2023-05-26 06:55:36 +02:00
const std : : string exepath ( Path : : fromNativeSeparators ( Path : : getPathFromFilename ( Path : : getCurrentExecutablePath ( exename ) ) ) ) ;
2016-08-01 12:58:33 +02:00
cfgfolders . push_back ( exepath + " cfg " ) ;
2023-05-26 06:55:36 +02:00
cfgfolders . push_back ( exepath + " ../cfg " ) ;
2016-08-01 12:58:33 +02:00
cfgfolders . push_back ( exepath ) ;
}
while ( error = = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND & & ! cfgfolders . empty ( ) ) {
2019-11-05 07:09:59 +01:00
const std : : string cfgfolder ( cfgfolders . back ( ) ) ;
cfgfolders . pop_back ( ) ;
2017-04-01 18:14:18 +02:00
const char * sep = ( ! cfgfolder . empty ( ) & & endsWith ( cfgfolder , ' / ' ) ? " " : " / " ) ;
2013-12-26 18:41:51 +01:00
const std : : string filename ( cfgfolder + sep + fullfilename ) ;
2014-03-01 14:09:03 +01:00
error = doc . LoadFile ( filename . c_str ( ) ) ;
2014-10-19 07:34:40 +02:00
if ( error ! = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND )
2015-12-03 14:19:17 +01:00
absolute_path = Path : : getAbsoluteFilePath ( filename ) ;
2013-07-20 17:12:56 +02:00
}
2014-10-19 07:34:40 +02:00
} else
absolute_path = Path : : getAbsoluteFilePath ( path ) ;
2016-07-09 11:56:07 +02:00
if ( error = = tinyxml2 : : XML_SUCCESS ) {
2018-06-16 16:23:55 +02:00
if ( mFiles . find ( absolute_path ) = = mFiles . end ( ) ) {
2014-10-19 07:34:40 +02:00
Error err = load ( doc ) ;
2021-01-08 10:29:01 +01:00
if ( err . errorcode = = ErrorCode : : OK )
2018-06-16 16:23:55 +02:00
mFiles . insert ( absolute_path ) ;
2014-10-19 07:34:40 +02:00
return err ;
}
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : OK ) ; // ignore duplicates
2013-07-20 10:21:05 +02:00
}
2019-01-18 17:10:41 +01:00
if ( error = = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : FILE_NOT_FOUND ) ;
2019-01-18 17:10:41 +01:00
else {
doc . PrintError ( ) ;
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_XML ) ;
2019-01-18 17:10:41 +01:00
}
2013-10-27 17:10:43 +01:00
}
2021-08-23 09:03:48 +02:00
Library : : Container : : Yield Library : : Container : : yieldFrom ( const std : : string & yieldName )
{
if ( yieldName = = " at_index " )
return Container : : Yield : : AT_INDEX ;
else if ( yieldName = = " item " )
return Container : : Yield : : ITEM ;
else if ( yieldName = = " buffer " )
return Container : : Yield : : BUFFER ;
else if ( yieldName = = " buffer-nt " )
return Container : : Yield : : BUFFER_NT ;
else if ( yieldName = = " start-iterator " )
return Container : : Yield : : START_ITERATOR ;
else if ( yieldName = = " end-iterator " )
return Container : : Yield : : END_ITERATOR ;
else if ( yieldName = = " iterator " )
return Container : : Yield : : ITERATOR ;
else if ( yieldName = = " size " )
return Container : : Yield : : SIZE ;
else if ( yieldName = = " empty " )
return Container : : Yield : : EMPTY ;
else
return Container : : Yield : : NO_YIELD ;
}
Library : : Container : : Action Library : : Container : : actionFrom ( const std : : string & actionName )
{
if ( actionName = = " resize " )
return Container : : Action : : RESIZE ;
else if ( actionName = = " clear " )
return Container : : Action : : CLEAR ;
else if ( actionName = = " push " )
return Container : : Action : : PUSH ;
else if ( actionName = = " pop " )
return Container : : Action : : POP ;
else if ( actionName = = " find " )
return Container : : Action : : FIND ;
else if ( actionName = = " insert " )
return Container : : Action : : INSERT ;
else if ( actionName = = " erase " )
return Container : : Action : : ERASE ;
else if ( actionName = = " change-content " )
return Container : : Action : : CHANGE_CONTENT ;
else if ( actionName = = " change-internal " )
return Container : : Action : : CHANGE_INTERNAL ;
else if ( actionName = = " change " )
return Container : : Action : : CHANGE ;
else
return Container : : Action : : NO_ACTION ;
}
2022-01-18 22:02:25 +01:00
// cppcheck-suppress unusedFunction - only used in unit tests
2014-01-09 21:58:56 +01:00
bool Library : : loadxmldata ( const char xmldata [ ] , std : : size_t len )
{
tinyxml2 : : XMLDocument doc ;
2021-01-08 10:29:01 +01:00
return ( tinyxml2 : : XML_SUCCESS = = doc . Parse ( xmldata , len ) ) & & ( load ( doc ) . errorcode = = ErrorCode : : OK ) ;
2014-01-09 21:58:56 +01:00
}
2014-05-26 17:00:41 +02:00
Library : : Error Library : : load ( const tinyxml2 : : XMLDocument & doc )
2013-10-27 17:10:43 +01:00
{
2013-07-02 07:18:19 +02:00
const tinyxml2 : : XMLElement * const rootnode = doc . FirstChildElement ( ) ;
2013-10-31 19:49:36 +01:00
2019-01-18 17:10:41 +01:00
if ( rootnode = = nullptr ) {
doc . PrintError ( ) ;
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_XML ) ;
2019-01-18 17:10:41 +01:00
}
2013-10-31 19:49:36 +01:00
if ( strcmp ( rootnode - > Name ( ) , " def " ) ! = 0 )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : UNSUPPORTED_FORMAT , rootnode - > Name ( ) ) ;
2013-07-02 07:18:19 +02:00
2022-10-02 07:12:40 +02:00
const int format = rootnode - > IntAttribute ( " format " , 1 ) ; // Assume format version 1 if nothing else is specified (very old .cfg files had no 'format' attribute)
2014-09-29 16:25:35 +02:00
2015-08-11 13:56:32 +02:00
if ( format > 2 | | format < = 0 )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : UNSUPPORTED_FORMAT ) ;
2014-09-29 16:25:35 +02:00
2015-01-10 22:18:57 +01:00
std : : set < std : : string > unknown_elements ;
2013-07-02 07:18:19 +02:00
for ( const tinyxml2 : : XMLElement * node = rootnode - > FirstChildElement ( ) ; node ; node = node - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string nodename = node - > Name ( ) ;
2014-09-10 17:03:31 +02:00
if ( nodename = = " memory " | | nodename = = " resource " ) {
2014-04-19 13:15:06 +02:00
// get allocationId to use..
int allocationId = 0 ;
for ( const tinyxml2 : : XMLElement * memorynode = node - > FirstChildElement ( ) ; memorynode ; memorynode = memorynode - > NextSiblingElement ( ) ) {
if ( strcmp ( memorynode - > Name ( ) , " dealloc " ) = = 0 ) {
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , AllocFunc > : : const_iterator it = mDealloc . find ( memorynode - > GetText ( ) ) ;
if ( it ! = mDealloc . end ( ) ) {
2016-05-22 17:18:50 +02:00
allocationId = it - > second . groupId ;
2014-04-19 13:15:06 +02:00
break ;
}
}
}
if ( allocationId = = 0 ) {
2014-12-12 22:16:20 +01:00
if ( nodename = = " memory " )
2018-06-17 16:55:02 +02:00
while ( ! ismemory ( + + mAllocId ) ) ;
2014-04-19 13:15:06 +02:00
else
2018-06-17 16:55:02 +02:00
while ( ! isresource ( + + mAllocId ) ) ;
allocationId = mAllocId ;
2014-04-19 13:15:06 +02:00
}
// add alloc/dealloc/use functions..
2013-07-02 07:18:19 +02:00
for ( const tinyxml2 : : XMLElement * memorynode = node - > FirstChildElement ( ) ; memorynode ; memorynode = memorynode - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string memorynodename = memorynode - > Name ( ) ;
2019-07-05 12:44:52 +02:00
if ( memorynodename = = " alloc " | | memorynodename = = " realloc " ) {
2019-04-30 20:45:48 +02:00
AllocFunc temp = { 0 } ;
2016-05-22 17:18:50 +02:00
temp . groupId = allocationId ;
2021-05-01 19:17:07 +02:00
temp . initData = memorynode - > BoolAttribute ( " init " , true ) ;
2021-05-01 18:40:20 +02:00
temp . arg = memorynode - > IntAttribute ( " arg " , - 1 ) ;
2019-03-17 10:55:15 +01:00
const char * bufferSize = memorynode - > Attribute ( " buffer-size " ) ;
2019-03-20 06:46:55 +01:00
if ( ! bufferSize )
temp . bufferSize = AllocFunc : : BufferSize : : none ;
2019-03-20 19:26:57 +01:00
else {
if ( std : : strncmp ( bufferSize , " malloc " , 6 ) = = 0 )
temp . bufferSize = AllocFunc : : BufferSize : : malloc ;
else if ( std : : strncmp ( bufferSize , " calloc " , 6 ) = = 0 )
temp . bufferSize = AllocFunc : : BufferSize : : calloc ;
else if ( std : : strncmp ( bufferSize , " strdup " , 6 ) = = 0 )
temp . bufferSize = AllocFunc : : BufferSize : : strdup ;
else
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , bufferSize ) ;
2019-03-30 05:58:23 +01:00
temp . bufferSizeArg1 = 1 ;
temp . bufferSizeArg2 = 2 ;
2019-03-20 19:26:57 +01:00
if ( bufferSize [ 6 ] = = 0 ) {
2019-03-30 05:58:23 +01:00
// use default values
2019-03-20 19:26:57 +01:00
} else if ( bufferSize [ 6 ] = = ' : ' & & bufferSize [ 7 ] > = ' 1 ' & & bufferSize [ 7 ] < = ' 5 ' ) {
temp . bufferSizeArg1 = bufferSize [ 7 ] - ' 0 ' ;
if ( bufferSize [ 8 ] = = ' , ' & & bufferSize [ 9 ] > = ' 1 ' & & bufferSize [ 9 ] < = ' 5 ' )
temp . bufferSizeArg2 = bufferSize [ 9 ] - ' 0 ' ;
} else
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , bufferSize ) ;
2019-03-20 19:26:57 +01:00
}
2019-03-17 10:55:15 +01:00
2021-05-01 18:40:20 +02:00
if ( memorynodename = = " realloc " )
temp . reallocArg = memorynode - > IntAttribute ( " realloc-arg " , 1 ) ;
2019-07-05 12:44:52 +02:00
if ( memorynodename ! = " realloc " )
mAlloc [ memorynode - > GetText ( ) ] = temp ;
else
mRealloc [ memorynode - > GetText ( ) ] = temp ;
2016-05-22 17:18:50 +02:00
} else if ( memorynodename = = " dealloc " ) {
2019-04-30 20:45:48 +02:00
AllocFunc temp = { 0 } ;
2016-05-22 17:18:50 +02:00
temp . groupId = allocationId ;
2021-05-01 18:40:20 +02:00
temp . arg = memorynode - > IntAttribute ( " arg " , 1 ) ;
2018-06-17 16:39:10 +02:00
mDealloc [ memorynode - > GetText ( ) ] = temp ;
2016-05-22 17:18:50 +02:00
} else if ( memorynodename = = " use " )
2016-12-06 12:31:16 +01:00
functions [ memorynode - > GetText ( ) ] . use = true ;
2013-07-02 07:18:19 +02:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( memorynodename ) ;
2013-07-02 07:18:19 +02:00
}
}
2014-09-10 17:03:31 +02:00
else if ( nodename = = " define " ) {
2014-02-06 09:22:07 +01:00
const char * name = node - > Attribute ( " name " ) ;
2014-02-15 08:41:17 +01:00
if ( name = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2014-02-06 09:22:07 +01:00
const char * value = node - > Attribute ( " value " ) ;
2014-02-15 08:41:17 +01:00
if ( value = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " value " ) ;
2019-02-28 22:34:08 +01:00
defines . push_back ( std : : string ( name ) +
2014-02-06 09:22:07 +01:00
" " +
2019-02-28 22:34:08 +01:00
value ) ;
2014-02-06 09:22:07 +01:00
}
2014-09-10 17:03:31 +02:00
else if ( nodename = = " function " ) {
2015-11-15 15:24:10 +01:00
const char * name = node - > Attribute ( " name " ) ;
if ( name = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2018-07-15 15:08:35 +02:00
for ( const std : : string & s : getnames ( name ) ) {
const Error & err = loadFunction ( node , s , unknown_elements ) ;
2015-08-09 21:27:57 +02:00
if ( err . errorcode ! = ErrorCode : : OK )
return err ;
2013-07-14 10:10:11 +02:00
}
2013-10-20 14:09:10 +02:00
}
2014-09-10 17:03:31 +02:00
else if ( nodename = = " reflection " ) {
2014-03-11 15:57:28 +01:00
for ( const tinyxml2 : : XMLElement * reflectionnode = node - > FirstChildElement ( ) ; reflectionnode ; reflectionnode = reflectionnode - > NextSiblingElement ( ) ) {
2015-01-10 22:18:57 +01:00
if ( strcmp ( reflectionnode - > Name ( ) , " call " ) ! = 0 ) {
unknown_elements . insert ( reflectionnode - > Name ( ) ) ;
continue ;
}
2014-03-11 15:57:28 +01:00
const char * const argString = reflectionnode - > Attribute ( " arg " ) ;
if ( ! argString )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " arg " ) ;
2014-03-11 15:57:28 +01:00
2023-04-08 22:29:09 +02:00
mReflection [ reflectionnode - > GetText ( ) ] = strToInt < int > ( argString ) ;
2014-03-11 15:57:28 +01:00
}
}
2014-09-10 17:03:31 +02:00
else if ( nodename = = " markup " ) {
2013-12-22 18:44:31 +01:00
const char * const extension = node - > Attribute ( " ext " ) ;
if ( ! extension )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " ext " ) ;
2018-06-17 16:39:10 +02:00
mMarkupExtensions . insert ( extension ) ;
2013-10-20 14:09:10 +02:00
2018-06-17 16:39:10 +02:00
mReportErrors [ extension ] = ( node - > Attribute ( " reporterrors " , " true " ) ! = nullptr ) ;
mProcessAfterCode [ extension ] = ( node - > Attribute ( " aftercode " , " true " ) ! = nullptr ) ;
2013-12-22 18:44:31 +01:00
for ( const tinyxml2 : : XMLElement * markupnode = node - > FirstChildElement ( ) ; markupnode ; markupnode = markupnode - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string markupnodename = markupnode - > Name ( ) ;
2014-09-10 17:03:31 +02:00
if ( markupnodename = = " keywords " ) {
2013-12-22 18:44:31 +01:00
for ( const tinyxml2 : : XMLElement * librarynode = markupnode - > FirstChildElement ( ) ; librarynode ; librarynode = librarynode - > NextSiblingElement ( ) ) {
2014-08-12 09:14:28 +02:00
if ( strcmp ( librarynode - > Name ( ) , " keyword " ) = = 0 ) {
const char * nodeName = librarynode - > Attribute ( " name " ) ;
if ( nodeName = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2018-06-17 16:39:10 +02:00
mKeywords [ extension ] . insert ( nodeName ) ;
2014-08-12 09:14:28 +02:00
} else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( librarynode - > Name ( ) ) ;
2013-10-20 14:09:10 +02:00
}
2013-12-22 18:44:31 +01:00
}
2013-10-20 14:09:10 +02:00
2014-09-10 17:03:31 +02:00
else if ( markupnodename = = " exported " ) {
2014-01-02 18:18:24 +01:00
for ( const tinyxml2 : : XMLElement * exporter = markupnode - > FirstChildElement ( ) ; exporter ; exporter = exporter - > NextSiblingElement ( ) ) {
2015-01-10 22:18:57 +01:00
if ( strcmp ( exporter - > Name ( ) , " exporter " ) ! = 0 ) {
unknown_elements . insert ( exporter - > Name ( ) ) ;
continue ;
}
2013-12-22 18:44:31 +01:00
const char * const prefix = exporter - > Attribute ( " prefix " ) ;
if ( ! prefix )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " prefix " ) ;
2013-12-22 18:44:31 +01:00
for ( const tinyxml2 : : XMLElement * e = exporter - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string ename = e - > Name ( ) ;
if ( ename = = " prefix " )
2018-06-17 16:39:10 +02:00
mExporters [ prefix ] . addPrefix ( e - > GetText ( ) ) ;
2014-12-12 22:16:20 +01:00
else if ( ename = = " suffix " )
2018-06-17 16:39:10 +02:00
mExporters [ prefix ] . addSuffix ( e - > GetText ( ) ) ;
2013-12-22 18:44:31 +01:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( ename ) ;
2013-12-22 18:44:31 +01:00
}
2013-10-20 14:09:10 +02:00
}
2013-12-22 18:44:31 +01:00
}
2013-10-20 14:09:10 +02:00
2014-09-10 17:03:31 +02:00
else if ( markupnodename = = " imported " ) {
2013-12-22 18:44:31 +01:00
for ( const tinyxml2 : : XMLElement * librarynode = markupnode - > FirstChildElement ( ) ; librarynode ; librarynode = librarynode - > NextSiblingElement ( ) ) {
if ( strcmp ( librarynode - > Name ( ) , " importer " ) = = 0 )
2018-06-17 16:39:10 +02:00
mImporters [ extension ] . insert ( librarynode - > GetText ( ) ) ;
2013-12-22 18:44:31 +01:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( librarynode - > Name ( ) ) ;
2013-10-20 14:09:10 +02:00
}
}
2014-09-10 17:03:31 +02:00
else if ( markupnodename = = " codeblocks " ) {
2013-12-23 12:27:00 +01:00
for ( const tinyxml2 : : XMLElement * blocknode = markupnode - > FirstChildElement ( ) ; blocknode ; blocknode = blocknode - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string blocknodename = blocknode - > Name ( ) ;
if ( blocknodename = = " block " ) {
2014-08-04 08:00:53 +02:00
const char * blockName = blocknode - > Attribute ( " name " ) ;
if ( blockName )
2018-06-17 16:39:10 +02:00
mExecutableBlocks [ extension ] . addBlock ( blockName ) ;
2014-12-12 22:16:20 +01:00
} else if ( blocknodename = = " structure " ) {
2013-12-22 18:44:31 +01:00
const char * start = blocknode - > Attribute ( " start " ) ;
2013-10-20 14:09:10 +02:00
if ( start )
2018-06-17 16:39:10 +02:00
mExecutableBlocks [ extension ] . setStart ( start ) ;
2013-12-22 18:44:31 +01:00
const char * end = blocknode - > Attribute ( " end " ) ;
2013-10-20 14:09:10 +02:00
if ( end )
2018-06-17 16:39:10 +02:00
mExecutableBlocks [ extension ] . setEnd ( end ) ;
2013-12-22 18:44:31 +01:00
const char * offset = blocknode - > Attribute ( " offset " ) ;
2013-10-20 14:09:10 +02:00
if ( offset )
2023-04-08 22:29:09 +02:00
mExecutableBlocks [ extension ] . setOffset ( strToInt < int > ( offset ) ) ;
2013-12-22 18:44:31 +01:00
}
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( blocknodename ) ;
2013-10-20 14:09:10 +02:00
}
}
2013-12-22 18:44:31 +01:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( markupnodename ) ;
2013-10-20 14:09:10 +02:00
}
2013-12-22 18:44:31 +01:00
}
2013-10-20 14:09:10 +02:00
2015-01-03 20:35:33 +01:00
else if ( nodename = = " container " ) {
const char * const id = node - > Attribute ( " id " ) ;
if ( ! id )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " id " ) ;
2015-01-03 20:35:33 +01:00
Container & container = containers [ id ] ;
const char * const inherits = node - > Attribute ( " inherits " ) ;
if ( inherits ) {
2018-04-04 21:51:31 +02:00
const std : : map < std : : string , Container > : : const_iterator i = containers . find ( inherits ) ;
2015-01-10 20:51:14 +01:00
if ( i ! = containers . end ( ) )
2015-01-03 20:35:33 +01:00
container = i - > second ; // Take values from parent and overwrite them if necessary
else
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , inherits ) ;
2015-01-03 20:35:33 +01:00
}
const char * const startPattern = node - > Attribute ( " startPattern " ) ;
2019-04-06 06:42:01 +02:00
if ( startPattern ) {
2015-01-03 20:35:33 +01:00
container . startPattern = startPattern ;
2019-04-06 06:42:01 +02:00
container . startPattern2 = container . startPattern + " !!:: " ;
}
2015-01-03 20:35:33 +01:00
const char * const endPattern = node - > Attribute ( " endPattern " ) ;
if ( endPattern )
container . endPattern = endPattern ;
2015-11-20 12:46:59 +01:00
const char * const itEndPattern = node - > Attribute ( " itEndPattern " ) ;
if ( itEndPattern )
container . itEndPattern = itEndPattern ;
2016-07-09 12:42:46 +02:00
const char * const opLessAllowed = node - > Attribute ( " opLessAllowed " ) ;
if ( opLessAllowed )
2022-08-14 12:44:09 +02:00
container . opLessAllowed = strcmp ( opLessAllowed , " true " ) = = 0 ;
2019-11-17 03:22:04 +01:00
const char * const hasInitializerListConstructor = node - > Attribute ( " hasInitializerListConstructor " ) ;
if ( hasInitializerListConstructor )
2022-08-14 12:44:09 +02:00
container . hasInitializerListConstructor = strcmp ( hasInitializerListConstructor , " true " ) = = 0 ;
2021-10-05 08:28:19 +02:00
const char * const view = node - > Attribute ( " view " ) ;
if ( view )
2022-08-14 12:44:09 +02:00
container . view = strcmp ( view , " true " ) = = 0 ;
2015-01-03 20:35:33 +01:00
for ( const tinyxml2 : : XMLElement * containerNode = node - > FirstChildElement ( ) ; containerNode ; containerNode = containerNode - > NextSiblingElement ( ) ) {
const std : : string containerNodeName = containerNode - > Name ( ) ;
if ( containerNodeName = = " size " | | containerNodeName = = " access " | | containerNodeName = = " other " ) {
for ( const tinyxml2 : : XMLElement * functionNode = containerNode - > FirstChildElement ( ) ; functionNode ; functionNode = functionNode - > NextSiblingElement ( ) ) {
2022-08-14 12:44:09 +02:00
if ( strcmp ( functionNode - > Name ( ) , " function " ) ! = 0 ) {
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( functionNode - > Name ( ) ) ;
continue ;
}
2015-01-03 20:35:33 +01:00
const char * const functionName = functionNode - > Attribute ( " name " ) ;
if ( ! functionName )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2015-01-03 20:35:33 +01:00
const char * const action_ptr = functionNode - > Attribute ( " action " ) ;
2019-07-17 11:39:30 +02:00
Container : : Action action = Container : : Action : : NO_ACTION ;
2015-01-03 20:35:33 +01:00
if ( action_ptr ) {
std : : string actionName = action_ptr ;
2021-08-23 09:03:48 +02:00
action = Container : : actionFrom ( actionName ) ;
if ( action = = Container : : Action : : NO_ACTION )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , actionName ) ;
2015-01-03 20:35:33 +01:00
}
const char * const yield_ptr = functionNode - > Attribute ( " yields " ) ;
2019-07-17 11:39:30 +02:00
Container : : Yield yield = Container : : Yield : : NO_YIELD ;
2015-01-03 20:35:33 +01:00
if ( yield_ptr ) {
std : : string yieldName = yield_ptr ;
2021-08-23 09:03:48 +02:00
yield = Container : : yieldFrom ( yieldName ) ;
if ( yield = = Container : : Yield : : NO_YIELD )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , yieldName ) ;
2015-01-03 20:35:33 +01:00
}
2023-06-05 22:12:30 +02:00
const char * const returnType = functionNode - > Attribute ( " returnType " ) ;
if ( returnType )
container . functions [ functionName ] . returnType = returnType ;
2015-01-03 20:35:33 +01:00
container . functions [ functionName ] . action = action ;
container . functions [ functionName ] . yield = yield ;
}
if ( containerNodeName = = " size " ) {
const char * const templateArg = containerNode - > Attribute ( " templateParameter " ) ;
if ( templateArg )
2023-04-08 22:29:09 +02:00
container . size_templateArgNo = strToInt < int > ( templateArg ) ;
2015-01-03 20:35:33 +01:00
} else if ( containerNodeName = = " access " ) {
2016-07-09 12:42:46 +02:00
const char * const indexArg = containerNode - > Attribute ( " indexOperator " ) ;
if ( indexArg )
2022-08-14 12:44:09 +02:00
container . arrayLike_indexOp = strcmp ( indexArg , " array-like " ) = = 0 ;
2015-01-03 20:35:33 +01:00
}
} else if ( containerNodeName = = " type " ) {
const char * const templateArg = containerNode - > Attribute ( " templateParameter " ) ;
if ( templateArg )
2023-04-08 22:29:09 +02:00
container . type_templateArgNo = strToInt < int > ( templateArg ) ;
2015-01-03 20:35:33 +01:00
2016-07-09 12:42:46 +02:00
const char * const string = containerNode - > Attribute ( " string " ) ;
if ( string )
2022-08-14 12:44:09 +02:00
container . stdStringLike = strcmp ( string , " std-like " ) = = 0 ;
2019-05-02 11:04:23 +02:00
const char * const associative = containerNode - > Attribute ( " associative " ) ;
if ( associative )
2022-08-14 12:44:09 +02:00
container . stdAssociativeLike = strcmp ( associative , " std-like " ) = = 0 ;
2020-04-03 13:16:57 +02:00
const char * const unstable = containerNode - > Attribute ( " unstable " ) ;
if ( unstable ) {
std : : string unstableType = unstable ;
if ( unstableType . find ( " erase " ) ! = std : : string : : npos )
container . unstableErase = true ;
if ( unstableType . find ( " insert " ) ! = std : : string : : npos )
container . unstableInsert = true ;
}
2021-12-11 15:16:54 +01:00
} else if ( containerNodeName = = " rangeItemRecordType " ) {
for ( const tinyxml2 : : XMLElement * memberNode = node - > FirstChildElement ( ) ; memberNode ; memberNode = memberNode - > NextSiblingElement ( ) ) {
const char * memberName = memberNode - > Attribute ( " name " ) ;
const char * memberTemplateParameter = memberNode - > Attribute ( " templateParameter " ) ;
struct Container : : RangeItemRecordTypeItem member ;
member . name = memberName ? memberName : " " ;
2023-04-08 22:29:09 +02:00
member . templateParameter = memberTemplateParameter ? strToInt < int > ( memberTemplateParameter ) : - 1 ;
2022-09-10 11:25:15 +02:00
container . rangeItemRecordType . emplace_back ( std : : move ( member ) ) ;
2021-12-11 15:16:54 +01:00
}
2015-01-03 20:35:33 +01:00
} else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( containerNodeName ) ;
2015-01-03 20:35:33 +01:00
}
}
2019-04-24 13:06:58 +02:00
else if ( nodename = = " smart-pointer " ) {
const char * className = node - > Attribute ( " class-name " ) ;
2021-07-20 21:30:27 +02:00
if ( ! className )
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " class-name " ) ;
SmartPointer & smartPointer = smartPointers [ className ] ;
2021-08-14 19:00:58 +02:00
smartPointer . name = className ;
2021-07-20 21:30:27 +02:00
for ( const tinyxml2 : : XMLElement * smartPointerNode = node - > FirstChildElement ( ) ; smartPointerNode ;
smartPointerNode = smartPointerNode - > NextSiblingElement ( ) ) {
const std : : string smartPointerNodeName = smartPointerNode - > Name ( ) ;
if ( smartPointerNodeName = = " unique " )
smartPointer . unique = true ;
}
2019-04-24 13:06:58 +02:00
}
2019-11-17 12:08:21 +01:00
else if ( nodename = = " type-checks " ) {
for ( const tinyxml2 : : XMLElement * checkNode = node - > FirstChildElement ( ) ; checkNode ; checkNode = checkNode - > NextSiblingElement ( ) ) {
const std : : string & checkName = checkNode - > Name ( ) ;
for ( const tinyxml2 : : XMLElement * checkTypeNode = checkNode - > FirstChildElement ( ) ; checkTypeNode ; checkTypeNode = checkTypeNode - > NextSiblingElement ( ) ) {
const std : : string checkTypeName = checkTypeNode - > Name ( ) ;
const char * typeName = checkTypeNode - > GetText ( ) ;
if ( ! typeName )
continue ;
if ( checkTypeName = = " check " )
mTypeChecks [ std : : pair < std : : string , std : : string > ( checkName , typeName ) ] = TypeCheck : : check ;
else if ( checkTypeName = = " suppress " )
mTypeChecks [ std : : pair < std : : string , std : : string > ( checkName , typeName ) ] = TypeCheck : : suppress ;
2022-09-30 07:25:33 +02:00
else if ( checkTypeName = = " checkFiniteLifetime " )
mTypeChecks [ std : : pair < std : : string , std : : string > ( checkName , typeName ) ] = TypeCheck : : checkFiniteLifetime ;
2019-11-17 12:08:21 +01:00
}
}
}
2014-09-10 17:03:31 +02:00
else if ( nodename = = " podtype " ) {
2014-06-08 12:09:00 +02:00
const char * const name = node - > Attribute ( " name " ) ;
if ( ! name )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2014-06-13 15:46:43 +02:00
PodType podType = { 0 } ;
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : NO ;
2019-09-29 16:48:25 +02:00
const char * const stdtype = node - > Attribute ( " stdtype " ) ;
if ( stdtype ) {
if ( std : : strcmp ( stdtype , " bool " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : BOOL ;
2019-09-29 16:48:25 +02:00
else if ( std : : strcmp ( stdtype , " char " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : CHAR ;
2019-09-29 16:48:25 +02:00
else if ( std : : strcmp ( stdtype , " short " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : SHORT ;
2019-09-29 16:48:25 +02:00
else if ( std : : strcmp ( stdtype , " int " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : INT ;
2019-09-29 16:48:25 +02:00
else if ( std : : strcmp ( stdtype , " long " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : LONG ;
2019-09-29 16:48:25 +02:00
else if ( std : : strcmp ( stdtype , " long long " ) = = 0 )
2021-01-08 10:29:01 +01:00
podType . stdtype = PodType : : Type : : LONGLONG ;
2019-09-29 16:48:25 +02:00
}
2015-01-30 20:27:48 +01:00
const char * const size = node - > Attribute ( " size " ) ;
2014-06-08 12:09:00 +02:00
if ( size )
2023-04-08 22:29:09 +02:00
podType . size = strToInt < unsigned int > ( size ) ;
2014-06-08 12:09:00 +02:00
const char * const sign = node - > Attribute ( " sign " ) ;
if ( sign )
podType . sign = * sign ;
2018-07-15 15:08:35 +02:00
for ( const std : : string & s : getnames ( name ) )
mPodTypes [ s ] = podType ;
2014-06-08 12:09:00 +02:00
}
2014-10-19 07:34:40 +02:00
else if ( nodename = = " platformtype " ) {
const char * const type_name = node - > Attribute ( " name " ) ;
if ( type_name = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
2014-10-19 07:34:40 +02:00
const char * value = node - > Attribute ( " value " ) ;
if ( value = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " value " ) ;
2014-10-19 07:34:40 +02:00
PlatformType type ;
2018-06-16 20:25:54 +02:00
type . mType = value ;
2014-10-19 07:34:40 +02:00
std : : set < std : : string > platform ;
for ( const tinyxml2 : : XMLElement * typenode = node - > FirstChildElement ( ) ; typenode ; typenode = typenode - > NextSiblingElement ( ) ) {
2014-12-12 22:16:20 +01:00
const std : : string typenodename = typenode - > Name ( ) ;
if ( typenodename = = " platform " ) {
2014-10-19 07:34:40 +02:00
const char * const type_attribute = typenode - > Attribute ( " type " ) ;
if ( type_attribute = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " type " ) ;
2014-10-19 07:34:40 +02:00
platform . insert ( type_attribute ) ;
2014-12-12 22:16:20 +01:00
} else if ( typenodename = = " signed " )
2019-11-20 15:37:09 +01:00
type . mSigned = true ;
2014-12-12 22:16:20 +01:00
else if ( typenodename = = " unsigned " )
2019-11-20 15:37:09 +01:00
type . mUnsigned = true ;
2014-12-12 22:16:20 +01:00
else if ( typenodename = = " long " )
2019-11-20 15:37:09 +01:00
type . mLong = true ;
2014-12-12 22:16:20 +01:00
else if ( typenodename = = " pointer " )
2019-11-20 15:37:09 +01:00
type . mPointer = true ;
2014-12-12 22:16:20 +01:00
else if ( typenodename = = " ptr_ptr " )
2019-11-20 15:37:09 +01:00
type . mPtrPtr = true ;
2014-12-12 22:16:20 +01:00
else if ( typenodename = = " const_ptr " )
2019-11-20 15:37:09 +01:00
type . mConstPtr = true ;
2014-10-19 07:34:40 +02:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( typenodename ) ;
2014-10-19 07:34:40 +02:00
}
if ( platform . empty ( ) ) {
2017-03-01 10:50:50 +01:00
const PlatformType * const type_ptr = platform_type ( type_name , emptyString ) ;
2014-10-19 07:34:40 +02:00
if ( type_ptr ) {
if ( * type_ptr = = type )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : DUPLICATE_PLATFORM_TYPE , type_name ) ;
return Error ( ErrorCode : : PLATFORM_TYPE_REDEFINED , type_name ) ;
2014-10-19 07:34:40 +02:00
}
2018-06-17 16:55:02 +02:00
mPlatformTypes [ type_name ] = type ;
2014-10-19 07:34:40 +02:00
} else {
2018-07-15 15:08:35 +02:00
for ( const std : : string & p : platform ) {
const PlatformType * const type_ptr = platform_type ( type_name , p ) ;
2014-10-19 07:34:40 +02:00
if ( type_ptr ) {
if ( * type_ptr = = type )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : DUPLICATE_PLATFORM_TYPE , type_name ) ;
return Error ( ErrorCode : : PLATFORM_TYPE_REDEFINED , type_name ) ;
2014-10-19 07:34:40 +02:00
}
2018-07-15 15:08:35 +02:00
mPlatforms [ p ] . mPlatformTypes [ type_name ] = type ;
2014-10-19 07:34:40 +02:00
}
}
}
2023-01-18 20:52:33 +01:00
else if ( nodename = = " entrypoint " ) {
const char * const type_name = node - > Attribute ( " name " ) ;
if ( type_name = = nullptr )
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " name " ) ;
mEntrypoints . emplace ( type_name ) ;
}
2013-12-22 18:44:31 +01:00
else
2015-01-10 22:18:57 +01:00
unknown_elements . insert ( nodename ) ;
}
if ( ! unknown_elements . empty ( ) ) {
std : : string str ;
2022-12-20 20:32:16 +01:00
for ( std : : set < std : : string > : : const_iterator i = unknown_elements . cbegin ( ) ; i ! = unknown_elements . cend ( ) ; ) {
2015-01-10 22:18:57 +01:00
str + = * i ;
if ( + + i ! = unknown_elements . end ( ) )
str + = " , " ;
}
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : UNKNOWN_ELEMENT , str ) ;
2013-07-02 07:18:19 +02:00
}
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : OK ) ;
2013-07-02 07:18:19 +02:00
}
2013-12-23 10:06:45 +01:00
2015-08-09 21:27:57 +02:00
Library : : Error Library : : loadFunction ( const tinyxml2 : : XMLElement * const node , const std : : string & name , std : : set < std : : string > & unknown_elements )
{
if ( name . empty ( ) )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : OK ) ;
2015-08-09 21:27:57 +02:00
2023-02-24 21:37:56 +01:00
// TODO: write debug warning if we modify an existing entry
2016-12-06 14:47:45 +01:00
Function & func = functions [ name ] ;
2016-09-04 14:14:21 +02:00
2015-08-09 21:27:57 +02:00
for ( const tinyxml2 : : XMLElement * functionnode = node - > FirstChildElement ( ) ; functionnode ; functionnode = functionnode - > NextSiblingElement ( ) ) {
const std : : string functionnodename = functionnode - > Name ( ) ;
2020-12-28 19:59:51 +01:00
if ( functionnodename = = " noreturn " ) {
2023-04-08 22:19:52 +02:00
const char * const text = functionnode - > GetText ( ) ;
if ( strcmp ( text , " false " ) = = 0 )
2020-12-28 19:59:51 +01:00
mNoReturn [ name ] = FalseTrueMaybe : : False ;
2023-04-08 22:19:52 +02:00
else if ( strcmp ( text , " maybe " ) = = 0 )
2020-12-28 19:59:51 +01:00
mNoReturn [ name ] = FalseTrueMaybe : : Maybe ;
else
mNoReturn [ name ] = FalseTrueMaybe : : True ; // Safe
} else if ( functionnodename = = " pure " )
2016-12-06 14:47:45 +01:00
func . ispure = true ;
2015-08-09 21:27:57 +02:00
else if ( functionnodename = = " const " ) {
2016-12-06 14:47:45 +01:00
func . ispure = true ;
func . isconst = true ; // a constant function is pure
2015-08-09 21:27:57 +02:00
} else if ( functionnodename = = " leak-ignore " )
2016-12-06 14:47:45 +01:00
func . leakignore = true ;
2021-06-12 21:16:52 +02:00
else if ( functionnodename = = " not-overlapping-data " ) {
NonOverlappingData nonOverlappingData ;
nonOverlappingData . ptr1Arg = functionnode - > IntAttribute ( " ptr1-arg " , - 1 ) ;
nonOverlappingData . ptr2Arg = functionnode - > IntAttribute ( " ptr2-arg " , - 1 ) ;
nonOverlappingData . sizeArg = functionnode - > IntAttribute ( " size-arg " , - 1 ) ;
2021-07-09 13:25:01 +02:00
nonOverlappingData . strlenArg = functionnode - > IntAttribute ( " strlen-arg " , - 1 ) ;
2021-06-12 21:16:52 +02:00
mNonOverlappingData [ name ] = nonOverlappingData ;
} else if ( functionnodename = = " use-retval " ) {
2020-11-05 13:35:52 +01:00
func . useretval = Library : : UseRetValType : : DEFAULT ;
if ( const char * type = functionnode - > Attribute ( " type " ) )
if ( std : : strcmp ( type , " error-code " ) = = 0 )
func . useretval = Library : : UseRetValType : : ERROR_CODE ;
} else if ( functionnodename = = " returnValue " ) {
2016-10-23 23:20:36 +02:00
if ( const char * expr = functionnode - > GetText ( ) )
2018-06-17 16:39:10 +02:00
mReturnValue [ name ] = expr ;
2016-10-23 23:20:36 +02:00
if ( const char * type = functionnode - > Attribute ( " type " ) )
2018-06-17 16:39:10 +02:00
mReturnValueType [ name ] = type ;
2016-11-01 14:08:42 +01:00
if ( const char * container = functionnode - > Attribute ( " container " ) )
2023-04-08 22:29:09 +02:00
mReturnValueContainer [ name ] = strToInt < int > ( container ) ;
2019-07-11 16:05:34 +02:00
if ( const char * unknownReturnValues = functionnode - > Attribute ( " unknownValues " ) ) {
if ( std : : strcmp ( unknownReturnValues , " all " ) = = 0 ) {
std : : vector < MathLib : : bigint > values { LLONG_MIN , LLONG_MAX } ;
mUnknownReturnValues [ name ] = values ;
}
2019-07-10 20:00:21 +02:00
}
2016-10-23 23:04:15 +02:00
} else if ( functionnodename = = " arg " ) {
2016-07-09 12:42:46 +02:00
const char * argNrString = functionnode - > Attribute ( " nr " ) ;
if ( ! argNrString )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " nr " ) ;
2017-03-14 17:41:34 +01:00
const bool bAnyArg = strcmp ( argNrString , " any " ) = = 0 ;
const bool bVariadicArg = strcmp ( argNrString , " variadic " ) = = 0 ;
2023-04-08 22:29:09 +02:00
const int nr = ( bAnyArg | | bVariadicArg ) ? - 1 : strToInt < int > ( argNrString ) ;
2016-12-06 14:47:45 +01:00
ArgumentChecks & ac = func . argumentChecks [ nr ] ;
2016-10-25 23:07:18 +02:00
ac . optional = functionnode - > Attribute ( " default " ) ! = nullptr ;
2017-03-14 17:41:34 +01:00
ac . variadic = bVariadicArg ;
2019-03-01 15:47:08 +01:00
const char * const argDirection = functionnode - > Attribute ( " direction " ) ;
if ( argDirection ) {
const size_t argDirLen = strlen ( argDirection ) ;
if ( ! strncmp ( argDirection , " in " , argDirLen ) ) {
ac . direction = ArgumentChecks : : Direction : : DIR_IN ;
} else if ( ! strncmp ( argDirection , " out " , argDirLen ) ) {
ac . direction = ArgumentChecks : : Direction : : DIR_OUT ;
} else if ( ! strncmp ( argDirection , " inout " , argDirLen ) ) {
ac . direction = ArgumentChecks : : Direction : : DIR_INOUT ;
}
}
2015-08-09 21:27:57 +02:00
for ( const tinyxml2 : : XMLElement * argnode = functionnode - > FirstChildElement ( ) ; argnode ; argnode = argnode - > NextSiblingElement ( ) ) {
const std : : string argnodename = argnode - > Name ( ) ;
2019-11-13 12:46:54 +01:00
int indirect = 0 ;
2020-06-07 20:18:54 +02:00
const char * const indirectStr = argnode - > Attribute ( " indirect " ) ;
2019-11-13 12:46:54 +01:00
if ( indirectStr )
2023-04-08 22:29:09 +02:00
indirect = strToInt < int > ( indirectStr ) ;
2015-08-09 21:27:57 +02:00
if ( argnodename = = " not-bool " )
2016-10-25 23:07:18 +02:00
ac . notbool = true ;
2015-08-09 21:27:57 +02:00
else if ( argnodename = = " not-null " )
2016-10-25 23:07:18 +02:00
ac . notnull = true ;
2015-08-09 21:27:57 +02:00
else if ( argnodename = = " not-uninit " )
2019-11-13 12:46:54 +01:00
ac . notuninit = indirect ;
2015-08-09 21:27:57 +02:00
else if ( argnodename = = " formatstr " )
2016-10-25 23:07:18 +02:00
ac . formatstr = true ;
2015-08-09 21:27:57 +02:00
else if ( argnodename = = " strz " )
2016-10-25 23:07:18 +02:00
ac . strz = true ;
2015-08-09 21:27:57 +02:00
else if ( argnodename = = " valid " ) {
// Validate the validation expression
const char * p = argnode - > GetText ( ) ;
2020-06-12 16:06:43 +02:00
if ( ! isCompliantValidationExpression ( p ) )
2023-04-08 22:19:52 +02:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , ( ! p ? " \" \" " : p ) ) ;
2015-08-09 21:27:57 +02:00
// Set validation expression
2023-04-08 22:19:52 +02:00
ac . valid = p ;
2022-05-14 16:05:18 +02:00
}
else if ( argnodename = = " minsize " ) {
2015-08-09 21:27:57 +02:00
const char * typeattr = argnode - > Attribute ( " type " ) ;
if ( ! typeattr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " type " ) ;
2015-08-09 21:27:57 +02:00
ArgumentChecks : : MinSize : : Type type ;
if ( strcmp ( typeattr , " strlen " ) = = 0 )
2019-03-09 22:14:02 +01:00
type = ArgumentChecks : : MinSize : : Type : : STRLEN ;
2015-08-09 21:27:57 +02:00
else if ( strcmp ( typeattr , " argvalue " ) = = 0 )
2019-03-09 22:14:02 +01:00
type = ArgumentChecks : : MinSize : : Type : : ARGVALUE ;
2015-08-09 21:27:57 +02:00
else if ( strcmp ( typeattr , " sizeof " ) = = 0 )
2019-03-09 22:14:02 +01:00
type = ArgumentChecks : : MinSize : : Type : : SIZEOF ;
2015-08-09 21:27:57 +02:00
else if ( strcmp ( typeattr , " mul " ) = = 0 )
2019-03-09 22:14:02 +01:00
type = ArgumentChecks : : MinSize : : Type : : MUL ;
2019-03-17 14:22:26 +01:00
else if ( strcmp ( typeattr , " value " ) = = 0 )
type = ArgumentChecks : : MinSize : : Type : : VALUE ;
2015-08-09 21:27:57 +02:00
else
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , typeattr ) ;
2015-08-09 21:27:57 +02:00
2019-03-17 14:22:26 +01:00
if ( type = = ArgumentChecks : : MinSize : : Type : : VALUE ) {
const char * valueattr = argnode - > Attribute ( " value " ) ;
if ( ! valueattr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " value " ) ;
2019-03-17 14:22:26 +01:00
long long minsizevalue = 0 ;
try {
2023-04-08 22:29:09 +02:00
minsizevalue = strToInt < long long > ( valueattr ) ;
} catch ( const std : : runtime_error & ) {
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , valueattr ) ;
2019-03-17 14:22:26 +01:00
}
if ( minsizevalue < = 0 )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , valueattr ) ;
2019-03-17 14:22:26 +01:00
ac . minsizes . emplace_back ( type , 0 ) ;
ac . minsizes . back ( ) . value = minsizevalue ;
} else {
const char * argattr = argnode - > Attribute ( " arg " ) ;
if ( ! argattr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " arg " ) ;
2019-03-17 14:22:26 +01:00
if ( strlen ( argattr ) ! = 1 | | argattr [ 0 ] < ' 0 ' | | argattr [ 0 ] > ' 9 ' )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , argattr ) ;
2019-03-17 14:22:26 +01:00
ac . minsizes . reserve ( type = = ArgumentChecks : : MinSize : : Type : : MUL ? 2 : 1 ) ;
ac . minsizes . emplace_back ( type , argattr [ 0 ] - ' 0 ' ) ;
if ( type = = ArgumentChecks : : MinSize : : Type : : MUL ) {
const char * arg2attr = argnode - > Attribute ( " arg2 " ) ;
if ( ! arg2attr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " arg2 " ) ;
2019-03-17 14:22:26 +01:00
if ( strlen ( arg2attr ) ! = 1 | | arg2attr [ 0 ] < ' 0 ' | | arg2attr [ 0 ] > ' 9 ' )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , arg2attr ) ;
2019-03-17 14:22:26 +01:00
ac . minsizes . back ( ) . arg2 = arg2attr [ 0 ] - ' 0 ' ;
}
2015-08-09 21:27:57 +02:00
}
2022-08-29 12:24:58 +02:00
const char * baseTypeAttr = argnode - > Attribute ( " baseType " ) ; // used by VALUE, ARGVALUE
if ( baseTypeAttr )
ac . minsizes . back ( ) . baseType = baseTypeAttr ;
2015-08-09 21:27:57 +02:00
}
2016-10-25 23:07:18 +02:00
else if ( argnodename = = " iterator " ) {
2016-12-06 12:31:16 +01:00
ac . iteratorInfo . it = true ;
const char * str = argnode - > Attribute ( " type " ) ;
2021-05-01 18:40:20 +02:00
ac . iteratorInfo . first = ( str & & std : : strcmp ( str , " first " ) = = 0 ) ;
ac . iteratorInfo . last = ( str & & std : : strcmp ( str , " last " ) = = 0 ) ;
ac . iteratorInfo . container = argnode - > IntAttribute ( " container " , 0 ) ;
2016-10-25 23:07:18 +02:00
}
2015-08-09 21:27:57 +02:00
else
unknown_elements . insert ( argnodename ) ;
}
2019-11-13 12:46:54 +01:00
if ( ac . notuninit = = 0 )
ac . notuninit = ac . notnull ? 1 : 0 ;
2015-08-09 21:27:57 +02:00
} else if ( functionnodename = = " ignorefunction " ) {
2016-12-06 14:47:45 +01:00
func . ignore = true ;
2015-08-09 21:27:57 +02:00
} else if ( functionnodename = = " formatstr " ) {
2016-12-06 14:47:45 +01:00
func . formatstr = true ;
2015-08-09 21:27:57 +02:00
const tinyxml2 : : XMLAttribute * scan = functionnode - > FindAttribute ( " scan " ) ;
const tinyxml2 : : XMLAttribute * secure = functionnode - > FindAttribute ( " secure " ) ;
2016-12-06 14:47:45 +01:00
func . formatstr_scan = scan & & scan - > BoolValue ( ) ;
func . formatstr_secure = secure & & secure - > BoolValue ( ) ;
2015-11-21 20:24:30 +01:00
} else if ( functionnodename = = " warn " ) {
WarnInfo wi ;
const char * const severity = functionnode - > Attribute ( " severity " ) ;
if ( severity = = nullptr )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " severity " ) ;
2015-11-21 20:24:30 +01:00
wi . severity = Severity : : fromString ( severity ) ;
const char * const cstd = functionnode - > Attribute ( " cstd " ) ;
if ( cstd ) {
if ( ! wi . standards . setC ( cstd ) )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , cstd ) ;
2015-11-21 20:24:30 +01:00
} else
wi . standards . c = Standards : : C89 ;
const char * const cppstd = functionnode - > Attribute ( " cppstd " ) ;
if ( cppstd ) {
if ( ! wi . standards . setCPP ( cppstd ) )
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , cppstd ) ;
2015-11-21 20:24:30 +01:00
} else
wi . standards . cpp = Standards : : CPP03 ;
const char * const reason = functionnode - > Attribute ( " reason " ) ;
const char * const alternatives = functionnode - > Attribute ( " alternatives " ) ;
if ( reason & & alternatives ) {
// Construct message
wi . message = std : : string ( reason ) + " function ' " + name + " ' called. It is recommended to use " ;
std : : vector < std : : string > alt = getnames ( alternatives ) ;
for ( std : : size_t i = 0 ; i < alt . size ( ) ; + + i ) {
wi . message + = " ' " + alt [ i ] + " ' " ;
if ( i = = alt . size ( ) - 1 )
wi . message + = " instead. " ;
else if ( i = = alt . size ( ) - 2 )
wi . message + = " or " ;
else
wi . message + = " , " ;
}
2019-02-28 06:19:42 +01:00
} else {
const char * const message = functionnode - > GetText ( ) ;
if ( ! message ) {
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : MISSING_ATTRIBUTE , " \" reason \" and \" alternatives \" or some text. " ) ;
2019-02-28 06:19:42 +01:00
} else
wi . message = message ;
}
2015-11-21 20:24:30 +01:00
functionwarn [ name ] = wi ;
2021-08-23 09:03:48 +02:00
} else if ( functionnodename = = " container " ) {
const char * const action_ptr = functionnode - > Attribute ( " action " ) ;
Container : : Action action = Container : : Action : : NO_ACTION ;
if ( action_ptr ) {
std : : string actionName = action_ptr ;
action = Container : : actionFrom ( actionName ) ;
if ( action = = Container : : Action : : NO_ACTION )
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , actionName ) ;
}
func . containerAction = action ;
const char * const yield_ptr = functionnode - > Attribute ( " yields " ) ;
Container : : Yield yield = Container : : Yield : : NO_YIELD ;
if ( yield_ptr ) {
std : : string yieldName = yield_ptr ;
yield = Container : : yieldFrom ( yieldName ) ;
if ( yield = = Container : : Yield : : NO_YIELD )
return Error ( ErrorCode : : BAD_ATTRIBUTE_VALUE , yieldName ) ;
}
func . containerYield = yield ;
2023-06-05 22:12:30 +02:00
const char * const returnType = functionnode - > Attribute ( " returnType " ) ;
if ( returnType )
func . returnType = returnType ;
2015-08-09 21:27:57 +02:00
} else
unknown_elements . insert ( functionnodename ) ;
}
2021-01-08 10:29:01 +01:00
return Error ( ErrorCode : : OK ) ;
2015-08-09 21:27:57 +02:00
}
2018-07-15 23:05:48 +02:00
bool Library : : isIntArgValid ( const Token * ftok , int argnr , const MathLib : : bigint argvalue ) const
2013-12-23 10:06:45 +01:00
{
2015-01-08 19:31:41 +01:00
const ArgumentChecks * ac = getarg ( ftok , argnr ) ;
2013-12-23 10:06:45 +01:00
if ( ! ac | | ac - > valid . empty ( ) )
return true ;
2018-07-15 22:47:56 +02:00
else if ( ac - > valid . find ( ' . ' ) ! = std : : string : : npos )
2018-07-15 23:05:48 +02:00
return isFloatArgValid ( ftok , argnr , argvalue ) ;
2017-08-09 20:00:26 +02:00
TokenList tokenList ( nullptr ) ;
2018-07-15 22:47:56 +02:00
gettokenlistfromvalid ( ac - > valid , tokenList ) ;
2013-12-23 10:06:45 +01:00
for ( const Token * tok = tokenList . front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > isNumber ( ) & & argvalue = = MathLib : : toLongNumber ( tok - > str ( ) ) )
return true ;
2014-06-08 18:12:11 +02:00
if ( Token : : Match ( tok , " %num% : %num% " ) & & argvalue > = MathLib : : toLongNumber ( tok - > str ( ) ) & & argvalue < = MathLib : : toLongNumber ( tok - > strAt ( 2 ) ) )
2013-12-23 10:06:45 +01:00
return true ;
2014-06-08 18:12:11 +02:00
if ( Token : : Match ( tok , " %num% : , " ) & & argvalue > = MathLib : : toLongNumber ( tok - > str ( ) ) )
2013-12-23 10:06:45 +01:00
return true ;
2014-06-08 18:12:11 +02:00
if ( ( ! tok - > previous ( ) | | tok - > previous ( ) - > str ( ) = = " , " ) & & Token : : Match ( tok , " : %num% " ) & & argvalue < = MathLib : : toLongNumber ( tok - > strAt ( 1 ) ) )
2013-12-23 10:06:45 +01:00
return true ;
}
return false ;
}
2014-03-06 06:16:14 +01:00
2018-07-15 23:05:48 +02:00
bool Library : : isFloatArgValid ( const Token * ftok , int argnr , double argvalue ) const
2018-07-15 22:47:56 +02:00
{
const ArgumentChecks * ac = getarg ( ftok , argnr ) ;
if ( ! ac | | ac - > valid . empty ( ) )
return true ;
TokenList tokenList ( nullptr ) ;
gettokenlistfromvalid ( ac - > valid , tokenList ) ;
for ( const Token * tok = tokenList . front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " %num% : %num% " ) & & argvalue > = MathLib : : toDoubleNumber ( tok - > str ( ) ) & & argvalue < = MathLib : : toDoubleNumber ( tok - > strAt ( 2 ) ) )
return true ;
if ( Token : : Match ( tok , " %num% : , " ) & & argvalue > = MathLib : : toDoubleNumber ( tok - > str ( ) ) )
return true ;
if ( ( ! tok - > previous ( ) | | tok - > previous ( ) - > str ( ) = = " , " ) & & Token : : Match ( tok , " : %num% " ) & & argvalue < = MathLib : : toDoubleNumber ( tok - > strAt ( 1 ) ) )
return true ;
2022-05-14 16:05:18 +02:00
if ( Token : : Match ( tok , " %num% " ) & & MathLib : : isFloat ( tok - > str ( ) ) & & MathLib : : isEqual ( tok - > str ( ) , MathLib : : toString ( argvalue ) ) )
return true ;
if ( Token : : Match ( tok , " ! %num% " ) & & MathLib : : isFloat ( tok - > next ( ) - > str ( ) ) )
return MathLib : : isNotEqual ( tok - > next ( ) - > str ( ) , MathLib : : toString ( argvalue ) ) ;
2018-07-15 22:47:56 +02:00
}
return false ;
}
2023-03-02 22:05:41 +01:00
std : : string Library : : getFunctionName ( const Token * ftok , bool & error ) const
2015-08-10 09:41:06 +02:00
{
if ( ! ftok ) {
2023-03-02 22:05:41 +01:00
error = true ;
2015-08-10 09:41:06 +02:00
return " " ;
}
2016-09-04 14:14:21 +02:00
if ( ftok - > isName ( ) ) {
for ( const Scope * scope = ftok - > scope ( ) ; scope ; scope = scope - > nestedIn ) {
if ( ! scope - > isClassOrStruct ( ) )
continue ;
2017-08-28 17:19:03 +02:00
const std : : vector < Type : : BaseInfo > & derivedFrom = scope - > definedType - > derivedFrom ;
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & baseInfo : derivedFrom ) {
2016-09-04 14:14:21 +02:00
const std : : string name ( baseInfo . name + " :: " + ftok - > str ( ) ) ;
2016-12-06 14:47:45 +01:00
if ( functions . find ( name ) ! = functions . end ( ) & & matchArguments ( ftok , name ) )
2016-09-04 14:14:21 +02:00
return name ;
}
}
2015-08-10 09:41:06 +02:00
return ftok - > str ( ) ;
2016-09-04 14:14:21 +02:00
}
2015-08-10 09:41:06 +02:00
if ( ftok - > str ( ) = = " :: " ) {
if ( ! ftok - > astOperand2 ( ) )
2016-09-04 14:14:21 +02:00
return getFunctionName ( ftok - > astOperand1 ( ) , error ) ;
return getFunctionName ( ftok - > astOperand1 ( ) , error ) + " :: " + getFunctionName ( ftok - > astOperand2 ( ) , error ) ;
2015-08-10 09:41:06 +02:00
}
if ( ftok - > str ( ) = = " . " & & ftok - > astOperand1 ( ) ) {
2023-04-01 09:38:40 +02:00
const std : : string type = astCanonicalType ( ftok - > astOperand1 ( ) , ftok - > originalName ( ) = = " -> " ) ;
2015-08-10 09:41:06 +02:00
if ( type . empty ( ) ) {
2023-03-02 22:05:41 +01:00
error = true ;
2015-08-10 09:41:06 +02:00
return " " ;
}
2016-09-04 14:14:21 +02:00
return type + " :: " + getFunctionName ( ftok - > astOperand2 ( ) , error ) ;
2015-08-10 09:41:06 +02:00
}
2023-03-02 22:05:41 +01:00
error = true ;
2015-08-10 09:41:06 +02:00
return " " ;
}
2016-09-04 14:14:21 +02:00
std : : string Library : : getFunctionName ( const Token * ftok ) const
2015-08-09 19:55:33 +02:00
{
2023-01-18 20:38:37 +01:00
if ( ! Token : : Match ( ftok , " %name% )| ( " ) & & ( ftok - > strAt ( - 1 ) ! = " & " | | ftok - > previous ( ) - > astOperand2 ( ) ) )
2015-08-10 09:41:06 +02:00
return " " ;
// Lookup function name using AST..
if ( ftok - > astParent ( ) ) {
bool error = false ;
2019-04-15 06:37:27 +02:00
const Token * tok = ftok - > astParent ( ) - > isUnaryOp ( " & " ) ? ftok - > astParent ( ) - > astOperand1 ( ) : ftok - > next ( ) - > astOperand1 ( ) ;
2023-03-02 22:05:41 +01:00
const std : : string ret = getFunctionName ( tok , error ) ;
2015-08-10 09:41:06 +02:00
return error ? std : : string ( ) : ret ;
}
// Lookup function name without using AST..
2015-08-09 19:55:33 +02:00
if ( Token : : simpleMatch ( ftok - > previous ( ) , " . " ) )
return " " ;
if ( ! Token : : Match ( ftok - > tokAt ( - 2 ) , " %name% :: " ) )
return ftok - > str ( ) ;
std : : string ret ( ftok - > str ( ) ) ;
ftok = ftok - > tokAt ( - 2 ) ;
while ( Token : : Match ( ftok , " %name% :: " ) ) {
ret = ftok - > str ( ) + " :: " + ret ;
ftok = ftok - > tokAt ( - 2 ) ;
}
return ret ;
}
2015-10-03 20:51:45 +02:00
bool Library : : isnullargbad ( const Token * ftok , int argnr ) const
{
const ArgumentChecks * arg = getarg ( ftok , argnr ) ;
if ( ! arg ) {
// scan format string argument should not be null
2016-09-04 14:14:21 +02:00
const std : : string funcname = getFunctionName ( ftok ) ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( funcname ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) & & it - > second . formatstr & & it - > second . formatstr_scan )
2015-10-03 20:51:45 +02:00
return true ;
}
return arg & & arg - > notnull ;
}
2020-06-07 20:18:54 +02:00
bool Library : : isuninitargbad ( const Token * ftok , int argnr , int indirect , bool * hasIndirect ) const
2015-10-03 18:35:16 +02:00
{
const ArgumentChecks * arg = getarg ( ftok , argnr ) ;
if ( ! arg ) {
// non-scan format string argument should not be uninitialized
2016-09-04 14:14:21 +02:00
const std : : string funcname = getFunctionName ( ftok ) ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( funcname ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) & & it - > second . formatstr & & ! it - > second . formatstr_scan )
2015-10-03 18:35:16 +02:00
return true ;
}
2020-06-07 20:18:54 +02:00
if ( hasIndirect & & arg & & arg - > notuninit > = 1 )
* hasIndirect = true ;
2019-11-13 12:46:54 +01:00
return arg & & arg - > notuninit > = indirect ;
2015-10-03 18:35:16 +02:00
}
2016-05-22 17:18:50 +02:00
/** get allocation info for function */
2019-07-05 12:44:52 +02:00
const Library : : AllocFunc * Library : : getAllocFuncInfo ( const Token * tok ) const
2015-08-10 18:36:09 +02:00
{
2016-09-04 14:14:21 +02:00
const std : : string funcname = getFunctionName ( tok ) ;
2018-06-17 16:32:08 +02:00
return isNotLibraryFunction ( tok ) & & functions . find ( funcname ) ! = functions . end ( ) ? nullptr : getAllocDealloc ( mAlloc , funcname ) ;
2015-08-10 18:36:09 +02:00
}
2016-05-22 17:18:50 +02:00
/** get deallocation info for function */
2019-07-05 12:44:52 +02:00
const Library : : AllocFunc * Library : : getDeallocFuncInfo ( const Token * tok ) const
2015-08-10 18:36:09 +02:00
{
2016-09-04 14:14:21 +02:00
const std : : string funcname = getFunctionName ( tok ) ;
2018-06-17 16:39:10 +02:00
return isNotLibraryFunction ( tok ) & & functions . find ( funcname ) ! = functions . end ( ) ? nullptr : getAllocDealloc ( mDealloc , funcname ) ;
2016-05-22 17:18:50 +02:00
}
2019-07-05 12:44:52 +02:00
/** get reallocation info for function */
const Library : : AllocFunc * Library : : getReallocFuncInfo ( const Token * tok ) const
{
const std : : string funcname = getFunctionName ( tok ) ;
return isNotLibraryFunction ( tok ) & & functions . find ( funcname ) ! = functions . end ( ) ? nullptr : getAllocDealloc ( mRealloc , funcname ) ;
}
2016-05-22 17:18:50 +02:00
/** get allocation id for function */
2019-07-05 12:44:52 +02:00
int Library : : getAllocId ( const Token * tok , int arg ) const
2016-05-22 17:18:50 +02:00
{
2019-07-05 12:44:52 +02:00
const Library : : AllocFunc * af = getAllocFuncInfo ( tok ) ;
2016-05-22 17:18:50 +02:00
return ( af & & af - > arg = = arg ) ? af - > groupId : 0 ;
}
/** get deallocation id for function */
2019-07-05 12:44:52 +02:00
int Library : : getDeallocId ( const Token * tok , int arg ) const
{
const Library : : AllocFunc * af = getDeallocFuncInfo ( tok ) ;
return ( af & & af - > arg = = arg ) ? af - > groupId : 0 ;
}
/** get reallocation id for function */
int Library : : getReallocId ( const Token * tok , int arg ) const
2016-05-22 17:18:50 +02:00
{
2019-07-05 12:44:52 +02:00
const Library : : AllocFunc * af = getReallocFuncInfo ( tok ) ;
2016-05-22 17:18:50 +02:00
return ( af & & af - > arg = = arg ) ? af - > groupId : 0 ;
2015-08-10 18:36:09 +02:00
}
2015-01-08 19:31:41 +01:00
const Library : : ArgumentChecks * Library : : getarg ( const Token * ftok , int argnr ) const
2014-03-06 06:16:14 +01:00
{
2015-01-08 19:31:41 +01:00
if ( isNotLibraryFunction ( ftok ) )
return nullptr ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it1 = functions . find ( getFunctionName ( ftok ) ) ;
2016-12-06 12:31:16 +01:00
if ( it1 = = functions . cend ( ) )
2014-03-06 06:16:14 +01:00
return nullptr ;
2016-12-06 12:31:16 +01:00
const std : : map < int , ArgumentChecks > : : const_iterator it2 = it1 - > second . argumentChecks . find ( argnr ) ;
if ( it2 ! = it1 - > second . argumentChecks . cend ( ) )
2014-03-06 06:16:14 +01:00
return & it2 - > second ;
2016-12-06 12:31:16 +01:00
const std : : map < int , ArgumentChecks > : : const_iterator it3 = it1 - > second . argumentChecks . find ( - 1 ) ;
if ( it3 ! = it1 - > second . argumentChecks . cend ( ) )
2014-03-06 06:16:14 +01:00
return & it3 - > second ;
2014-03-06 06:27:01 +01:00
return nullptr ;
2014-03-06 06:16:14 +01:00
}
2014-06-22 19:13:15 +02:00
bool Library : : isScopeNoReturn ( const Token * end , std : : string * unknownFunc ) const
{
if ( unknownFunc )
unknownFunc - > clear ( ) ;
2018-08-21 06:32:33 +02:00
if ( Token : : Match ( end - > tokAt ( - 2 ) , " !!{ ; } " ) ) {
const Token * lastTop = end - > tokAt ( - 2 ) - > astTop ( ) ;
if ( Token : : simpleMatch ( lastTop , " << " ) & &
Token : : simpleMatch ( lastTop - > astOperand1 ( ) , " ( " ) & &
Token : : Match ( lastTop - > astOperand1 ( ) - > previous ( ) , " %name% ( " ) )
return isnoreturn ( lastTop - > astOperand1 ( ) - > previous ( ) ) ;
}
2014-06-22 19:13:15 +02:00
if ( ! Token : : simpleMatch ( end - > tokAt ( - 2 ) , " ) ; } " ) )
return false ;
const Token * funcname = end - > linkAt ( - 2 ) - > previous ( ) ;
const Token * start = funcname ;
2015-02-01 15:21:09 +01:00
if ( Token : : Match ( funcname - > tokAt ( - 3 ) , " ( * %name% ) " ) ) {
2014-06-22 19:13:15 +02:00
funcname = funcname - > previous ( ) ;
start = funcname - > tokAt ( - 3 ) ;
} else if ( funcname - > isName ( ) ) {
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( start , " %name%|.|:: " ) )
2014-06-22 19:13:15 +02:00
start = start - > previous ( ) ;
} else {
return false ;
}
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( start , " [;{}] " ) & & Token : : Match ( funcname , " %name% )| ( " ) ) {
2022-09-04 10:26:31 +02:00
if ( funcname - > isKeyword ( ) )
return false ;
2014-06-22 19:13:15 +02:00
if ( funcname - > str ( ) = = " exit " )
return true ;
2015-01-08 19:31:41 +01:00
if ( ! isnotnoreturn ( funcname ) ) {
if ( unknownFunc & & ! isnoreturn ( funcname ) )
2014-06-22 19:13:15 +02:00
* unknownFunc = funcname - > str ( ) ;
return true ;
}
}
return false ;
}
2023-05-28 14:33:41 +02:00
const Library : : Container * Library : : detectContainerInternal ( const Token * typeStart , DetectContainer detect , bool * isIterator , bool withoutStd ) const
2015-01-03 20:35:33 +01:00
{
2022-06-11 23:21:25 +02:00
for ( const std : : pair < const std : : string , Library : : Container > & c : containers ) {
2022-06-11 13:51:55 +02:00
const Container & container = c . second ;
2015-01-03 20:35:33 +01:00
if ( container . startPattern . empty ( ) )
continue ;
2023-05-28 14:33:41 +02:00
const int offset = ( withoutStd & & container . startPattern2 . find ( " std :: " ) = = 0 ) ? 7 : 0 ;
2022-08-20 12:14:55 +02:00
// If endPattern is undefined, it will always match, but itEndPattern has to be defined.
if ( detect ! = IteratorOnly & & container . endPattern . empty ( ) ) {
2023-05-28 14:33:41 +02:00
if ( ! Token : : Match ( typeStart , container . startPattern2 . c_str ( ) + offset ) )
2022-09-23 20:19:56 +02:00
continue ;
2022-08-20 12:14:55 +02:00
if ( isIterator )
* isIterator = false ;
2018-06-23 16:42:36 +02:00
return & container ;
2022-08-20 12:14:55 +02:00
}
2018-06-23 16:42:36 +02:00
for ( const Token * tok = typeStart ; tok & & ! tok - > varId ( ) ; tok = tok - > next ( ) ) {
2022-09-23 20:19:56 +02:00
if ( ! tok - > link ( ) )
continue ;
2023-05-28 14:33:41 +02:00
const bool matchedStartPattern = Token : : Match ( typeStart , container . startPattern2 . c_str ( ) + offset ) ;
2022-09-23 20:19:56 +02:00
if ( detect ! = ContainerOnly & & matchedStartPattern & & Token : : Match ( tok - > link ( ) , container . itEndPattern . c_str ( ) ) ) {
if ( isIterator )
* isIterator = true ;
return & container ;
}
if ( detect ! = IteratorOnly & & matchedStartPattern & & Token : : Match ( tok - > link ( ) , container . endPattern . c_str ( ) ) ) {
if ( isIterator )
* isIterator = false ;
return & container ;
2015-01-03 20:35:33 +01:00
}
2022-09-23 20:19:56 +02:00
break ;
2015-01-03 20:35:33 +01:00
}
}
return nullptr ;
}
2015-08-09 19:55:33 +02:00
2022-08-20 12:14:55 +02:00
const Library : : Container * Library : : detectContainer ( const Token * typeStart ) const
{
return detectContainerInternal ( typeStart , ContainerOnly ) ;
}
const Library : : Container * Library : : detectIterator ( const Token * typeStart ) const
{
return detectContainerInternal ( typeStart , IteratorOnly ) ;
}
2023-05-28 14:33:41 +02:00
const Library : : Container * Library : : detectContainerOrIterator ( const Token * typeStart , bool * isIterator , bool withoutStd ) const
2022-04-07 06:47:15 +02:00
{
2022-08-20 12:14:55 +02:00
bool res ;
2023-05-28 14:33:41 +02:00
const Library : : Container * c = detectContainerInternal ( typeStart , Both , & res , withoutStd ) ;
2022-04-07 06:47:15 +02:00
if ( c & & isIterator )
2022-08-20 12:14:55 +02:00
* isIterator = res ;
2022-04-07 06:47:15 +02:00
return c ;
}
2018-03-24 07:58:37 +01:00
bool Library : : isContainerYield ( const Token * const cond , Library : : Container : : Yield y , const std : : string & fallback )
{
2018-03-24 12:30:11 +01:00
if ( ! cond )
2018-03-24 07:58:37 +01:00
return false ;
if ( cond - > str ( ) = = " ( " ) {
const Token * tok = cond - > astOperand1 ( ) ;
2018-03-24 12:30:11 +01:00
if ( tok & & tok - > str ( ) = = " . " ) {
if ( tok - > astOperand1 ( ) & & tok - > astOperand1 ( ) - > valueType ( ) ) {
if ( const Library : : Container * container = tok - > astOperand1 ( ) - > valueType ( ) - > container ) {
2018-03-24 07:58:37 +01:00
return tok - > astOperand2 ( ) & & y = = container - > getYield ( tok - > astOperand2 ( ) - > str ( ) ) ;
}
2018-03-24 12:30:11 +01:00
} else if ( ! fallback . empty ( ) ) {
2018-03-24 07:58:37 +01:00
return Token : : simpleMatch ( cond , " ( ) " ) & & cond - > previous ( ) - > str ( ) = = fallback ;
}
}
}
return false ;
}
2015-01-27 17:55:18 +01:00
// returns true if ftok is not a library function
bool Library : : isNotLibraryFunction ( const Token * ftok ) const
{
2023-03-20 19:40:57 +01:00
if ( ftok - > isKeyword ( ) | | ftok - > isStandardType ( ) )
return true ;
2015-03-08 16:13:32 +01:00
if ( ftok - > function ( ) & & ftok - > function ( ) - > nestedIn & & ftok - > function ( ) - > nestedIn - > type ! = Scope : : eGlobal )
return true ;
2017-10-11 17:15:28 +02:00
2015-03-01 11:46:43 +01:00
// variables are not library functions.
if ( ftok - > varId ( ) )
return true ;
2016-09-04 14:14:21 +02:00
return ! matchArguments ( ftok , getFunctionName ( ftok ) ) ;
}
bool Library : : matchArguments ( const Token * ftok , const std : : string & functionName ) const
{
2023-01-18 20:38:37 +01:00
if ( functionName . empty ( ) )
return false ;
2022-05-13 06:51:07 +02:00
const int callargs = numberOfArgumentsWithoutAst ( ftok ) ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( functionName ) ;
2016-12-06 12:31:16 +01:00
if ( it = = functions . cend ( ) )
2023-06-02 15:24:18 +02:00
return false ;
2015-01-27 17:55:18 +01:00
int args = 0 ;
2016-07-09 12:42:46 +02:00
int firstOptionalArg = - 1 ;
2022-06-11 23:21:25 +02:00
for ( const std : : pair < const int , Library : : ArgumentChecks > & argCheck : it - > second . argumentChecks ) {
2022-06-11 13:51:55 +02:00
if ( argCheck . first > args )
args = argCheck . first ;
if ( argCheck . second . optional & & ( firstOptionalArg = = - 1 | | firstOptionalArg > argCheck . first ) )
firstOptionalArg = argCheck . first ;
2016-07-09 12:42:46 +02:00
2022-06-11 13:51:55 +02:00
if ( argCheck . second . formatstr | | argCheck . second . variadic )
2016-09-04 14:14:21 +02:00
return args < = callargs ;
2015-01-27 17:55:18 +01:00
}
2016-09-04 14:14:21 +02:00
return ( firstOptionalArg < 0 ) ? args = = callargs : ( callargs > = firstOptionalArg - 1 & & callargs < = args ) ;
2015-01-27 17:55:18 +01:00
}
2015-03-11 20:52:54 +01:00
2015-11-21 20:24:30 +01:00
const Library : : WarnInfo * Library : : getWarnInfo ( const Token * ftok ) const
{
if ( isNotLibraryFunction ( ftok ) )
return nullptr ;
2022-10-02 07:12:40 +02:00
const std : : map < std : : string , WarnInfo > : : const_iterator i = functionwarn . find ( getFunctionName ( ftok ) ) ;
2015-11-21 20:24:30 +01:00
if ( i = = functionwarn . cend ( ) )
return nullptr ;
return & i - > second ;
}
2020-06-12 16:06:43 +02:00
bool Library : : isCompliantValidationExpression ( const char * p )
{
2022-05-14 16:05:18 +02:00
if ( ! p | | ! * p )
2020-06-12 16:06:43 +02:00
return false ;
bool error = false ;
bool range = false ;
bool has_dot = false ;
bool has_E = false ;
error = * p = = ' . ' ;
for ( ; * p ; p + + ) {
2022-05-14 16:05:18 +02:00
if ( std : : isdigit ( * p ) ) {
2020-06-12 16:06:43 +02:00
error | = ( * ( p + 1 ) = = ' - ' ) ;
2022-05-14 16:05:18 +02:00
}
2020-06-12 16:06:43 +02:00
else if ( * p = = ' : ' ) {
error | = range | ( * ( p + 1 ) = = ' . ' ) ;
range = true ;
has_dot = false ;
has_E = false ;
2022-05-14 16:05:18 +02:00
}
else if ( ( * p = = ' - ' ) | | ( * p = = ' + ' ) ) {
2020-06-12 16:06:43 +02:00
error | = ( ! std : : isdigit ( * ( p + 1 ) ) ) ;
2022-05-14 16:05:18 +02:00
}
2020-06-12 16:06:43 +02:00
else if ( * p = = ' , ' ) {
range = false ;
error | = * ( p + 1 ) = = ' . ' ;
has_dot = false ;
has_E = false ;
2020-06-12 16:08:40 +02:00
} else if ( * p = = ' . ' ) {
2020-06-12 16:06:43 +02:00
error | = has_dot | ( ! std : : isdigit ( * ( p + 1 ) ) ) ;
has_dot = true ;
2020-06-12 16:08:40 +02:00
} else if ( * p = = ' E ' | | * p = = ' e ' ) {
2020-06-12 16:06:43 +02:00
error | = has_E ;
has_E = true ;
2022-05-14 16:05:18 +02:00
} else if ( * p = = ' ! ' ) {
error | = ! ( ( * ( p + 1 ) = = ' - ' ) | | ( * ( p + 1 ) = = ' + ' ) | | ( std : : isdigit ( * ( p + 1 ) ) ) ) ;
2020-06-12 16:08:40 +02:00
} else
2020-06-12 16:06:43 +02:00
return false ;
}
return ! error ;
}
2016-08-19 17:36:27 +02:00
bool Library : : formatstr_function ( const Token * ftok ) const
{
2016-12-06 12:31:16 +01:00
if ( isNotLibraryFunction ( ftok ) )
return false ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( getFunctionName ( ftok ) ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return it - > second . formatstr ;
return false ;
2016-08-19 17:36:27 +02:00
}
int Library : : formatstr_argno ( const Token * ftok ) const
{
2016-12-06 12:31:16 +01:00
const std : : map < int , Library : : ArgumentChecks > & argumentChecksFunc = functions . at ( getFunctionName ( ftok ) ) . argumentChecks ;
2022-12-30 15:13:47 +01:00
auto it = std : : find_if ( argumentChecksFunc . cbegin ( ) , argumentChecksFunc . cend ( ) , [ ] ( const std : : pair < const int , Library : : ArgumentChecks > & a ) {
2022-10-16 13:46:26 +02:00
return a . second . formatstr ;
} ) ;
2022-12-30 15:13:47 +01:00
return it = = argumentChecksFunc . cend ( ) ? - 1 : it - > first - 1 ;
2016-08-19 17:36:27 +02:00
}
bool Library : : formatstr_scan ( const Token * ftok ) const
{
2016-12-06 12:31:16 +01:00
return functions . at ( getFunctionName ( ftok ) ) . formatstr_scan ;
2016-08-19 17:36:27 +02:00
}
bool Library : : formatstr_secure ( const Token * ftok ) const
{
2016-12-06 12:31:16 +01:00
return functions . at ( getFunctionName ( ftok ) ) . formatstr_secure ;
2016-08-19 17:36:27 +02:00
}
2021-06-12 21:16:52 +02:00
const Library : : NonOverlappingData * Library : : getNonOverlappingData ( const Token * ftok ) const
{
if ( isNotLibraryFunction ( ftok ) )
return nullptr ;
const std : : unordered_map < std : : string , NonOverlappingData > : : const_iterator it = mNonOverlappingData . find ( getFunctionName ( ftok ) ) ;
return ( it ! = mNonOverlappingData . cend ( ) ) ? & it - > second : nullptr ;
}
2020-11-05 13:35:52 +01:00
Library : : UseRetValType Library : : getUseRetValType ( const Token * ftok ) const
2015-08-15 12:19:14 +02:00
{
2023-06-07 17:49:45 +02:00
if ( isNotLibraryFunction ( ftok ) ) {
if ( Token : : simpleMatch ( ftok - > astParent ( ) , " . " ) ) {
using Yield = Library : : Container : : Yield ;
const Yield yield = astContainerYield ( ftok - > astParent ( ) - > astOperand1 ( ) ) ;
if ( yield = = Yield : : START_ITERATOR | | yield = = Yield : : END_ITERATOR | | yield = = Yield : : AT_INDEX | |
yield = = Yield : : SIZE | | yield = = Yield : : EMPTY | | yield = = Yield : : BUFFER | | yield = = Yield : : BUFFER_NT | |
( yield = = Yield : : ITEM & & astContainerAction ( ftok - > astParent ( ) - > astOperand1 ( ) ) = = Library : : Container : : Action : : NO_ACTION ) | |
( yield = = Yield : : ITERATOR & & astContainerAction ( ftok - > astParent ( ) - > astOperand1 ( ) ) = = Library : : Container : : Action : : NO_ACTION ) )
return Library : : UseRetValType : : DEFAULT ;
}
2020-11-05 13:35:52 +01:00
return Library : : UseRetValType : : NONE ;
2023-06-07 17:49:45 +02:00
}
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( getFunctionName ( ftok ) ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return it - > second . useretval ;
2020-11-05 13:35:52 +01:00
return Library : : UseRetValType : : NONE ;
2015-08-15 12:19:14 +02:00
}
2016-12-05 17:30:06 +01:00
const std : : string & Library : : returnValue ( const Token * ftok ) const
2016-10-17 13:05:19 +02:00
{
if ( isNotLibraryFunction ( ftok ) )
2016-12-05 17:30:06 +01:00
return emptyString ;
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , std : : string > : : const_iterator it = mReturnValue . find ( getFunctionName ( ftok ) ) ;
2022-12-30 15:13:47 +01:00
return it ! = mReturnValue . cend ( ) ? it - > second : emptyString ;
2016-10-17 13:05:19 +02:00
}
2016-12-05 17:30:06 +01:00
const std : : string & Library : : returnValueType ( const Token * ftok ) const
2016-10-23 23:04:15 +02:00
{
2023-06-07 17:49:45 +02:00
if ( isNotLibraryFunction ( ftok ) ) {
if ( Token : : simpleMatch ( ftok - > astParent ( ) , " . " ) & & ftok - > astParent ( ) - > astOperand1 ( ) ) {
const Token * contTok = ftok - > astParent ( ) - > astOperand1 ( ) ;
if ( contTok - > valueType ( ) & & contTok - > valueType ( ) - > container )
return contTok - > valueType ( ) - > container - > getReturnType ( ftok - > str ( ) ) ;
}
2016-12-05 17:30:06 +01:00
return emptyString ;
2023-06-07 17:49:45 +02:00
}
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , std : : string > : : const_iterator it = mReturnValueType . find ( getFunctionName ( ftok ) ) ;
2022-12-30 15:13:47 +01:00
return it ! = mReturnValueType . cend ( ) ? it - > second : emptyString ;
2016-10-23 23:04:15 +02:00
}
2016-11-01 14:08:42 +01:00
int Library : : returnValueContainer ( const Token * ftok ) const
{
if ( isNotLibraryFunction ( ftok ) )
return - 1 ;
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , int > : : const_iterator it = mReturnValueContainer . find ( getFunctionName ( ftok ) ) ;
2022-12-30 15:13:47 +01:00
return it ! = mReturnValueContainer . cend ( ) ? it - > second : - 1 ;
2016-11-01 14:08:42 +01:00
}
2019-07-11 16:05:34 +02:00
std : : vector < MathLib : : bigint > Library : : unknownReturnValues ( const Token * ftok ) const
2019-07-10 20:00:21 +02:00
{
if ( isNotLibraryFunction ( ftok ) )
2019-07-11 16:05:34 +02:00
return std : : vector < MathLib : : bigint > ( ) ;
const std : : map < std : : string , std : : vector < MathLib : : bigint > > : : const_iterator it = mUnknownReturnValues . find ( getFunctionName ( ftok ) ) ;
2022-12-30 15:13:47 +01:00
return ( it = = mUnknownReturnValues . cend ( ) ) ? std : : vector < MathLib : : bigint > ( ) : it - > second ;
2019-07-10 20:00:21 +02:00
}
2020-05-23 17:50:24 +02:00
const Library : : Function * Library : : getFunction ( const Token * ftok ) const
{
if ( isNotLibraryFunction ( ftok ) )
return nullptr ;
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it1 = functions . find ( getFunctionName ( ftok ) ) ;
2020-05-23 17:50:24 +02:00
if ( it1 = = functions . cend ( ) )
return nullptr ;
return & it1 - > second ;
}
2019-03-09 22:14:02 +01:00
bool Library : : hasminsize ( const Token * ftok ) const
2016-12-06 12:31:16 +01:00
{
2019-03-09 22:14:02 +01:00
if ( isNotLibraryFunction ( ftok ) )
return false ;
2022-10-16 13:46:26 +02:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( getFunctionName ( ftok ) ) ;
if ( it = = functions . cend ( ) )
2016-12-06 12:31:16 +01:00
return false ;
2022-12-30 15:13:47 +01:00
return std : : any_of ( it - > second . argumentChecks . cbegin ( ) , it - > second . argumentChecks . cend ( ) , [ ] ( const std : : pair < const int , Library : : ArgumentChecks > & a ) {
2022-10-16 13:46:26 +02:00
return ! a . second . minsizes . empty ( ) ;
} ) ;
2016-12-06 12:31:16 +01:00
}
2019-11-24 01:40:31 +01:00
Library : : ArgumentChecks : : Direction Library : : getArgDirection ( const Token * ftok , int argnr ) const
{
const ArgumentChecks * arg = getarg ( ftok , argnr ) ;
if ( arg )
return arg - > direction ;
if ( formatstr_function ( ftok ) ) {
const int fs_argno = formatstr_argno ( ftok ) ;
if ( fs_argno > = 0 & & argnr > = fs_argno ) {
if ( formatstr_scan ( ftok ) )
return ArgumentChecks : : Direction : : DIR_OUT ;
else
return ArgumentChecks : : Direction : : DIR_IN ;
}
}
return ArgumentChecks : : Direction : : DIR_UNKNOWN ;
}
2016-12-06 12:31:16 +01:00
bool Library : : ignorefunction ( const std : : string & functionName ) const
{
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( functionName ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return it - > second . ignore ;
return false ;
}
bool Library : : isUse ( const std : : string & functionName ) const
{
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( functionName ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return it - > second . use ;
return false ;
}
bool Library : : isLeakIgnore ( const std : : string & functionName ) const
{
2021-08-07 20:51:18 +02:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( functionName ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return it - > second . leakignore ;
return false ;
}
bool Library : : isFunctionConst ( const std : : string & functionName , bool pure ) const
{
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( functionName ) ;
2016-12-06 12:31:16 +01:00
if ( it ! = functions . cend ( ) )
return pure ? it - > second . ispure : it - > second . isconst ;
return false ;
}
2017-09-08 18:08:32 +02:00
bool Library : : isFunctionConst ( const Token * ftok ) const
{
2021-04-18 21:42:27 +02:00
if ( ftok - > function ( ) & & ftok - > function ( ) - > isConst ( ) )
2017-09-08 18:08:32 +02:00
return true ;
2023-06-07 17:49:45 +02:00
if ( isNotLibraryFunction ( ftok ) ) {
if ( Token : : simpleMatch ( ftok - > astParent ( ) , " . " ) ) {
using Yield = Library : : Container : : Yield ;
const Yield yield = astContainerYield ( ftok - > astParent ( ) - > astOperand1 ( ) ) ;
if ( yield = = Yield : : EMPTY | | yield = = Yield : : SIZE | | yield = = Yield : : BUFFER_NT )
return true ;
}
2017-09-08 18:08:32 +02:00
return false ;
2023-06-07 17:49:45 +02:00
}
2021-01-16 13:52:09 +01:00
const std : : unordered_map < std : : string , Function > : : const_iterator it = functions . find ( getFunctionName ( ftok ) ) ;
2022-12-30 15:13:47 +01:00
return ( it ! = functions . cend ( ) & & it - > second . isconst ) ;
2017-09-08 18:08:32 +02:00
}
2020-12-28 19:59:51 +01:00
2015-03-11 20:52:54 +01:00
bool Library : : isnoreturn ( const Token * ftok ) const
{
if ( ftok - > function ( ) & & ftok - > function ( ) - > isAttributeNoreturn ( ) )
return true ;
2023-06-07 17:49:45 +02:00
if ( isNotLibraryFunction ( ftok ) ) {
if ( Token : : simpleMatch ( ftok - > astParent ( ) , " . " ) ) {
if ( astContainerAction ( ftok - > astParent ( ) - > astOperand1 ( ) ) ! = Library : : Container : : Action : : NO_ACTION | |
astContainerYield ( ftok - > astParent ( ) - > astOperand1 ( ) ) ! = Library : : Container : : Yield : : NO_YIELD )
return false ;
}
2015-03-11 20:52:54 +01:00
return false ;
2023-06-07 17:49:45 +02:00
}
2021-01-28 22:18:17 +01:00
const std : : unordered_map < std : : string , FalseTrueMaybe > : : const_iterator it = mNoReturn . find ( getFunctionName ( ftok ) ) ;
2020-12-28 19:59:51 +01:00
if ( it = = mNoReturn . end ( ) )
return false ;
if ( it - > second = = FalseTrueMaybe : : Maybe )
2022-04-11 07:30:55 +02:00
return true ;
2020-12-28 19:59:51 +01:00
return it - > second = = FalseTrueMaybe : : True ;
2015-03-11 20:52:54 +01:00
}
bool Library : : isnotnoreturn ( const Token * ftok ) const
{
if ( ftok - > function ( ) & & ftok - > function ( ) - > isAttributeNoreturn ( ) )
return false ;
if ( isNotLibraryFunction ( ftok ) )
return false ;
2021-01-28 22:18:17 +01:00
const std : : unordered_map < std : : string , FalseTrueMaybe > : : const_iterator it = mNoReturn . find ( getFunctionName ( ftok ) ) ;
2020-12-28 19:59:51 +01:00
if ( it = = mNoReturn . end ( ) )
return false ;
if ( it - > second = = FalseTrueMaybe : : Maybe )
2022-04-11 07:30:55 +02:00
return false ;
2020-12-28 19:59:51 +01:00
return it - > second = = FalseTrueMaybe : : False ;
2015-03-11 20:52:54 +01:00
}
2015-03-11 22:12:17 +01:00
bool Library : : markupFile ( const std : : string & path ) const
{
2018-06-17 16:39:10 +02:00
return mMarkupExtensions . find ( Path : : getFilenameExtensionInLowerCase ( path ) ) ! = mMarkupExtensions . end ( ) ;
2015-03-11 22:12:17 +01:00
}
bool Library : : processMarkupAfterCode ( const std : : string & path ) const
{
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , bool > : : const_iterator it = mProcessAfterCode . find ( Path : : getFilenameExtensionInLowerCase ( path ) ) ;
2022-12-30 15:13:47 +01:00
return ( it = = mProcessAfterCode . cend ( ) | | it - > second ) ;
2015-03-11 22:12:17 +01:00
}
bool Library : : reportErrors ( const std : : string & path ) const
{
2018-06-17 16:39:10 +02:00
const std : : map < std : : string , bool > : : const_iterator it = mReportErrors . find ( Path : : getFilenameExtensionInLowerCase ( path ) ) ;
2022-12-30 15:13:47 +01:00
return ( it = = mReportErrors . cend ( ) | | it - > second ) ;
2015-03-11 22:12:17 +01:00
}
bool Library : : isexecutableblock ( const std : : string & file , const std : : string & token ) const
{
2022-10-06 20:12:07 +02:00
const std : : unordered_map < std : : string , CodeBlock > : : const_iterator it = mExecutableBlocks . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
2022-12-30 15:13:47 +01:00
return ( it ! = mExecutableBlocks . cend ( ) & & it - > second . isBlock ( token ) ) ;
2015-03-11 22:12:17 +01:00
}
int Library : : blockstartoffset ( const std : : string & file ) const
{
int offset = - 1 ;
2022-10-06 20:12:07 +02:00
const std : : unordered_map < std : : string , CodeBlock > : : const_iterator map_it
2018-06-17 16:39:10 +02:00
= mExecutableBlocks . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
2015-03-11 22:12:17 +01:00
2018-06-17 16:39:10 +02:00
if ( map_it ! = mExecutableBlocks . end ( ) ) {
2015-03-11 22:12:17 +01:00
offset = map_it - > second . offset ( ) ;
}
return offset ;
}
const std : : string & Library : : blockstart ( const std : : string & file ) const
{
2022-10-06 20:12:07 +02:00
const std : : unordered_map < std : : string , CodeBlock > : : const_iterator map_it
2018-06-17 16:39:10 +02:00
= mExecutableBlocks . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
2015-03-11 22:12:17 +01:00
2018-06-17 16:39:10 +02:00
if ( map_it ! = mExecutableBlocks . end ( ) ) {
2015-03-11 22:12:17 +01:00
return map_it - > second . start ( ) ;
}
return emptyString ;
}
const std : : string & Library : : blockend ( const std : : string & file ) const
{
2022-10-06 20:12:07 +02:00
const std : : unordered_map < std : : string , CodeBlock > : : const_iterator map_it
2018-06-17 16:39:10 +02:00
= mExecutableBlocks . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
2015-03-11 22:12:17 +01:00
2018-06-17 16:39:10 +02:00
if ( map_it ! = mExecutableBlocks . end ( ) ) {
2015-03-11 22:12:17 +01:00
return map_it - > second . end ( ) ;
}
return emptyString ;
}
bool Library : : iskeyword ( const std : : string & file , const std : : string & keyword ) const
{
2021-08-07 20:51:18 +02:00
const std : : map < std : : string , std : : set < std : : string > > : : const_iterator it =
2018-06-17 16:39:10 +02:00
mKeywords . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
return ( it ! = mKeywords . end ( ) & & it - > second . count ( keyword ) ) ;
2015-03-11 22:12:17 +01:00
}
bool Library : : isimporter ( const std : : string & file , const std : : string & importer ) const
{
2021-08-07 20:51:18 +02:00
const std : : map < std : : string , std : : set < std : : string > > : : const_iterator it =
2018-06-17 16:39:10 +02:00
mImporters . find ( Path : : getFilenameExtensionInLowerCase ( file ) ) ;
return ( it ! = mImporters . end ( ) & & it - > second . count ( importer ) > 0 ) ;
2015-03-11 22:12:17 +01:00
}
2019-04-24 13:06:58 +02:00
2021-08-23 09:03:48 +02:00
const Token * Library : : getContainerFromYield ( const Token * tok , Library : : Container : : Yield yield ) const
{
if ( ! tok )
return nullptr ;
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " . %name% ( " ) ) {
const Token * containerTok = tok - > tokAt ( - 2 ) - > astOperand1 ( ) ;
if ( ! astIsContainer ( containerTok ) )
return nullptr ;
if ( containerTok - > valueType ( ) - > container & &
containerTok - > valueType ( ) - > container - > getYield ( tok - > strAt ( - 1 ) ) = = yield )
return containerTok ;
if ( yield = = Library : : Container : : Yield : : EMPTY & & Token : : simpleMatch ( tok - > tokAt ( - 1 ) , " empty ( ) " ) )
return containerTok ;
if ( yield = = Library : : Container : : Yield : : SIZE & & Token : : Match ( tok - > tokAt ( - 1 ) , " size|length ( ) " ) )
return containerTok ;
} else if ( Token : : Match ( tok - > previous ( ) , " %name% ( " ) ) {
if ( const Library : : Function * f = this - > getFunction ( tok - > previous ( ) ) ) {
if ( f - > containerYield = = yield ) {
return tok - > astOperand2 ( ) ;
}
}
}
return nullptr ;
}
2022-01-18 22:02:25 +01:00
// cppcheck-suppress unusedFunction
2021-08-23 09:03:48 +02:00
const Token * Library : : getContainerFromAction ( const Token * tok , Library : : Container : : Action action ) const
{
if ( ! tok )
return nullptr ;
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " . %name% ( " ) ) {
const Token * containerTok = tok - > tokAt ( - 2 ) - > astOperand1 ( ) ;
if ( ! astIsContainer ( containerTok ) )
return nullptr ;
if ( containerTok - > valueType ( ) - > container & &
containerTok - > valueType ( ) - > container - > getAction ( tok - > strAt ( - 1 ) ) = = action )
return containerTok ;
if ( Token : : simpleMatch ( tok - > tokAt ( - 1 ) , " empty ( ) " ) )
return containerTok ;
} else if ( Token : : Match ( tok - > previous ( ) , " %name% ( " ) ) {
if ( const Library : : Function * f = this - > getFunction ( tok - > previous ( ) ) ) {
if ( f - > containerAction = = action ) {
return tok - > astOperand2 ( ) ;
}
}
}
return nullptr ;
}
2021-07-21 20:13:38 +02:00
bool Library : : isSmartPointer ( const Token * tok ) const
{
return detectSmartPointer ( tok ) ;
}
2021-07-20 21:30:27 +02:00
2023-05-28 14:33:41 +02:00
const Library : : SmartPointer * Library : : detectSmartPointer ( const Token * tok , bool withoutStd ) const
2019-04-24 13:06:58 +02:00
{
2023-05-28 14:33:41 +02:00
std : : string typestr = withoutStd ? " std:: " : " " ;
2019-04-24 13:06:58 +02:00
while ( Token : : Match ( tok , " %name%|:: " ) ) {
typestr + = tok - > str ( ) ;
tok = tok - > next ( ) ;
}
2021-07-20 21:30:27 +02:00
auto it = smartPointers . find ( typestr ) ;
if ( it = = smartPointers . end ( ) )
return nullptr ;
return & it - > second ;
2019-04-24 13:06:58 +02:00
}
2022-06-08 15:27:56 +02:00
const Library : : Container * getLibraryContainer ( const Token * tok )
2019-08-15 21:14:27 +02:00
{
if ( ! tok )
return nullptr ;
// TODO: Support dereferencing iterators
// TODO: Support dereferencing with ->
if ( tok - > isUnaryOp ( " * " ) & & astIsPointer ( tok - > astOperand1 ( ) ) ) {
for ( const ValueFlow : : Value & v : tok - > astOperand1 ( ) - > values ( ) ) {
if ( ! v . isLocalLifetimeValue ( ) )
continue ;
if ( v . lifetimeKind ! = ValueFlow : : Value : : LifetimeKind : : Address )
continue ;
return getLibraryContainer ( v . tokvalue ) ;
}
}
if ( ! tok - > valueType ( ) )
return nullptr ;
return tok - > valueType ( ) - > container ;
}
2022-09-29 21:47:17 +02:00
Library : : TypeCheck Library : : getTypeCheck ( std : : string check , std : : string typeName ) const
2019-11-17 12:08:21 +01:00
{
2022-09-29 21:47:17 +02:00
auto it = mTypeChecks . find ( std : : pair < std : : string , std : : string > ( std : : move ( check ) , std : : move ( typeName ) ) ) ;
2019-11-17 12:08:21 +01:00
return it = = mTypeChecks . end ( ) ? TypeCheck : : def : it - > second ;
}
2022-04-06 06:35:38 +02:00
2023-05-28 14:33:41 +02:00
bool Library : : hasAnyTypeCheck ( const std : : string & typeName ) const
{
return std : : any_of ( mTypeChecks . begin ( ) , mTypeChecks . end ( ) , [ & ] ( const std : : pair < std : : pair < std : : string , std : : string > , Library : : TypeCheck > & tc ) {
return tc . first . second = = typeName ;
} ) ;
}
2022-04-06 06:35:38 +02:00
std : : shared_ptr < Token > createTokenFromExpression ( const std : : string & returnValue ,
const Settings * settings ,
std : : unordered_map < nonneg int , const Token * > * lookupVarId )
{
std : : shared_ptr < TokenList > tokenList = std : : make_shared < TokenList > ( settings ) ;
{
const std : : string code = " return " + returnValue + " ; " ;
std : : istringstream istr ( code ) ;
if ( ! tokenList - > createTokens ( istr ) )
return nullptr ;
}
// combine operators, set links, etc..
std : : stack < Token * > lpar ;
for ( Token * tok2 = tokenList - > front ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( Token : : Match ( tok2 , " [!<>=] = " ) ) {
tok2 - > str ( tok2 - > str ( ) + " = " ) ;
tok2 - > deleteNext ( ) ;
} else if ( tok2 - > str ( ) = = " ( " )
lpar . push ( tok2 ) ;
else if ( tok2 - > str ( ) = = " ) " ) {
if ( lpar . empty ( ) )
return nullptr ;
Token : : createMutualLinks ( lpar . top ( ) , tok2 ) ;
lpar . pop ( ) ;
}
}
if ( ! lpar . empty ( ) )
return nullptr ;
// set varids
for ( Token * tok2 = tokenList - > front ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) . compare ( 0 , 3 , " arg " ) ! = 0 )
continue ;
2023-04-08 22:29:09 +02:00
nonneg int const id = strToInt < nonneg int > ( tok2 - > str ( ) . c_str ( ) + 3 ) ;
2022-04-06 06:35:38 +02:00
tok2 - > varId ( id ) ;
if ( lookupVarId )
( * lookupVarId ) [ id ] = tok2 ;
}
// Evaluate expression
tokenList - > createAst ( ) ;
Token * expr = tokenList - > front ( ) - > astOperand1 ( ) ;
ValueFlow : : valueFlowConstantFoldAST ( expr , settings ) ;
return { tokenList , expr } ;
}