2009-01-09 20:01:25 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2009-01-09 20:01:25 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-01-09 20:01:25 +01:00
*/
2009-02-01 16:47:36 +01:00
# include "errorlogger.h"
2017-05-27 04:33:47 +02:00
2021-07-08 21:21:35 +02:00
# include "color.h"
2010-12-22 10:29:23 +01:00
# include "cppcheck.h"
2017-05-27 04:33:47 +02:00
# include "mathlib.h"
# include "path.h"
2013-05-07 18:18:15 +02:00
# include "token.h"
2017-05-27 04:33:47 +02:00
# include "tokenlist.h"
2023-04-30 07:33:19 +02:00
# include "utils.h"
2009-01-03 14:51:55 +01:00
2022-01-27 19:03:20 +01:00
# include <algorithm>
2017-05-27 04:33:47 +02:00
# include <array>
2011-12-30 00:22:16 +01:00
# include <cassert>
2017-05-27 04:33:47 +02:00
# include <cctype>
# include <cstdlib>
# include <cstring>
2014-04-13 09:50:57 +02:00
# include <iomanip>
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
2022-01-27 19:03:20 +01:00
# include <string>
2023-04-30 07:33:19 +02:00
# include <unordered_map>
2022-07-28 22:51:45 +02:00
# include <utility>
2022-01-27 19:03:20 +01:00
# include <tinyxml2.h>
2009-02-01 16:47:36 +01:00
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( )
2022-08-13 08:27:52 +02:00
: severity ( Severity : : none ) , cwe ( 0U ) , certainty ( Certainty : : normal ) , hash ( 0 )
2021-08-07 20:51:18 +02:00
{ }
2010-07-27 09:32:20 +02:00
2023-01-08 19:31:54 +01:00
ErrorMessage : : ErrorMessage ( std : : list < FileLocation > callStack , std : : string file1 , Severity : : SeverityType severity , const std : : string & msg , std : : string id , Certainty certainty ) :
2022-07-28 22:51:45 +02:00
callStack ( std : : move ( callStack ) ) , // locations for this error message
id ( std : : move ( id ) ) , // set the message id
file0 ( std : : move ( file1 ) ) ,
2020-05-03 20:46:29 +02:00
severity ( severity ) , // severity for this error message
2019-08-18 12:19:05 +02:00
cwe ( 0U ) ,
2021-02-24 22:00:06 +01:00
certainty ( certainty ) ,
2020-07-21 11:27:03 +02:00
hash ( 0 )
2009-02-10 22:51:52 +01:00
{
2010-12-30 22:07:27 +01:00
// set the summary and verbose messages
2010-11-11 19:54:43 +01:00
setmsg ( msg ) ;
2009-02-10 22:51:52 +01:00
}
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
2023-01-08 19:31:54 +01:00
ErrorMessage : : ErrorMessage ( std : : list < FileLocation > callStack , std : : string file1 , Severity : : SeverityType severity , const std : : string & msg , std : : string id , const CWE & cwe , Certainty certainty ) :
2022-07-28 22:51:45 +02:00
callStack ( std : : move ( callStack ) ) , // locations for this error message
id ( std : : move ( id ) ) , // set the message id
file0 ( std : : move ( file1 ) ) ,
2020-05-03 20:46:29 +02:00
severity ( severity ) , // severity for this error message
2019-08-18 12:19:05 +02:00
cwe ( cwe . id ) ,
2021-02-24 22:00:06 +01:00
certainty ( certainty ) ,
2020-07-21 11:27:03 +02:00
hash ( 0 )
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
{
// set the summary and verbose messages
setmsg ( msg ) ;
}
2023-01-08 19:31:54 +01:00
ErrorMessage : : ErrorMessage ( const std : : list < const Token * > & callstack , const TokenList * list , Severity : : SeverityType severity , std : : string id , const std : : string & msg , Certainty certainty )
2022-08-13 08:27:52 +02:00
: id ( std : : move ( id ) ) , severity ( severity ) , cwe ( 0U ) , certainty ( certainty ) , hash ( 0 )
2012-05-06 10:17:15 +02:00
{
// Format callstack
2022-12-20 20:32:16 +01:00
for ( std : : list < const Token * > : : const_iterator it = callstack . cbegin ( ) ; it ! = callstack . cend ( ) ; + + it ) {
2012-05-06 10:17:15 +02:00
// --errorlist can provide null values here
if ( ! ( * it ) )
continue ;
2019-08-18 12:19:05 +02:00
callStack . emplace_back ( * it , list ) ;
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
}
if ( list & & ! list - > getFiles ( ) . empty ( ) )
file0 = list - > getFiles ( ) [ 0 ] ;
setmsg ( msg ) ;
}
2023-01-08 19:31:54 +01:00
ErrorMessage : : ErrorMessage ( const std : : list < const Token * > & callstack , const TokenList * list , Severity : : SeverityType severity , std : : string id , const std : : string & msg , const CWE & cwe , Certainty certainty )
2022-08-13 08:27:52 +02:00
: id ( std : : move ( id ) ) , severity ( severity ) , cwe ( cwe . id ) , certainty ( certainty )
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
{
// Format callstack
2020-01-05 15:12:53 +01:00
for ( const Token * tok : callstack ) {
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
// --errorlist can provide null values here
2020-01-05 15:12:53 +01:00
if ( ! tok )
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
continue ;
2020-01-05 15:12:53 +01:00
callStack . emplace_back ( tok , list ) ;
2012-05-06 10:17:15 +02:00
}
if ( list & & ! list - > getFiles ( ) . empty ( ) )
file0 = list - > getFiles ( ) [ 0 ] ;
setmsg ( msg ) ;
2020-07-14 22:30:42 +02:00
2022-04-11 07:30:55 +02:00
hash = 0 ; // calculateWarningHash(list, hashWarning.str());
2012-05-06 10:17:15 +02:00
}
2023-01-08 19:31:54 +01:00
ErrorMessage : : ErrorMessage ( const ErrorPath & errorPath , const TokenList * tokenList , Severity : : SeverityType severity , const char id [ ] , const std : : string & msg , const CWE & cwe , Certainty certainty )
2022-08-13 08:27:52 +02:00
: id ( id ) , severity ( severity ) , cwe ( cwe . id ) , certainty ( certainty )
2017-05-16 22:38:13 +02:00
{
// Format callstack
2020-07-21 15:59:48 +02:00
for ( const ErrorPathItem & e : errorPath ) {
const Token * tok = e . first ;
2023-04-28 12:42:51 +02:00
// --errorlist can provide null values here
if ( ! tok )
continue ;
2020-09-25 19:04:22 +02:00
std : : string info = e . second ;
2023-02-08 21:01:51 +01:00
if ( info . compare ( 0 , 8 , " $symbol: " ) = = 0 & & info . find ( ' \n ' ) < info . size ( ) ) {
const std : : string : : size_type pos = info . find ( ' \n ' ) ;
2020-09-25 19:04:22 +02:00
const std : : string & symbolName = info . substr ( 8 , pos - 8 ) ;
info = replaceStr ( info . substr ( pos + 1 ) , " $symbol " , symbolName ) ;
}
2017-05-16 22:38:13 +02:00
2023-04-28 12:42:51 +02:00
callStack . emplace_back ( tok , info , tokenList ) ;
2017-05-16 22:38:13 +02:00
}
if ( tokenList & & ! tokenList - > getFiles ( ) . empty ( ) )
file0 = tokenList - > getFiles ( ) [ 0 ] ;
setmsg ( msg ) ;
2020-07-14 22:30:42 +02:00
2022-04-11 07:30:55 +02:00
hash = 0 ; // calculateWarningHash(tokenList, hashWarning.str());
2017-05-16 22:38:13 +02:00
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const tinyxml2 : : XMLElement * const errmsg )
2022-08-13 08:27:52 +02:00
: severity ( Severity : : none ) ,
2021-08-07 20:51:18 +02:00
cwe ( 0U ) ,
certainty ( Certainty : : normal )
2016-10-29 12:18:11 +02:00
{
2017-08-16 16:53:04 +02:00
const char * const unknown = " <UNKNOWN> " ;
const char * attr = errmsg - > Attribute ( " id " ) ;
2019-08-18 12:19:05 +02:00
id = attr ? attr : unknown ;
2017-08-16 16:53:04 +02:00
attr = errmsg - > Attribute ( " severity " ) ;
2019-08-18 12:19:05 +02:00
severity = attr ? Severity : : fromString ( attr ) : Severity : : none ;
2017-08-16 16:53:04 +02:00
attr = errmsg - > Attribute ( " cwe " ) ;
2023-04-08 22:29:09 +02:00
cwe . id = attr ? strToInt < unsigned short > ( attr ) : 0 ;
2017-08-16 16:53:04 +02:00
2016-10-29 12:18:11 +02:00
attr = errmsg - > Attribute ( " inconclusive " ) ;
2021-02-24 22:00:06 +01:00
certainty = ( attr & & ( std : : strcmp ( attr , " true " ) = = 0 ) ) ? Certainty : : inconclusive : Certainty : : normal ;
2017-08-16 16:53:04 +02:00
attr = errmsg - > Attribute ( " msg " ) ;
2018-06-17 07:54:50 +02:00
mShortMessage = attr ? attr : " " ;
2017-08-16 16:53:04 +02:00
attr = errmsg - > Attribute ( " verbose " ) ;
2018-06-17 07:55:47 +02:00
mVerboseMessage = attr ? attr : " " ;
2017-08-16 16:53:04 +02:00
2020-07-21 11:27:03 +02:00
attr = errmsg - > Attribute ( " hash " ) ;
2023-04-08 22:29:09 +02:00
hash = attr ? strToInt < std : : size_t > ( attr ) : 0 ;
2020-07-14 22:30:42 +02:00
2016-10-29 12:18:11 +02:00
for ( const tinyxml2 : : XMLElement * e = errmsg - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
if ( std : : strcmp ( e - > Name ( ) , " location " ) = = 0 ) {
2017-05-16 22:38:13 +02:00
const char * strfile = e - > Attribute ( " file " ) ;
const char * strinfo = e - > Attribute ( " info " ) ;
const char * strline = e - > Attribute ( " line " ) ;
2019-08-18 12:19:05 +02:00
const char * strcolumn = e - > Attribute ( " column " ) ;
2017-08-16 16:53:04 +02:00
const char * file = strfile ? strfile : unknown ;
const char * info = strinfo ? strinfo : " " ;
2023-04-08 22:29:09 +02:00
const int line = strline ? strToInt < int > ( strline ) : 0 ;
const int column = strcolumn ? strToInt < int > ( strcolumn ) : 0 ;
2021-04-22 14:28:33 +02:00
callStack . emplace_front ( file , info , line , column ) ;
2022-02-21 18:18:35 +01:00
} else if ( std : : strcmp ( e - > Name ( ) , " symbol " ) = = 0 ) {
mSymbolNames + = e - > GetText ( ) ;
2016-10-29 12:18:11 +02:00
}
}
}
2020-05-23 07:16:49 +02:00
void ErrorMessage : : setmsg ( const std : : string & msg )
2010-11-11 19:54:43 +01:00
{
2011-12-30 00:22:16 +01:00
// If a message ends to a '\n' and contains only a one '\n'
2018-06-17 07:55:47 +02:00
// it will cause the mVerboseMessage to be empty which will show
2011-12-30 00:22:16 +01:00
// as an empty message to the user if --verbose is used.
// Even this doesn't cause problems with messages that have multiple
2018-10-08 13:58:21 +02:00
// lines, none of the error messages should end into it.
2017-04-01 18:14:18 +02:00
assert ( ! endsWith ( msg , ' \n ' ) ) ;
2011-12-30 00:22:16 +01:00
2010-12-30 22:07:27 +01:00
// The summary and verbose message are separated by a newline
// If there is no newline then both the summary and verbose messages
// are the given message
2015-08-15 20:24:26 +02:00
const std : : string : : size_type pos = msg . find ( ' \n ' ) ;
2018-06-17 07:59:48 +02:00
const std : : string symbolName = mSymbolNames . empty ( ) ? std : : string ( ) : mSymbolNames . substr ( 0 , mSymbolNames . find ( ' \n ' ) ) ;
2011-10-13 20:53:06 +02:00
if ( pos = = std : : string : : npos ) {
2018-06-17 07:54:50 +02:00
mShortMessage = replaceStr ( msg , " $symbol " , symbolName ) ;
2018-06-17 07:55:47 +02:00
mVerboseMessage = replaceStr ( msg , " $symbol " , symbolName ) ;
2018-04-09 06:43:48 +02:00
} else if ( msg . compare ( 0 , 8 , " $symbol: " ) = = 0 ) {
2018-06-17 07:59:48 +02:00
mSymbolNames + = msg . substr ( 8 , pos - 7 ) ;
2018-04-09 06:43:48 +02:00
setmsg ( msg . substr ( pos + 1 ) ) ;
2011-10-13 20:53:06 +02:00
} else {
2018-06-17 07:54:50 +02:00
mShortMessage = replaceStr ( msg . substr ( 0 , pos ) , " $symbol " , symbolName ) ;
2018-06-17 07:55:47 +02:00
mVerboseMessage = replaceStr ( msg . substr ( pos + 1 ) , " $symbol " , symbolName ) ;
2010-11-11 19:54:43 +01:00
}
}
2020-05-23 07:16:49 +02:00
Suppressions : : ErrorMessage ErrorMessage : : toSuppressionsErrorMessage ( ) const
2018-04-09 06:43:48 +02:00
{
Suppressions : : ErrorMessage ret ;
2020-07-21 11:27:03 +02:00
ret . hash = hash ;
2019-08-18 12:19:05 +02:00
ret . errorId = id ;
if ( ! callStack . empty ( ) ) {
ret . setFileName ( callStack . back ( ) . getfile ( false ) ) ;
ret . lineNumber = callStack . back ( ) . line ;
2021-10-28 17:09:33 +02:00
} else {
ret . lineNumber = Suppressions : : Suppression : : NO_LINE ;
2018-04-09 06:43:48 +02:00
}
2021-02-24 22:00:06 +01:00
ret . certainty = certainty ;
2018-06-17 07:59:48 +02:00
ret . symbolNames = mSymbolNames ;
2018-04-09 06:43:48 +02:00
return ret ;
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : serialize ( ) const
2009-02-19 23:21:18 +01:00
{
2010-12-30 22:07:27 +01:00
// Serialize this message into a simple string
2009-02-19 23:21:18 +01:00
std : : ostringstream oss ;
2019-08-18 12:19:05 +02:00
oss < < id . length ( ) < < " " < < id ;
oss < < Severity : : toString ( severity ) . length ( ) < < " " < < Severity : : toString ( severity ) ;
oss < < MathLib : : toString ( cwe . id ) . length ( ) < < " " < < MathLib : : toString ( cwe . id ) ;
2020-07-21 11:27:03 +02:00
oss < < MathLib : : toString ( hash ) . length ( ) < < " " < < MathLib : : toString ( hash ) ;
2021-04-05 12:03:20 +02:00
oss < < file0 . size ( ) < < " " < < file0 ;
2021-02-24 22:00:06 +01:00
if ( certainty = = Certainty : : inconclusive ) {
2020-05-10 22:16:58 +02:00
const std : : string text ( " inconclusive " ) ;
oss < < text . length ( ) < < " " < < text ;
2011-04-16 13:42:48 +02:00
}
2015-01-17 15:58:36 +01:00
2018-06-17 07:54:50 +02:00
const std : : string saneShortMessage = fixInvalidChars ( mShortMessage ) ;
2018-06-17 07:55:47 +02:00
const std : : string saneVerboseMessage = fixInvalidChars ( mVerboseMessage ) ;
2015-01-17 15:58:36 +01:00
oss < < saneShortMessage . length ( ) < < " " < < saneShortMessage ;
oss < < saneVerboseMessage . length ( ) < < " " < < saneVerboseMessage ;
2019-08-18 12:19:05 +02:00
oss < < callStack . size ( ) < < " " ;
2009-02-19 23:21:18 +01:00
2022-12-20 20:32:16 +01:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator loc = callStack . cbegin ( ) ; loc ! = callStack . cend ( ) ; + + loc ) {
2009-02-19 23:21:18 +01:00
std : : ostringstream smallStream ;
2019-08-18 16:33:32 +02:00
smallStream < < ( * loc ) . line < < ' \t ' < < ( * loc ) . column < < ' \t ' < < ( * loc ) . getfile ( false ) < < ' \t ' < < loc - > getOrigFile ( false ) < < ' \t ' < < loc - > getinfo ( ) ;
2009-02-19 23:21:18 +01:00
oss < < smallStream . str ( ) . length ( ) < < " " < < smallStream . str ( ) ;
}
2010-12-24 11:13:57 +01:00
2009-02-19 23:21:18 +01:00
return oss . str ( ) ;
}
2022-12-07 18:00:45 +01:00
void ErrorMessage : : deserialize ( const std : : string & data )
2009-02-19 23:21:18 +01:00
{
2022-12-03 15:44:33 +01:00
// TODO: clear all fields
2021-02-24 22:00:06 +01:00
certainty = Certainty : : normal ;
2019-08-18 12:19:05 +02:00
callStack . clear ( ) ;
2022-12-03 15:44:33 +01:00
2009-02-19 23:21:18 +01:00
std : : istringstream iss ( data ) ;
2021-04-05 12:03:20 +02:00
std : : array < std : : string , 7 > results ;
2015-11-29 10:49:10 +01:00
std : : size_t elem = 0 ;
2021-04-05 12:03:20 +02:00
while ( iss . good ( ) & & elem < 7 ) {
2009-02-19 23:21:18 +01:00
unsigned int len = 0 ;
2010-04-02 07:30:58 +02:00
if ( ! ( iss > > len ) )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid length " ) ;
2009-02-19 23:21:18 +01:00
2022-12-03 15:44:33 +01:00
if ( iss . get ( ) ! = ' ' )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid separator " ) ;
2022-12-03 15:44:33 +01:00
if ( ! iss . good ( ) )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - premature end of data " ) ;
2022-12-03 15:44:33 +01:00
2009-02-19 23:21:18 +01:00
std : : string temp ;
2022-12-09 19:34:51 +01:00
if ( len > 0 ) {
temp . resize ( len ) ;
iss . read ( & temp [ 0 ] , len ) ;
2009-02-19 23:21:18 +01:00
2022-12-09 19:34:51 +01:00
if ( ! iss . good ( ) )
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - premature end of data " ) ;
2022-12-03 15:44:33 +01:00
2022-12-09 19:34:51 +01:00
if ( temp = = " inconclusive " ) {
certainty = Certainty : : inconclusive ;
continue ;
}
2011-04-14 18:02:01 +02:00
}
2015-11-29 10:49:10 +01:00
results [ elem + + ] = temp ;
2009-02-19 23:21:18 +01:00
}
2022-12-03 15:44:33 +01:00
if ( ! iss . good ( ) )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - premature end of data " ) ;
2022-12-03 15:44:33 +01:00
2021-04-05 12:03:20 +02:00
if ( elem ! = 7 )
2022-12-03 15:44:33 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - insufficient elements " ) ;
2015-01-17 15:56:09 +01:00
2022-12-09 19:34:51 +01:00
id = std : : move ( results [ 0 ] ) ;
2019-08-18 12:19:05 +02:00
severity = Severity : : fromString ( results [ 1 ] ) ;
2023-04-08 22:29:09 +02:00
cwe . id = 0 ;
2022-12-09 19:34:51 +01:00
if ( ! results [ 2 ] . empty ( ) ) {
2023-04-08 22:29:09 +02:00
std : : string err ;
if ( ! strToInt ( results [ 2 ] , cwe . id , & err ) )
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid CWE ID - " + err ) ;
2022-12-09 19:34:51 +01:00
}
hash = 0 ;
if ( ! results [ 3 ] . empty ( ) ) {
2023-04-08 22:29:09 +02:00
std : : string err ;
if ( ! strToInt ( results [ 3 ] , hash , & err ) )
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid hash - " + err ) ;
2022-12-09 19:34:51 +01:00
}
file0 = std : : move ( results [ 4 ] ) ;
mShortMessage = std : : move ( results [ 5 ] ) ;
mVerboseMessage = std : : move ( results [ 6 ] ) ;
2009-02-19 23:21:18 +01:00
unsigned int stackSize = 0 ;
2010-04-02 07:30:58 +02:00
if ( ! ( iss > > stackSize ) )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid stack size " ) ;
2009-02-19 23:21:18 +01:00
2022-12-03 15:44:33 +01:00
if ( iss . get ( ) ! = ' ' )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid separator " ) ;
2022-12-03 15:44:33 +01:00
if ( stackSize = = 0 )
2022-12-07 18:00:45 +01:00
return ;
2022-12-03 15:44:33 +01:00
2011-10-13 20:53:06 +02:00
while ( iss . good ( ) ) {
2009-02-19 23:21:18 +01:00
unsigned int len = 0 ;
2010-04-02 07:30:58 +02:00
if ( ! ( iss > > len ) )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid length (stack) " ) ;
2009-02-19 23:21:18 +01:00
2022-12-09 19:34:51 +01:00
if ( iss . get ( ) ! = ' ' )
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - invalid separator (stack) " ) ;
2009-02-19 23:21:18 +01:00
std : : string temp ;
2022-12-09 19:34:51 +01:00
if ( len > 0 ) {
temp . resize ( len ) ;
iss . read ( & temp [ 0 ] , len ) ;
if ( ! iss . good ( ) )
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed - premature end of data (stack) " ) ;
2009-03-08 19:50:19 +01:00
}
2009-02-19 23:21:18 +01:00
2019-08-18 16:33:32 +02:00
std : : vector < std : : string > substrings ;
2022-12-09 19:34:51 +01:00
substrings . reserve ( 5 ) ;
2019-08-18 16:33:32 +02:00
for ( std : : string : : size_type pos = 0 ; pos < temp . size ( ) & & substrings . size ( ) < 5 ; + + pos ) {
if ( substrings . size ( ) = = 4 ) {
substrings . push_back ( temp . substr ( pos ) ) ;
break ;
}
const std : : string : : size_type start = pos ;
2023-02-08 21:01:51 +01:00
pos = temp . find ( ' \t ' , pos ) ;
2019-08-18 16:33:32 +02:00
if ( pos = = std : : string : : npos ) {
substrings . push_back ( temp . substr ( start ) ) ;
break ;
}
substrings . push_back ( temp . substr ( start , pos - start ) ) ;
}
if ( substrings . size ( ) < 4 )
2022-12-07 18:00:45 +01:00
throw InternalError ( nullptr , " Internal Error: Deserializing of error message failed " ) ;
2019-08-18 16:33:32 +02:00
// (*loc).line << '\t' << (*loc).column << '\t' << (*loc).getfile(false) << '\t' << loc->getOrigFile(false) << '\t' << loc->getinfo();
2023-04-08 22:29:09 +02:00
ErrorMessage : : FileLocation loc ( substrings [ 3 ] , strToInt < int > ( substrings [ 0 ] ) , strToInt < unsigned int > ( substrings [ 1 ] ) ) ;
2022-12-09 19:34:51 +01:00
loc . setfile ( std : : move ( substrings [ 2 ] ) ) ;
2019-08-18 16:33:32 +02:00
if ( substrings . size ( ) = = 5 )
loc . setinfo ( substrings [ 4 ] ) ;
2009-02-19 23:21:18 +01:00
2022-09-08 09:21:35 +02:00
callStack . push_back ( std : : move ( loc ) ) ;
2009-02-19 23:21:18 +01:00
2019-08-18 12:19:05 +02:00
if ( callStack . size ( ) > = stackSize )
2009-02-19 23:21:18 +01:00
break ;
}
}
2022-07-07 17:35:13 +02:00
std : : string ErrorMessage : : getXMLHeader ( const std : : string & productName )
2009-06-15 20:36:39 +02:00
{
2013-08-07 16:30:55 +02:00
tinyxml2 : : XMLPrinter printer ;
2010-12-02 17:32:51 +01:00
2013-08-07 16:30:55 +02:00
// standard xml header
printer . PushDeclaration ( " xml version= \" 1.0 \" encoding= \" UTF-8 \" " ) ;
2010-12-30 22:07:27 +01:00
2013-08-07 16:30:55 +02:00
// header
2014-03-01 11:15:08 +01:00
printer . OpenElement ( " results " , false ) ;
2017-07-29 18:56:22 +02:00
printer . PushAttribute ( " version " , 2 ) ;
printer . OpenElement ( " cppcheck " , false ) ;
2022-07-07 17:35:13 +02:00
if ( ! productName . empty ( ) )
printer . PushAttribute ( " product-name " , productName . c_str ( ) ) ;
2017-07-29 18:56:22 +02:00
printer . PushAttribute ( " version " , CppCheck : : version ( ) ) ;
printer . CloseElement ( false ) ;
printer . OpenElement ( " errors " , false ) ;
2010-12-22 10:29:23 +01:00
2013-08-07 16:30:55 +02:00
return std : : string ( printer . CStr ( ) ) + ' > ' ;
2009-06-15 20:36:39 +02:00
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : getXMLFooter ( )
2009-06-15 20:36:39 +02:00
{
2017-07-29 18:56:22 +02:00
return " </errors> \n </results> " ;
2009-10-27 22:10:14 +01:00
}
2014-04-13 09:50:57 +02:00
// There is no utf-8 support around but the strings should at least be safe for to tinyxml2.
2015-06-18 19:07:51 +02:00
// See #5300 "Invalid encoding in XML output" and #6431 "Invalid XML created - Invalid encoding of string literal "
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : fixInvalidChars ( const std : : string & raw )
2014-04-13 09:50:57 +02:00
{
std : : string result ;
result . reserve ( raw . length ( ) ) ;
2022-12-20 20:32:16 +01:00
std : : string : : const_iterator from = raw . cbegin ( ) ;
while ( from ! = raw . cend ( ) ) {
2014-04-27 13:27:39 +02:00
if ( std : : isprint ( static_cast < unsigned char > ( * from ) ) ) {
2014-04-13 09:50:57 +02:00
result . push_back ( * from ) ;
} else {
std : : ostringstream es ;
// straight cast to (unsigned) doesn't work out.
2015-07-04 13:19:21 +02:00
const unsigned uFrom = ( unsigned char ) * from ;
2016-02-01 18:53:46 +01:00
es < < ' \\ ' < < std : : setbase ( 8 ) < < std : : setw ( 3 ) < < std : : setfill ( ' 0 ' ) < < uFrom ;
2014-04-13 09:50:57 +02:00
result + = es . str ( ) ;
}
+ + from ;
}
return result ;
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : toXML ( ) const
2009-02-10 22:51:52 +01:00
{
2017-08-09 20:00:26 +02:00
tinyxml2 : : XMLPrinter printer ( nullptr , false , 2 ) ;
2017-07-29 18:56:22 +02:00
printer . OpenElement ( " error " , false ) ;
2019-08-18 12:19:05 +02:00
printer . PushAttribute ( " id " , id . c_str ( ) ) ;
printer . PushAttribute ( " severity " , Severity : : toString ( severity ) . c_str ( ) ) ;
2018-06-17 07:54:50 +02:00
printer . PushAttribute ( " msg " , fixInvalidChars ( mShortMessage ) . c_str ( ) ) ;
2018-06-17 07:55:47 +02:00
printer . PushAttribute ( " verbose " , fixInvalidChars ( mVerboseMessage ) . c_str ( ) ) ;
2019-08-18 12:19:05 +02:00
if ( cwe . id )
printer . PushAttribute ( " cwe " , cwe . id ) ;
2020-07-21 11:27:03 +02:00
if ( hash )
printer . PushAttribute ( " hash " , MathLib : : toString ( hash ) . c_str ( ) ) ;
2021-02-24 22:00:06 +01:00
if ( certainty = = Certainty : : inconclusive )
2017-07-29 18:56:22 +02:00
printer . PushAttribute ( " inconclusive " , " true " ) ;
2021-04-05 12:03:20 +02:00
if ( ! file0 . empty ( ) )
printer . PushAttribute ( " file0 " , file0 . c_str ( ) ) ;
2022-12-20 20:32:16 +01:00
for ( std : : list < FileLocation > : : const_reverse_iterator it = callStack . crbegin ( ) ; it ! = callStack . crend ( ) ; + + it ) {
2017-07-29 18:56:22 +02:00
printer . OpenElement ( " location " , false ) ;
printer . PushAttribute ( " file " , ( * it ) . getfile ( ) . c_str ( ) ) ;
2018-09-25 06:14:26 +02:00
printer . PushAttribute ( " line " , std : : max ( ( * it ) . line , 0 ) ) ;
2019-08-18 12:19:05 +02:00
printer . PushAttribute ( " column " , ( * it ) . column ) ;
2017-07-29 18:56:22 +02:00
if ( ! it - > getinfo ( ) . empty ( ) )
2019-01-02 18:22:12 +01:00
printer . PushAttribute ( " info " , fixInvalidChars ( it - > getinfo ( ) ) . c_str ( ) ) ;
2014-03-01 11:15:08 +01:00
printer . CloseElement ( false ) ;
2010-12-01 21:24:17 +01:00
}
2018-06-17 07:59:48 +02:00
for ( std : : string : : size_type pos = 0 ; pos < mSymbolNames . size ( ) ; ) {
const std : : string : : size_type pos2 = mSymbolNames . find ( ' \n ' , pos ) ;
2018-04-09 06:43:48 +02:00
std : : string symbolName ;
if ( pos2 = = std : : string : : npos ) {
2018-06-17 07:59:48 +02:00
symbolName = mSymbolNames . substr ( pos ) ;
2018-04-09 06:43:48 +02:00
pos = pos2 ;
} else {
2018-06-17 07:59:48 +02:00
symbolName = mSymbolNames . substr ( pos , pos2 - pos ) ;
2018-04-09 06:43:48 +02:00
pos = pos2 + 1 ;
}
printer . OpenElement ( " symbol " , false ) ;
printer . PushText ( symbolName . c_str ( ) ) ;
printer . CloseElement ( false ) ;
}
2017-07-29 18:56:22 +02:00
printer . CloseElement ( false ) ;
return printer . CStr ( ) ;
2009-02-10 22:51:52 +01:00
}
2021-07-08 21:21:35 +02:00
/**
* Replace all occurrences of searchFor with replaceWith in the
* given source .
* @ param source The string to modify
* @ param searchFor What should be searched for
* @ param replaceWith What will replace the found item
*/
static void findAndReplace ( std : : string & source , const std : : string & searchFor , const std : : string & replaceWith )
2009-02-10 22:51:52 +01:00
{
2009-09-05 21:01:49 +02:00
std : : string : : size_type index = 0 ;
2011-10-13 20:53:06 +02:00
while ( ( index = source . find ( searchFor , index ) ) ! = std : : string : : npos ) {
2009-09-05 21:01:49 +02:00
source . replace ( index , searchFor . length ( ) , replaceWith ) ;
2015-09-02 16:06:19 +02:00
index + = replaceWith . length ( ) ;
2009-09-05 21:01:49 +02:00
}
}
2018-04-23 09:18:32 +02:00
// TODO: read info from some shared resource instead?
2019-08-18 16:33:32 +02:00
static std : : string readCode ( const std : : string & file , int linenr , int column , const char endl [ ] )
2018-04-23 09:18:32 +02:00
{
std : : ifstream fin ( file ) ;
std : : string line ;
while ( linenr > 0 & & std : : getline ( fin , line ) ) {
linenr - - ;
}
const std : : string : : size_type endPos = line . find_last_not_of ( " \r \n \t " ) ;
if ( endPos + 1 < line . size ( ) )
line . erase ( endPos + 1 ) ;
2018-04-23 14:11:33 +02:00
std : : string : : size_type pos = 0 ;
2018-06-17 16:39:28 +02:00
while ( ( pos = line . find ( ' \t ' , pos ) ) ! = std : : string : : npos )
2018-04-23 14:11:33 +02:00
line [ pos ] = ' ' ;
2022-07-07 15:07:17 +02:00
return line + endl + std : : string ( ( column > 0 ? column - 1 : 0 ) , ' ' ) + ' ^ ' ;
2018-04-23 09:18:32 +02:00
}
2023-04-08 22:19:52 +02:00
static void replaceSpecialChars ( std : : string & source )
{
// Support a few special characters to allow to specific formatting, see http://sourceforge.net/apps/phpbb/cppcheck/viewtopic.php?f=4&t=494&sid=21715d362c0dbafd3791da4d9522f814
// Substitution should be done first so messages from cppcheck never get translated.
static const std : : unordered_map < char , std : : string > substitutionMap = {
{ ' b ' , " \b " } ,
{ ' n ' , " \n " } ,
{ ' r ' , " \r " } ,
{ ' t ' , " \t " }
} ;
std : : string : : size_type index = 0 ;
while ( ( index = source . find ( ' \\ ' , index ) ) ! = std : : string : : npos ) {
const char searchFor = source [ index + 1 ] ;
const auto it = substitutionMap . find ( searchFor ) ;
if ( it = = substitutionMap . end ( ) ) {
index + = 1 ;
continue ;
}
const std : : string & replaceWith = it - > second ;
source . replace ( index , 2 , replaceWith ) ;
index + = replaceWith . length ( ) ;
}
}
static void replace ( std : : string & source , const std : : unordered_map < std : : string , std : : string > & substitutionMap )
{
std : : string : : size_type index = 0 ;
while ( ( index = source . find ( ' { ' , index ) ) ! = std : : string : : npos ) {
const std : : string : : size_type end = source . find ( ' } ' , index ) ;
if ( end = = std : : string : : npos )
break ;
const std : : string searchFor = source . substr ( index , end - index + 1 ) ;
const auto it = substitutionMap . find ( searchFor ) ;
if ( it = = substitutionMap . end ( ) ) {
index + = 1 ;
continue ;
}
const std : : string & replaceWith = it - > second ;
source . replace ( index , searchFor . length ( ) , replaceWith ) ;
index + = replaceWith . length ( ) ;
}
}
static void replaceColors ( std : : string & source ) {
// TODO: colors are not applied when either stdout or stderr is not a TTY because we resolve them before the stream usage
static const std : : unordered_map < std : : string , std : : string > substitutionMap =
{
{ " {reset} " , : : toString ( Color : : Reset ) } ,
{ " {bold} " , : : toString ( Color : : Bold ) } ,
{ " {dim} " , : : toString ( Color : : Dim ) } ,
{ " {red} " , : : toString ( Color : : FgRed ) } ,
{ " {green} " , : : toString ( Color : : FgGreen ) } ,
{ " {blue} " , : : toString ( Color : : FgBlue ) } ,
{ " {magenta} " , : : toString ( Color : : FgMagenta ) } ,
{ " {default} " , : : toString ( Color : : FgDefault ) } ,
} ;
replace ( source , substitutionMap ) ;
2021-07-08 21:21:35 +02:00
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : toString ( bool verbose , const std : : string & templateFormat , const std : : string & templateLocation ) const
2009-09-05 21:01:49 +02:00
{
2010-12-30 22:07:27 +01:00
// Save this ErrorMessage in plain text.
// No template is given
2018-04-23 12:21:18 +02:00
if ( templateFormat . empty ( ) ) {
2022-12-09 19:34:51 +01:00
std : : string text ;
if ( ! callStack . empty ( ) ) {
text + = ErrorLogger : : callStackToString ( callStack ) ;
text + = " : " ;
}
2019-08-18 12:19:05 +02:00
if ( severity ! = Severity : : none ) {
2022-12-09 19:34:51 +01:00
text + = ' ( ' ;
text + = Severity : : toString ( severity ) ;
2021-02-24 22:00:06 +01:00
if ( certainty = = Certainty : : inconclusive )
2022-12-09 19:34:51 +01:00
text + = " , inconclusive " ;
text + = " ) " ;
2012-05-06 19:37:41 +02:00
}
2022-12-09 19:34:51 +01:00
text + = ( verbose ? mVerboseMessage : mShortMessage ) ;
return text ;
2009-09-05 21:01:49 +02:00
}
2010-12-30 22:07:27 +01:00
2018-04-23 12:21:18 +02:00
// template is given. Reformat the output according to it
std : : string result = templateFormat ;
2019-08-18 12:19:05 +02:00
findAndReplace ( result , " {id} " , id ) ;
2021-07-08 21:21:35 +02:00
std : : string : : size_type pos1 = result . find ( " {inconclusive: " ) ;
while ( pos1 ! = std : : string : : npos ) {
2018-06-17 16:39:28 +02:00
const std : : string : : size_type pos2 = result . find ( ' } ' , pos1 + 1 ) ;
2018-04-23 12:21:18 +02:00
const std : : string replaceFrom = result . substr ( pos1 , pos2 - pos1 + 1 ) ;
2021-02-24 22:00:06 +01:00
const std : : string replaceWith = ( certainty = = Certainty : : inconclusive ) ? result . substr ( pos1 + 14 , pos2 - pos1 - 14 ) : std : : string ( ) ;
2018-04-23 12:21:18 +02:00
findAndReplace ( result , replaceFrom , replaceWith ) ;
2021-07-08 21:21:35 +02:00
pos1 = result . find ( " {inconclusive: " , pos1 ) ;
2018-04-23 12:21:18 +02:00
}
2019-08-18 12:19:05 +02:00
findAndReplace ( result , " {severity} " , Severity : : toString ( severity ) ) ;
findAndReplace ( result , " {cwe} " , MathLib : : toString ( cwe . id ) ) ;
2018-06-17 07:55:47 +02:00
findAndReplace ( result , " {message} " , verbose ? mVerboseMessage : mShortMessage ) ;
2019-08-18 12:19:05 +02:00
if ( ! callStack . empty ( ) ) {
2022-12-09 19:34:51 +01:00
if ( result . find ( " {callstack} " ) ! = std : : string : : npos )
findAndReplace ( result , " {callstack} " , ErrorLogger : : callStackToString ( callStack ) ) ;
2019-08-18 12:19:05 +02:00
findAndReplace ( result , " {file} " , callStack . back ( ) . getfile ( ) ) ;
findAndReplace ( result , " {line} " , MathLib : : toString ( callStack . back ( ) . line ) ) ;
findAndReplace ( result , " {column} " , MathLib : : toString ( callStack . back ( ) . column ) ) ;
2018-04-23 12:21:18 +02:00
if ( result . find ( " {code} " ) ! = std : : string : : npos ) {
2018-06-17 16:39:28 +02:00
const std : : string : : size_type pos = result . find ( ' \r ' ) ;
2018-04-23 12:21:18 +02:00
const char * endl ;
if ( pos = = std : : string : : npos )
endl = " \n " ;
else if ( pos + 1 < result . size ( ) & & result [ pos + 1 ] = = ' \n ' )
endl = " \r \n " ;
else
endl = " \r " ;
2019-08-18 12:19:05 +02:00
findAndReplace ( result , " {code} " , readCode ( callStack . back ( ) . getOrigFile ( ) , callStack . back ( ) . line , callStack . back ( ) . column , endl ) ) ;
2017-05-22 11:25:58 +02:00
}
2018-04-23 12:21:18 +02:00
} else {
2023-04-08 22:19:52 +02:00
static const std : : unordered_map < std : : string , std : : string > callStackSubstitutionMap =
{
{ " {callstack} " , " " } ,
{ " {file} " , " nofile " } ,
{ " {line} " , " 0 " } ,
{ " {column} " , " 0 " } ,
{ " {code} " , " " }
} ;
replace ( result , callStackSubstitutionMap ) ;
2017-05-19 17:09:49 +02:00
}
2019-08-18 12:19:05 +02:00
if ( ! templateLocation . empty ( ) & & callStack . size ( ) > = 2U ) {
for ( const FileLocation & fileLocation : callStack ) {
2018-04-23 12:21:18 +02:00
std : : string text = templateLocation ;
findAndReplace ( text , " {file} " , fileLocation . getfile ( ) ) ;
findAndReplace ( text , " {line} " , MathLib : : toString ( fileLocation . line ) ) ;
2019-08-18 12:19:05 +02:00
findAndReplace ( text , " {column} " , MathLib : : toString ( fileLocation . column ) ) ;
2018-06-17 07:54:50 +02:00
findAndReplace ( text , " {info} " , fileLocation . getinfo ( ) . empty ( ) ? mShortMessage : fileLocation . getinfo ( ) ) ;
2018-04-23 12:21:18 +02:00
if ( text . find ( " {code} " ) ! = std : : string : : npos ) {
2018-06-17 16:39:28 +02:00
const std : : string : : size_type pos = text . find ( ' \r ' ) ;
2018-04-23 09:18:32 +02:00
const char * endl ;
if ( pos = = std : : string : : npos )
endl = " \n " ;
2018-04-23 12:21:18 +02:00
else if ( pos + 1 < text . size ( ) & & text [ pos + 1 ] = = ' \n ' )
2018-04-23 09:18:32 +02:00
endl = " \r \n " ;
else
endl = " \r " ;
2019-08-18 12:19:05 +02:00
findAndReplace ( text , " {code} " , readCode ( fileLocation . getOrigFile ( ) , fileLocation . line , fileLocation . column , endl ) ) ;
2018-04-23 09:18:32 +02:00
}
2018-04-23 12:21:18 +02:00
result + = ' \n ' + text ;
2009-09-05 21:01:49 +02:00
}
}
2018-04-23 12:21:18 +02:00
return result ;
2009-02-10 22:51:52 +01:00
}
2019-01-21 20:33:22 +01:00
bool ErrorLogger : : reportUnmatchedSuppressions ( const std : : list < Suppressions : : Suppression > & unmatched )
2011-02-16 02:12:15 +01:00
{
2019-01-22 06:45:22 +01:00
bool err = false ;
2012-07-13 08:29:49 +02:00
// Report unmatched suppressions
2018-09-23 17:02:54 +02:00
for ( const Suppressions : : Suppression & s : unmatched ) {
2012-07-13 08:29:49 +02:00
// don't report "unmatchedSuppression" as unmatched
2018-09-23 17:02:54 +02:00
if ( s . errorId = = " unmatchedSuppression " )
2012-07-13 08:29:49 +02:00
continue ;
// check if this unmatched suppression is suppressed
bool suppressed = false ;
2018-09-23 17:02:54 +02:00
for ( const Suppressions : : Suppression & s2 : unmatched ) {
if ( s2 . errorId = = " unmatchedSuppression " ) {
2019-12-11 09:07:18 +01:00
if ( ( s2 . fileName . empty ( ) | | s2 . fileName = = " * " | | s2 . fileName = = s . fileName ) & &
2018-09-23 17:02:54 +02:00
( s2 . lineNumber = = Suppressions : : Suppression : : NO_LINE | | s2 . lineNumber = = s . lineNumber ) ) {
2012-07-13 08:29:49 +02:00
suppressed = true ;
2015-08-06 16:10:43 +02:00
break ;
}
2012-07-13 08:29:49 +02:00
}
}
if ( suppressed )
continue ;
2020-05-23 07:16:49 +02:00
std : : list < ErrorMessage : : FileLocation > callStack ;
2018-09-23 17:02:54 +02:00
if ( ! s . fileName . empty ( ) )
2019-08-18 12:19:05 +02:00
callStack . emplace_back ( s . fileName , s . lineNumber , 0 ) ;
2021-02-24 22:00:06 +01:00
reportErr ( ErrorMessage ( callStack , emptyString , Severity : : information , " Unmatched suppression: " + s . errorId , " unmatchedSuppression " , Certainty : : normal ) ) ;
2019-01-22 06:45:22 +01:00
err = true ;
2011-02-16 02:12:15 +01:00
}
2019-01-22 06:45:22 +01:00
return err ;
2011-02-16 02:12:15 +01:00
}
2020-05-23 07:16:49 +02:00
std : : string ErrorLogger : : callStackToString ( const std : : list < ErrorMessage : : FileLocation > & callStack )
2009-02-09 21:51:04 +01:00
{
2021-01-16 19:03:28 +01:00
std : : string str ;
2022-12-20 20:32:16 +01:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator tok = callStack . cbegin ( ) ; tok ! = callStack . cend ( ) ; + + tok ) {
2022-12-30 15:13:47 +01:00
str + = ( tok = = callStack . cbegin ( ) ? " " : " -> " ) ;
2021-01-16 19:03:28 +01:00
str + = tok - > stringify ( ) ;
2011-02-16 02:12:15 +01:00
}
2021-01-16 19:03:28 +01:00
return str ;
2009-02-01 16:47:36 +01:00
}
2009-05-31 10:12:19 +02:00
2020-05-23 07:16:49 +02:00
ErrorMessage : : FileLocation : : FileLocation ( const Token * tok , const TokenList * tokenList )
2019-08-18 12:19:05 +02:00
: fileIndex ( tok - > fileIndex ( ) ) , line ( tok - > linenr ( ) ) , column ( tok - > column ( ) ) , mOrigFileName ( tokenList - > getOrigFile ( tok ) ) , mFileName ( tokenList - > file ( tok ) )
2021-08-07 20:51:18 +02:00
{ }
2012-05-06 10:17:15 +02:00
2022-07-28 22:51:45 +02:00
ErrorMessage : : FileLocation : : FileLocation ( const Token * tok , std : : string info , const TokenList * tokenList )
: fileIndex ( tok - > fileIndex ( ) ) , line ( tok - > linenr ( ) ) , column ( tok - > column ( ) ) , mOrigFileName ( tokenList - > getOrigFile ( tok ) ) , mFileName ( tokenList - > file ( tok ) ) , mInfo ( std : : move ( info ) )
2021-08-07 20:51:18 +02:00
{ }
2017-05-16 22:38:13 +02:00
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : FileLocation : : getfile ( bool convert ) const
2009-05-31 10:12:19 +02:00
{
2010-07-18 10:20:10 +02:00
if ( convert )
2018-06-17 07:52:59 +02:00
return Path : : toNativeSeparators ( mFileName ) ;
return mFileName ;
2009-05-31 10:12:19 +02:00
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : FileLocation : : getOrigFile ( bool convert ) const
2018-11-18 16:08:08 +01:00
{
if ( convert )
return Path : : toNativeSeparators ( mOrigFileName ) ;
return mOrigFileName ;
}
2022-12-09 19:34:51 +01:00
void ErrorMessage : : FileLocation : : setfile ( std : : string file )
2010-07-17 00:27:40 +02:00
{
2022-12-09 19:34:51 +01:00
mFileName = Path : : fromNativeSeparators ( std : : move ( file ) ) ;
mFileName = Path : : simplifyPath ( std : : move ( mFileName ) ) ;
2010-07-17 00:27:40 +02:00
}
2012-05-06 10:17:15 +02:00
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : FileLocation : : stringify ( ) const
2012-05-06 10:17:15 +02:00
{
2021-01-16 19:03:28 +01:00
std : : string str ;
str + = ' [ ' ;
str + = Path : : toNativeSeparators ( mFileName ) ;
if ( line ! = Suppressions : : Suppression : : NO_LINE ) {
str + = ' : ' ;
str + = std : : to_string ( line ) ;
}
str + = ' ] ' ;
return str ;
2012-05-06 10:17:15 +02:00
}
2015-12-07 18:11:13 +01:00
std : : string ErrorLogger : : toxml ( const std : : string & str )
{
std : : ostringstream xml ;
2022-10-02 07:12:40 +02:00
for ( const unsigned char c : str ) {
2015-12-07 18:11:13 +01:00
switch ( c ) {
case ' < ' :
xml < < " < " ;
break ;
case ' > ' :
xml < < " > " ;
break ;
case ' & ' :
xml < < " & " ;
break ;
case ' \" ' :
xml < < " " " ;
break ;
2020-09-02 07:13:15 +02:00
case ' \' ' :
xml < < " ' " ;
break ;
2015-12-07 18:11:13 +01:00
case ' \0 ' :
xml < < " \\ 0 " ;
break ;
default :
2018-03-31 10:27:34 +02:00
if ( c > = ' ' & & c < = 0x7f )
2015-12-07 18:11:13 +01:00
xml < < c ;
else
xml < < ' x ' ;
break ;
}
}
return xml . str ( ) ;
}
2017-05-16 14:07:23 +02:00
std : : string ErrorLogger : : plistHeader ( const std : : string & version , const std : : vector < std : : string > & files )
{
std : : ostringstream ostr ;
ostr < < " <?xml version= \" 1.0 \" encoding= \" UTF-8 \" ?> \r \n "
< < " <!DOCTYPE plist PUBLIC \" -//Apple Computer//DTD PLIST 1.0//EN \" \" http://www.apple.com/DTDs/PropertyList-1.0.dtd \" > \r \n "
< < " <plist version= \" 1.0 \" > \r \n "
< < " <dict> \r \n "
< < " <key>clang_version</key> \r \n "
< < " <string>cppcheck version " < < version < < " </string> \r \n "
< < " <key>files</key> \r \n "
< < " <array> \r \n " ;
2019-09-19 20:29:33 +02:00
for ( const std : : string & file : files )
ostr < < " <string> " < < ErrorLogger : : toxml ( file ) < < " </string> \r \n " ;
2021-08-07 20:51:18 +02:00
ostr < < " </array> \r \n "
< < " <key>diagnostics</key> \r \n "
< < " <array> \r \n " ;
2017-05-16 14:07:23 +02:00
return ostr . str ( ) ;
}
2020-05-23 07:16:49 +02:00
static std : : string plistLoc ( const char indent [ ] , const ErrorMessage : : FileLocation & loc )
2017-05-16 14:07:23 +02:00
{
std : : ostringstream ostr ;
ostr < < indent < < " <dict> \r \n "
< < indent < < ' ' < < " <key>line</key><integer> " < < loc . line < < " </integer> \r \n "
2019-08-18 12:19:05 +02:00
< < indent < < ' ' < < " <key>col</key><integer> " < < loc . column < < " </integer> \r \n "
2017-05-17 15:22:51 +02:00
< < indent < < ' ' < < " <key>file</key><integer> " < < loc . fileIndex < < " </integer> \r \n "
2017-05-16 14:07:23 +02:00
< < indent < < " </dict> \r \n " ;
return ostr . str ( ) ;
}
2020-05-23 07:16:49 +02:00
std : : string ErrorLogger : : plistData ( const ErrorMessage & msg )
2017-05-16 14:07:23 +02:00
{
std : : ostringstream plist ;
plist < < " <dict> \r \n "
< < " <key>path</key> \r \n "
< < " <array> \r \n " ;
2022-12-20 20:32:16 +01:00
std : : list < ErrorMessage : : FileLocation > : : const_iterator prev = msg . callStack . cbegin ( ) ;
2017-05-16 14:07:23 +02:00
2022-12-20 20:32:16 +01:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator it = msg . callStack . cbegin ( ) ; it ! = msg . callStack . cend ( ) ; + + it ) {
2017-05-16 14:07:23 +02:00
if ( prev ! = it ) {
plist < < " <dict> \r \n "
< < " <key>kind</key><string>control</string> \r \n "
< < " <key>edges</key> \r \n "
< < " <array> \r \n "
< < " <dict> \r \n "
< < " <key>start</key> \r \n "
< < " <array> \r \n "
< < plistLoc ( " " , * prev )
< < plistLoc ( " " , * prev )
< < " </array> \r \n "
< < " <key>end</key> \r \n "
< < " <array> \r \n "
< < plistLoc ( " " , * it )
< < plistLoc ( " " , * it )
< < " </array> \r \n "
< < " </dict> \r \n "
< < " </array> \r \n "
< < " </dict> \r \n " ;
prev = it ;
}
2020-05-23 07:16:49 +02:00
std : : list < ErrorMessage : : FileLocation > : : const_iterator next = it ;
2017-05-16 14:07:23 +02:00
+ + next ;
2022-12-30 15:13:47 +01:00
const std : : string message = ( it - > getinfo ( ) . empty ( ) & & next = = msg . callStack . cend ( ) ? msg . shortMessage ( ) : it - > getinfo ( ) ) ;
2017-05-16 14:07:23 +02:00
plist < < " <dict> \r \n "
< < " <key>kind</key><string>event</string> \r \n "
< < " <key>location</key> \r \n "
< < plistLoc ( " " , * it )
< < " <key>ranges</key> \r \n "
< < " <array> \r \n "
< < " <array> \r \n "
< < plistLoc ( " " , * it )
< < plistLoc ( " " , * it )
< < " </array> \r \n "
< < " </array> \r \n "
< < " <key>depth</key><integer>0</integer> \r \n "
< < " <key>extended_message</key> \r \n "
2017-05-17 15:22:51 +02:00
< < " <string> " < < ErrorLogger : : toxml ( message ) < < " </string> \r \n "
2019-04-08 18:09:18 +02:00
< < " <key>message</key> \r \n "
2017-05-17 15:22:51 +02:00
< < " <string> " < < ErrorLogger : : toxml ( message ) < < " </string> \r \n "
2017-05-16 14:07:23 +02:00
< < " </dict> \r \n " ;
}
plist < < " </array> \r \n "
< < " <key>description</key><string> " < < ErrorLogger : : toxml ( msg . shortMessage ( ) ) < < " </string> \r \n "
2019-08-18 12:19:05 +02:00
< < " <key>category</key><string> " < < Severity : : toString ( msg . severity ) < < " </string> \r \n "
2017-05-16 14:07:23 +02:00
< < " <key>type</key><string> " < < ErrorLogger : : toxml ( msg . shortMessage ( ) ) < < " </string> \r \n "
2019-08-18 12:19:05 +02:00
< < " <key>check_name</key><string> " < < msg . id < < " </string> \r \n "
2017-05-16 14:07:23 +02:00
< < " <!-- This hash is experimental and going to change! --> \r \n "
< < " <key>issue_hash_content_of_line_in_context</key><string> " < < 0 < < " </string> \r \n "
< < " <key>issue_context_kind</key><string></string> \r \n "
< < " <key>issue_context</key><string></string> \r \n "
< < " <key>issue_hash_function_offset</key><string></string> \r \n "
< < " <key>location</key> \r \n "
2019-08-18 12:19:05 +02:00
< < plistLoc ( " " , msg . callStack . back ( ) )
2017-05-16 14:07:23 +02:00
< < " </dict> \r \n " ;
return plist . str ( ) ;
}
2018-12-28 13:11:54 +01:00
std : : string replaceStr ( std : : string s , const std : : string & from , const std : : string & to )
{
std : : string : : size_type pos1 = 0 ;
while ( pos1 < s . size ( ) ) {
pos1 = s . find ( from , pos1 ) ;
if ( pos1 = = std : : string : : npos )
return s ;
if ( pos1 > 0 & & ( s [ pos1 - 1 ] = = ' _ ' | | std : : isalnum ( s [ pos1 - 1 ] ) ) ) {
pos1 + + ;
continue ;
}
const std : : string : : size_type pos2 = pos1 + from . size ( ) ;
if ( pos2 > = s . size ( ) )
return s . substr ( 0 , pos1 ) + to ;
if ( s [ pos2 ] = = ' _ ' | | std : : isalnum ( s [ pos2 ] ) ) {
pos1 + + ;
continue ;
}
2022-07-11 23:07:37 +02:00
s . replace ( pos1 , from . size ( ) , to ) ;
2018-12-28 13:11:54 +01:00
pos1 + = to . size ( ) ;
}
return s ;
}
2023-04-08 22:19:52 +02:00
void substituteTemplateFormatStatic ( std : : string & templateFormat )
{
replaceSpecialChars ( templateFormat ) ;
replaceColors ( templateFormat ) ;
}
void substituteTemplateLocationStatic ( std : : string & templateLocation )
{
replaceSpecialChars ( templateLocation ) ;
replaceColors ( templateLocation ) ;
}