2011-08-22 18:54:23 +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 .
2011-08-22 18:54:23 +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/>.
*/
# include "suppressions.h"
2017-05-27 04:33:47 +02:00
2018-04-24 22:19:24 +02:00
# include "errorlogger.h"
2023-10-09 10:07:20 +02:00
# include "errortypes.h"
2011-08-22 18:54:23 +02:00
# include "path.h"
2020-01-24 07:06:09 +01:00
# include "utils.h"
2022-04-13 12:24:00 +02:00
# include "token.h"
2022-03-30 19:24:53 +02:00
# include "tokenize.h"
2022-04-13 12:24:00 +02:00
# include "tokenlist.h"
2011-08-22 18:54:23 +02:00
2012-07-24 21:21:05 +02:00
# include <algorithm>
2011-08-22 19:21:25 +02:00
# include <cctype> // std::isdigit, std::isalnum, etc
2022-01-27 19:03:20 +01:00
# include <cstring>
2020-11-04 21:01:48 +01:00
# include <functional> // std::bind, std::placeholders
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
# include <utility>
2011-08-22 18:54:23 +02:00
2023-11-26 14:04:35 +01:00
# include "xml.h"
2022-01-27 19:03:20 +01:00
2023-12-19 15:55:29 +01:00
static const char ID_UNUSEDFUNCTION [ ] = " unusedFunction " ;
static const char ID_CHECKERSREPORT [ ] = " checkersReport " ;
2023-10-16 19:43:15 +02:00
Suppressions : : ErrorMessage Suppressions : : ErrorMessage : : fromErrorMessage ( const : : ErrorMessage & msg , const std : : set < std : : string > & macroNames )
2023-08-18 11:55:23 +02:00
{
Suppressions : : ErrorMessage ret ;
ret . hash = msg . hash ;
ret . errorId = msg . id ;
if ( ! msg . callStack . empty ( ) ) {
ret . setFileName ( msg . callStack . back ( ) . getfile ( false ) ) ;
ret . lineNumber = msg . callStack . back ( ) . line ;
} else {
ret . lineNumber = Suppressions : : Suppression : : NO_LINE ;
}
ret . certainty = msg . certainty ;
ret . symbolNames = msg . symbolNames ( ) ;
2023-10-16 19:43:15 +02:00
ret . macroNames = macroNames ;
2023-08-18 11:55:23 +02:00
return ret ;
}
2018-08-17 08:20:39 +02:00
static bool isAcceptedErrorIdChar ( char c )
{
switch ( c ) {
case ' _ ' :
case ' - ' :
case ' . ' :
2023-11-20 11:54:41 +01:00
case ' * ' :
2018-08-17 19:55:21 +02:00
return true ;
2018-08-17 08:20:39 +02:00
default :
2023-11-20 11:54:41 +01:00
return c > 0 & & std : : isalnum ( c ) ;
2018-08-17 08:20:39 +02:00
}
}
2011-08-22 18:54:23 +02:00
std : : string Suppressions : : parseFile ( std : : istream & istr )
{
// Change '\r' to '\n' in the istr
std : : string filedata ;
std : : string line ;
while ( std : : getline ( istr , line ) )
filedata + = line + " \n " ;
2012-07-24 21:21:05 +02:00
std : : replace ( filedata . begin ( ) , filedata . end ( ) , ' \r ' , ' \n ' ) ;
2011-08-22 18:54:23 +02:00
// Parse filedata..
std : : istringstream istr2 ( filedata ) ;
2011-10-13 20:53:06 +02:00
while ( std : : getline ( istr2 , line ) ) {
2011-08-22 18:54:23 +02:00
// Skip empty lines
if ( line . empty ( ) )
continue ;
// Skip comments
2019-01-12 15:21:47 +01:00
if ( line . length ( ) > 1 & & line [ 0 ] = = ' # ' )
continue ;
2011-08-22 18:54:23 +02:00
if ( line . length ( ) > = 2 & & line [ 0 ] = = ' / ' & & line [ 1 ] = = ' / ' )
continue ;
const std : : string errmsg ( addSuppressionLine ( line ) ) ;
if ( ! errmsg . empty ( ) )
return errmsg ;
}
return " " ;
}
2018-04-09 06:43:48 +02:00
std : : string Suppressions : : parseXmlFile ( const char * filename )
{
tinyxml2 : : XMLDocument doc ;
2018-05-29 13:24:48 +02:00
const tinyxml2 : : XMLError error = doc . LoadFile ( filename ) ;
2018-04-09 06:43:48 +02:00
if ( error = = tinyxml2 : : XML_ERROR_FILE_NOT_FOUND )
return " File not found " ;
2018-04-10 16:32:47 +02:00
if ( error ! = tinyxml2 : : XML_SUCCESS )
return " Failed to parse XML file " ;
2018-04-09 06:43:48 +02:00
const tinyxml2 : : XMLElement * const rootnode = doc . FirstChildElement ( ) ;
for ( const tinyxml2 : : XMLElement * e = rootnode - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
2018-04-10 16:32:47 +02:00
if ( std : : strcmp ( e - > Name ( ) , " suppress " ) ! = 0 )
2020-07-21 11:27:03 +02:00
return " Invalid suppression xml file format, expected <suppress> element but got a \" " + std : : string ( e - > Name ( ) ) + ' \" ' ;
2018-04-10 16:32:47 +02:00
Suppression s ;
for ( const tinyxml2 : : XMLElement * e2 = e - > FirstChildElement ( ) ; e2 ; e2 = e2 - > NextSiblingElement ( ) ) {
const char * text = e2 - > GetText ( ) ? e2 - > GetText ( ) : " " ;
if ( std : : strcmp ( e2 - > Name ( ) , " id " ) = = 0 )
s . errorId = text ;
else if ( std : : strcmp ( e2 - > Name ( ) , " fileName " ) = = 0 )
s . fileName = text ;
else if ( std : : strcmp ( e2 - > Name ( ) , " lineNumber " ) = = 0 )
2023-04-08 22:29:09 +02:00
s . lineNumber = strToInt < int > ( text ) ;
2018-04-10 16:32:47 +02:00
else if ( std : : strcmp ( e2 - > Name ( ) , " symbolName " ) = = 0 )
s . symbolName = text ;
2020-07-21 11:27:03 +02:00
else if ( * text & & std : : strcmp ( e2 - > Name ( ) , " hash " ) = = 0 )
2023-04-08 22:29:09 +02:00
s . hash = strToInt < std : : size_t > ( text ) ;
2018-04-10 16:32:47 +02:00
else
2020-07-21 11:27:03 +02:00
return " Unknown suppression element \" " + std : : string ( e2 - > Name ( ) ) + " \" , expected id/fileName/lineNumber/symbolName/hash " ;
2018-04-09 06:43:48 +02:00
}
2018-04-10 16:32:47 +02:00
2023-05-04 18:15:18 +02:00
const std : : string err = addSuppression ( std : : move ( s ) ) ;
2018-04-10 16:32:47 +02:00
if ( ! err . empty ( ) )
return err ;
2018-04-09 06:43:48 +02:00
}
return " " ;
}
2020-02-23 19:49:53 +01:00
std : : vector < Suppressions : : Suppression > Suppressions : : parseMultiSuppressComment ( const std : : string & comment , std : : string * errorMessage )
2020-02-23 18:04:24 +01:00
{
std : : vector < Suppression > suppressions ;
2020-02-23 19:49:53 +01:00
// If this function is called we assume that comment starts with "cppcheck-suppress[".
2023-02-08 21:01:51 +01:00
const std : : string : : size_type start_position = comment . find ( ' [ ' ) ;
const std : : string : : size_type end_position = comment . find ( ' ] ' , start_position ) ;
2020-02-23 19:49:53 +01:00
if ( end_position = = std : : string : : npos ) {
2020-02-23 18:04:24 +01:00
if ( errorMessage & & errorMessage - > empty ( ) )
* errorMessage = " Bad multi suppression ' " + comment + " '. legal format is cppcheck-suppress[errorId, errorId symbolName=arr, ...] " ;
return suppressions ;
}
2020-02-23 19:49:53 +01:00
// parse all suppressions
for ( std : : string : : size_type pos = start_position ; pos < end_position ; ) {
const std : : string : : size_type pos1 = pos + 1 ;
2023-02-08 21:01:51 +01:00
pos = comment . find ( ' , ' , pos1 ) ;
2020-02-23 19:49:53 +01:00
const std : : string : : size_type pos2 = ( pos < end_position ) ? pos : end_position ;
if ( pos1 = = pos2 )
continue ;
2020-02-23 18:04:24 +01:00
Suppression s ;
2020-02-23 19:49:53 +01:00
std : : istringstream iss ( comment . substr ( pos1 , pos2 - pos1 ) ) ;
2020-02-23 18:04:24 +01:00
2020-02-23 19:49:53 +01:00
iss > > s . errorId ;
2020-02-23 18:04:47 +01:00
if ( ! iss ) {
2020-02-23 18:04:24 +01:00
if ( errorMessage & & errorMessage - > empty ( ) )
* errorMessage = " Bad multi suppression ' " + comment + " '. legal format is cppcheck-suppress[errorId, errorId symbolName=arr, ...] " ;
suppressions . clear ( ) ;
return suppressions ;
}
2023-10-13 19:57:08 +02:00
const std : : string symbolNameString = " symbolName= " ;
2023-10-13 12:45:13 +02:00
2020-02-23 18:04:47 +01:00
while ( iss ) {
2020-02-23 19:49:53 +01:00
std : : string word ;
2020-02-23 18:04:24 +01:00
iss > > word ;
if ( ! iss )
break ;
if ( word . find_first_not_of ( " +-*/%#; " ) = = std : : string : : npos )
break ;
2023-10-13 19:57:08 +02:00
if ( startsWith ( word , symbolNameString ) ) {
s . symbolName = word . substr ( symbolNameString . size ( ) ) ;
2020-02-23 18:04:47 +01:00
} else {
2020-02-23 18:04:24 +01:00
if ( errorMessage & & errorMessage - > empty ( ) )
* errorMessage = " Bad multi suppression ' " + comment + " '. legal format is cppcheck-suppress[errorId, errorId symbolName=arr, ...] " ;
suppressions . clear ( ) ;
return suppressions ;
}
}
2022-09-08 09:21:35 +02:00
suppressions . push_back ( std : : move ( s ) ) ;
2020-02-23 19:49:53 +01:00
}
2020-02-23 18:04:24 +01:00
return suppressions ;
}
2011-08-22 18:54:23 +02:00
std : : string Suppressions : : addSuppressionLine ( const std : : string & line )
{
2020-08-20 21:49:07 +02:00
std : : istringstream lineStream ;
2018-04-09 06:43:48 +02:00
Suppressions : : Suppression suppression ;
2020-08-20 21:49:07 +02:00
// Strip any end of line comments
2023-02-08 21:01:51 +01:00
std : : string : : size_type endpos = std : : min ( line . find ( ' # ' ) , line . find ( " // " ) ) ;
2020-08-20 21:49:07 +02:00
if ( endpos ! = std : : string : : npos ) {
while ( endpos > 0 & & std : : isspace ( line [ endpos - 1 ] ) ) {
endpos - - ;
}
lineStream . str ( line . substr ( 0 , endpos ) ) ;
} else {
lineStream . str ( line ) ;
}
2018-04-09 06:43:48 +02:00
if ( std : : getline ( lineStream , suppression . errorId , ' : ' ) ) {
if ( std : : getline ( lineStream , suppression . fileName ) ) {
2011-08-22 18:54:23 +02:00
// If there is not a dot after the last colon in "file" then
// the colon is a separator and the contents after the colon
// is a line number..
// Get position of last colon
2018-04-09 06:43:48 +02:00
const std : : string : : size_type pos = suppression . fileName . rfind ( ' : ' ) ;
2011-08-22 18:54:23 +02:00
// if a colon is found and there is no dot after it..
if ( pos ! = std : : string : : npos & &
2018-04-09 06:43:48 +02:00
suppression . fileName . find ( ' . ' , pos ) = = std : : string : : npos ) {
2011-08-22 18:54:23 +02:00
// Try to parse out the line number
2011-10-13 20:53:06 +02:00
try {
2018-04-09 06:43:48 +02:00
std : : istringstream istr1 ( suppression . fileName . substr ( pos + 1 ) ) ;
istr1 > > suppression . lineNumber ;
2011-10-13 20:53:06 +02:00
} catch ( . . . ) {
2018-09-18 12:58:14 +02:00
suppression . lineNumber = Suppressions : : Suppression : : NO_LINE ;
2011-08-22 18:54:23 +02:00
}
2018-09-23 16:50:51 +02:00
if ( suppression . lineNumber ! = Suppressions : : Suppression : : NO_LINE ) {
2018-04-09 06:43:48 +02:00
suppression . fileName . erase ( pos ) ;
2011-08-22 18:54:23 +02:00
}
}
}
}
2018-04-09 06:43:48 +02:00
suppression . fileName = Path : : simplifyPath ( suppression . fileName ) ;
2023-05-04 18:15:18 +02:00
return addSuppression ( std : : move ( suppression ) ) ;
2018-04-09 06:43:48 +02:00
}
2023-05-04 18:15:18 +02:00
std : : string Suppressions : : addSuppression ( Suppressions : : Suppression suppression )
2018-04-09 06:43:48 +02:00
{
2020-11-04 21:01:48 +01:00
// Check if suppression is already in list
2020-11-06 19:50:05 +01:00
auto foundSuppression = std : : find_if ( mSuppressions . begin ( ) , mSuppressions . end ( ) ,
std : : bind ( & Suppression : : isSameParameters , & suppression , std : : placeholders : : _1 ) ) ;
2020-11-04 21:01:48 +01:00
if ( foundSuppression ! = mSuppressions . end ( ) ) {
// Update matched state of existing global suppression
if ( ! suppression . isLocal ( ) & & suppression . matched )
foundSuppression - > matched = suppression . matched ;
return " " ;
}
2018-04-09 06:43:48 +02:00
// Check that errorId is valid..
2020-07-21 11:27:03 +02:00
if ( suppression . errorId . empty ( ) & & suppression . hash = = 0 )
2018-04-09 06:43:48 +02:00
return " Failed to add suppression. No id. " ;
2020-07-15 13:03:07 +02:00
2023-11-20 11:54:41 +01:00
for ( std : : string : : size_type pos = 0 ; pos < suppression . errorId . length ( ) ; + + pos ) {
if ( ! isAcceptedErrorIdChar ( suppression . errorId [ pos ] ) ) {
return " Failed to add suppression. Invalid id \" " + suppression . errorId + " \" " ;
}
if ( pos = = 0 & & std : : isdigit ( suppression . errorId [ pos ] ) ) {
return " Failed to add suppression. Invalid id \" " + suppression . errorId + " \" " ;
2018-04-09 06:43:48 +02:00
}
}
if ( ! isValidGlobPattern ( suppression . errorId ) )
return " Failed to add suppression. Invalid glob pattern ' " + suppression . errorId + " '. " ;
if ( ! isValidGlobPattern ( suppression . fileName ) )
return " Failed to add suppression. Invalid glob pattern ' " + suppression . fileName + " '. " ;
2023-05-04 18:15:18 +02:00
mSuppressions . push_back ( std : : move ( suppression ) ) ;
2011-08-22 18:54:23 +02:00
return " " ;
}
2023-05-04 18:15:18 +02:00
std : : string Suppressions : : addSuppressions ( std : : list < Suppression > suppressions )
2020-11-04 21:01:48 +01:00
{
2023-05-04 18:15:18 +02:00
for ( auto & newSuppression : suppressions ) {
auto errmsg = addSuppression ( std : : move ( newSuppression ) ) ;
2022-04-09 19:02:37 +02:00
if ( ! errmsg . empty ( ) )
2020-11-04 21:01:48 +01:00
return errmsg ;
}
return " " ;
}
2022-12-09 19:34:51 +01:00
void Suppressions : : ErrorMessage : : setFileName ( std : : string s )
2018-04-09 06:43:48 +02:00
{
2022-12-09 19:34:51 +01:00
mFileName = Path : : simplifyPath ( std : : move ( s ) ) ;
2018-04-09 06:43:48 +02:00
}
2018-04-11 08:18:00 +02:00
bool Suppressions : : Suppression : : parseComment ( std : : string comment , std : : string * errorMessage )
{
if ( comment . size ( ) < 2 )
return false ;
2018-06-17 16:39:28 +02:00
if ( comment . find ( ' ; ' ) ! = std : : string : : npos )
comment . erase ( comment . find ( ' ; ' ) ) ;
2018-04-11 08:18:00 +02:00
if ( comment . find ( " // " , 2 ) ! = std : : string : : npos )
comment . erase ( comment . find ( " // " , 2 ) ) ;
if ( comment . compare ( comment . size ( ) - 2 , 2 , " */ " ) = = 0 )
comment . erase ( comment . size ( ) - 2 , 2 ) ;
2023-10-13 19:57:08 +02:00
const std : : set < std : : string > cppchecksuppress {
" cppcheck-suppress " ,
" cppcheck-suppress-begin " ,
" cppcheck-suppress-end " ,
2023-10-16 19:43:15 +02:00
" cppcheck-suppress-file " ,
" cppcheck-suppress-macro "
2023-10-13 19:57:08 +02:00
} ;
2023-10-13 12:45:13 +02:00
2018-04-11 08:18:00 +02:00
std : : istringstream iss ( comment . substr ( 2 ) ) ;
std : : string word ;
iss > > word ;
2023-10-13 19:57:08 +02:00
if ( ! cppchecksuppress . count ( word ) )
2018-04-11 08:18:00 +02:00
return false ;
2023-10-13 12:45:13 +02:00
2018-04-11 08:18:00 +02:00
iss > > errorId ;
if ( ! iss )
return false ;
2023-10-13 12:45:13 +02:00
2023-10-13 19:57:08 +02:00
const std : : string symbolNameString = " symbolName= " ;
2023-10-13 12:45:13 +02:00
2018-04-11 08:18:00 +02:00
while ( iss ) {
iss > > word ;
if ( ! iss )
break ;
2018-06-09 22:50:51 +02:00
if ( word . find_first_not_of ( " +-*/%#; " ) = = std : : string : : npos )
break ;
2023-10-13 19:57:08 +02:00
if ( startsWith ( word , symbolNameString ) )
symbolName = word . substr ( symbolNameString . size ( ) ) ;
2018-04-11 08:18:00 +02:00
else if ( errorMessage & & errorMessage - > empty ( ) )
* errorMessage = " Bad suppression attribute ' " + word + " '. You can write comments in the comment after a ; or //. Valid suppression attributes; symbolName=sym " ;
}
return true ;
}
2018-04-09 06:43:48 +02:00
bool Suppressions : : Suppression : : isSuppressed ( const Suppressions : : ErrorMessage & errmsg ) const
{
2020-07-21 11:27:03 +02:00
if ( hash > 0 & & hash ! = errmsg . hash )
2020-07-15 13:03:07 +02:00
return false ;
2018-04-09 06:43:48 +02:00
if ( ! errorId . empty ( ) & & ! matchglob ( errorId , errmsg . errorId ) )
return false ;
2023-10-16 19:43:15 +02:00
if ( type = = Suppressions : : Type : : macro ) {
if ( errmsg . macroNames . count ( macroName ) = = 0 )
return false ;
} else {
if ( ! fileName . empty ( ) & & ! matchglob ( fileName , errmsg . getFileName ( ) ) )
return false ;
if ( ( Suppressions : : Type : : unique = = type ) & & ( lineNumber ! = NO_LINE ) & & ( lineNumber ! = errmsg . lineNumber ) ) {
if ( ! thisAndNextLine | | lineNumber + 1 ! = errmsg . lineNumber )
return false ;
}
if ( ( Suppressions : : Type : : block = = type ) & & ( ( errmsg . lineNumber < lineBegin ) | | ( errmsg . lineNumber > lineEnd ) ) )
2020-10-02 18:56:26 +02:00
return false ;
}
2018-04-09 06:43:48 +02:00
if ( ! symbolName . empty ( ) ) {
for ( std : : string : : size_type pos = 0 ; pos < errmsg . symbolNames . size ( ) ; ) {
const std : : string : : size_type pos2 = errmsg . symbolNames . find ( ' \n ' , pos ) ;
std : : string symname ;
if ( pos2 = = std : : string : : npos ) {
symname = errmsg . symbolNames . substr ( pos ) ;
pos = pos2 ;
} else {
symname = errmsg . symbolNames . substr ( pos , pos2 - pos ) ;
pos = pos2 + 1 ;
}
if ( matchglob ( symbolName , symname ) )
return true ;
}
return false ;
}
return true ;
}
bool Suppressions : : Suppression : : isMatch ( const Suppressions : : ErrorMessage & errmsg )
{
if ( ! isSuppressed ( errmsg ) )
return false ;
matched = true ;
2022-03-30 19:24:53 +02:00
checked = true ;
2018-04-09 06:43:48 +02:00
return true ;
}
std : : string Suppressions : : Suppression : : getText ( ) const
{
std : : string ret ;
if ( ! errorId . empty ( ) )
ret = errorId ;
if ( ! fileName . empty ( ) )
ret + = " fileName= " + fileName ;
2018-09-23 16:50:51 +02:00
if ( lineNumber ! = NO_LINE )
2023-08-17 16:46:32 +02:00
ret + = " lineNumber= " + std : : to_string ( lineNumber ) ;
2018-04-09 06:43:48 +02:00
if ( ! symbolName . empty ( ) )
ret + = " symbolName= " + symbolName ;
2020-07-21 11:27:03 +02:00
if ( hash > 0 )
2023-08-17 16:46:32 +02:00
ret + = " hash= " + std : : to_string ( hash ) ;
2023-09-08 19:30:25 +02:00
if ( startsWith ( ret , " " ) )
2018-04-09 06:43:48 +02:00
return ret . substr ( 1 ) ;
return ret ;
}
2023-05-04 18:15:18 +02:00
bool Suppressions : : isSuppressed ( const Suppressions : : ErrorMessage & errmsg , bool global )
2018-04-09 06:43:48 +02:00
{
const bool unmatchedSuppression ( errmsg . errorId = = " unmatchedSuppression " ) ;
2023-10-13 19:57:08 +02:00
bool returnValue = false ;
2018-07-15 14:51:33 +02:00
for ( Suppression & s : mSuppressions ) {
2023-05-04 18:15:18 +02:00
if ( ! global & & ! s . isLocal ( ) )
continue ;
2018-04-09 06:43:48 +02:00
if ( unmatchedSuppression & & s . errorId ! = errmsg . errorId )
continue ;
if ( s . isMatch ( errmsg ) )
2023-10-13 19:57:08 +02:00
returnValue = true ;
2018-04-09 06:43:48 +02:00
}
2023-10-13 19:57:08 +02:00
return returnValue ;
2018-04-09 06:43:48 +02:00
}
2023-12-18 18:26:23 +01:00
bool Suppressions : : isSuppressedExplicitly ( const Suppressions : : ErrorMessage & errmsg , bool global )
{
for ( Suppression & s : mSuppressions ) {
if ( ! global & & ! s . isLocal ( ) )
continue ;
if ( s . errorId ! = errmsg . errorId ) // Error id must match exactly
continue ;
if ( s . isMatch ( errmsg ) )
return true ;
}
return false ;
}
2023-10-16 19:43:15 +02:00
bool Suppressions : : isSuppressed ( const : : ErrorMessage & errmsg , const std : : set < std : : string > & macroNames )
2023-03-03 18:37:09 +01:00
{
if ( mSuppressions . empty ( ) )
return false ;
2023-10-16 19:43:15 +02:00
return isSuppressed ( Suppressions : : ErrorMessage : : fromErrorMessage ( errmsg , macroNames ) ) ;
2023-03-03 18:37:09 +01:00
}
2019-06-29 07:53:32 +02:00
void Suppressions : : dump ( std : : ostream & out ) const
2018-04-24 22:19:24 +02:00
{
out < < " <suppressions> " < < std : : endl ;
2018-06-17 08:16:37 +02:00
for ( const Suppression & suppression : mSuppressions ) {
2018-04-24 22:19:24 +02:00
out < < " <suppression " ;
out < < " errorId= \" " < < ErrorLogger : : toxml ( suppression . errorId ) < < ' " ' ;
2018-04-24 22:42:25 +02:00
if ( ! suppression . fileName . empty ( ) )
2018-04-24 22:19:24 +02:00
out < < " fileName= \" " < < ErrorLogger : : toxml ( suppression . fileName ) < < ' " ' ;
2018-09-23 16:50:51 +02:00
if ( suppression . lineNumber ! = Suppression : : NO_LINE )
2018-04-24 22:19:24 +02:00
out < < " lineNumber= \" " < < suppression . lineNumber < < ' " ' ;
if ( ! suppression . symbolName . empty ( ) )
out < < " symbolName= \" " < < ErrorLogger : : toxml ( suppression . symbolName ) < < ' \" ' ;
2020-07-21 11:27:03 +02:00
if ( suppression . hash > 0 )
out < < " hash= \" " < < suppression . hash < < ' \" ' ;
2018-04-24 22:19:24 +02:00
out < < " /> " < < std : : endl ;
}
out < < " </suppressions> " < < std : : endl ;
}
2018-04-09 06:43:48 +02:00
std : : list < Suppressions : : Suppression > Suppressions : : getUnmatchedLocalSuppressions ( const std : : string & file , const bool unusedFunctionChecking ) const
{
2020-07-29 12:13:21 +02:00
std : : string tmpFile = Path : : simplifyPath ( file ) ;
2018-04-09 06:43:48 +02:00
std : : list < Suppression > result ;
2018-07-15 14:51:33 +02:00
for ( const Suppression & s : mSuppressions ) {
2022-03-30 19:24:53 +02:00
if ( s . matched | | ( ( s . lineNumber ! = Suppression : : NO_LINE ) & & ! s . checked ) )
2018-04-09 06:43:48 +02:00
continue ;
2023-10-16 19:43:15 +02:00
if ( s . type = = Suppressions : : Type : : macro )
continue ;
2020-07-21 11:27:03 +02:00
if ( s . hash > 0 )
2020-07-15 13:03:07 +02:00
continue ;
2023-12-19 15:55:29 +01:00
if ( s . errorId = = ID_CHECKERSREPORT )
continue ;
if ( ! unusedFunctionChecking & & s . errorId = = ID_UNUSEDFUNCTION )
2018-04-09 06:43:48 +02:00
continue ;
2020-07-29 12:13:21 +02:00
if ( tmpFile . empty ( ) | | ! s . isLocal ( ) | | s . fileName ! = tmpFile )
2018-04-09 06:43:48 +02:00
continue ;
result . push_back ( s ) ;
}
return result ;
}
std : : list < Suppressions : : Suppression > Suppressions : : getUnmatchedGlobalSuppressions ( const bool unusedFunctionChecking ) const
{
std : : list < Suppression > result ;
2018-07-15 14:51:33 +02:00
for ( const Suppression & s : mSuppressions ) {
2022-03-30 19:24:53 +02:00
if ( s . matched | | ( ( s . lineNumber ! = Suppression : : NO_LINE ) & & ! s . checked ) )
2018-04-09 06:43:48 +02:00
continue ;
2020-07-21 11:27:03 +02:00
if ( s . hash > 0 )
2020-07-15 13:03:07 +02:00
continue ;
2023-12-19 15:55:29 +01:00
if ( ! unusedFunctionChecking & & s . errorId = = ID_UNUSEDFUNCTION )
continue ;
if ( s . errorId = = ID_CHECKERSREPORT )
2018-04-09 06:43:48 +02:00
continue ;
2018-05-11 09:01:08 +02:00
if ( s . isLocal ( ) )
2018-04-09 06:43:48 +02:00
continue ;
result . push_back ( s ) ;
}
return result ;
}
2020-11-04 21:01:48 +01:00
2021-08-21 22:00:45 +02:00
const std : : list < Suppressions : : Suppression > & Suppressions : : getSuppressions ( ) const
2020-11-04 21:01:48 +01:00
{
return mSuppressions ;
}
2022-03-30 19:24:53 +02:00
void Suppressions : : markUnmatchedInlineSuppressionsAsChecked ( const Tokenizer & tokenizer ) {
int currLineNr = - 1 ;
int currFileIdx = - 1 ;
for ( const Token * tok = tokenizer . tokens ( ) ; tok ; tok = tok - > next ( ) ) {
if ( currFileIdx ! = tok - > fileIndex ( ) | | currLineNr ! = tok - > linenr ( ) ) {
currLineNr = tok - > linenr ( ) ;
currFileIdx = tok - > fileIndex ( ) ;
for ( auto & suppression : mSuppressions ) {
2023-10-13 12:45:13 +02:00
if ( suppression . type = = Suppressions : : Type : : unique ) {
if ( ! suppression . checked & & ( suppression . lineNumber = = currLineNr ) & & ( suppression . fileName = = tokenizer . list . file ( tok ) ) ) {
suppression . checked = true ;
}
} else if ( suppression . type = = Suppressions : : Type : : block ) {
if ( ( ! suppression . checked & & ( suppression . lineBegin < = currLineNr ) & & ( suppression . lineEnd > = currLineNr ) & & ( suppression . fileName = = tokenizer . list . file ( tok ) ) ) ) {
suppression . checked = true ;
}
} else if ( ! suppression . checked & & suppression . fileName = = tokenizer . list . file ( tok ) ) {
2022-03-30 19:24:53 +02:00
suppression . checked = true ;
}
}
}
}
}
2023-08-18 11:55:23 +02:00
bool Suppressions : : reportUnmatchedSuppressions ( const std : : list < Suppressions : : Suppression > & unmatched , ErrorLogger & errorLogger )
{
bool err = false ;
// Report unmatched suppressions
for ( const Suppressions : : Suppression & s : unmatched ) {
// don't report "unmatchedSuppression" as unmatched
if ( s . errorId = = " unmatchedSuppression " )
continue ;
// check if this unmatched suppression is suppressed
bool suppressed = false ;
for ( const Suppressions : : Suppression & s2 : unmatched ) {
if ( s2 . errorId = = " unmatchedSuppression " ) {
if ( ( s2 . fileName . empty ( ) | | s2 . fileName = = " * " | | s2 . fileName = = s . fileName ) & &
( s2 . lineNumber = = Suppressions : : Suppression : : NO_LINE | | s2 . lineNumber = = s . lineNumber ) ) {
suppressed = true ;
break ;
}
}
}
if ( suppressed )
continue ;
std : : list < : : ErrorMessage : : FileLocation > callStack ;
if ( ! s . fileName . empty ( ) )
callStack . emplace_back ( s . fileName , s . lineNumber , 0 ) ;
errorLogger . reportErr ( : : ErrorMessage ( callStack , emptyString , Severity : : information , " Unmatched suppression: " + s . errorId , " unmatchedSuppression " , Certainty : : normal ) ) ;
err = true ;
}
return err ;
}