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
2020-05-10 11:16:32 +02:00
* Copyright ( C ) 2007 - 2020 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
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"
2016-02-27 16:03:50 +01:00
# include "utils.h"
2009-01-03 14:51:55 +01:00
2013-08-07 16:30:55 +02:00
# include <tinyxml2.h>
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>
2020-07-14 22:30:42 +02:00
# include <functional> // std::hash
2009-02-01 16:47:36 +01:00
2014-03-27 13:15:21 +01:00
InternalError : : InternalError ( const Token * tok , const std : : string & errorMsg , Type type ) :
2018-11-13 20:14:56 +01:00
token ( tok ) , errorMessage ( errorMsg ) , type ( type )
2012-01-08 21:19:44 +01:00
{
2014-03-27 13:15:21 +01:00
switch ( type ) {
2017-09-05 16:56:13 +02:00
case AST :
id = " internalAstError " ;
break ;
2014-03-27 13:15:21 +01:00
case SYNTAX :
id = " syntaxError " ;
break ;
2018-11-13 20:14:56 +01:00
case UNKNOWN_MACRO :
id = " unknownMacro " ;
break ;
2014-03-27 13:15:21 +01:00
case INTERNAL :
id = " cppcheckError " ;
break ;
2019-07-12 07:56:05 +02:00
case LIMIT :
id = " cppcheckLimit " ;
break ;
2019-07-15 12:41:06 +02:00
case INSTANTIATION :
id = " instantiationError " ;
break ;
2014-03-27 13:15:21 +01:00
}
2012-01-08 21:19:44 +01:00
}
2020-07-21 11:27:03 +02:00
static std : : size_t calculateWarningHash ( const TokenList * tokenList , const std : : string & msg )
2020-07-14 22:30:42 +02:00
{
if ( ! tokenList )
return 0 ;
return std : : hash < std : : string > { } ( msg + " \n " + tokenList - > front ( ) - > stringifyList ( false , true , false , false , false ) ) ;
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( )
2020-07-21 11:27:03 +02:00
: incomplete ( false ) , severity ( Severity : : none ) , cwe ( 0U ) , inconclusive ( false ) , hash ( 0 )
2009-02-19 23:21:18 +01:00
{
}
2010-07-27 09:32:20 +02:00
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const std : : list < FileLocation > & callStack , const std : : string & file1 , Severity : : SeverityType severity , const std : : string & msg , const std : : string & id , bool inconclusive ) :
2019-08-18 12:19:05 +02:00
callStack ( callStack ) , // locations for this error message
id ( id ) , // set the message id
lib: fix a bunch of warnings about differing function arguments in definition and declaration.
[lib/token.h:72] -> [lib/token.cpp:36]: (style, inconclusive) Function 'Token' argument 1 names different: declaration 'tokensBack' definition 't'.
[lib/token.h:445] -> [lib/token.cpp:497]: (style, inconclusive) Function 'multiCompare' argument 1 names different: declaration 'needle' definition 'tok'.
[lib/checkio.h:73] -> [lib/checkio.cpp:1385]: (style, inconclusive) Function 'ArgumentInfo' argument 3 names different: declaration 'isCPP' definition '_isCPP'.
[lib/checkother.h:216] -> [lib/checkother.cpp:2136]: (style, inconclusive) Function 'checkComparisonFunctionIsAlwaysTrueOrFalseError' argument 2 names different: declaration 'strFunctionName' definition 'functionName'.
[lib/errorlogger.h:214] -> [lib/errorlogger.cpp:51]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/errorlogger.h:215] -> [lib/errorlogger.cpp:65]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/library.h:327] -> [lib/library.cpp:1043]: (style, inconclusive) Function 'ignorefunction' argument 1 names different: declaration 'function' definition 'functionName'.
[lib/mathlib.h:112] -> [lib/mathlib.cpp:1275]: (style, inconclusive) Function 'isNullValue' argument 1 names different: declaration 'tok' definition 'str'.
[lib/preprocessor.h:91] -> [lib/preprocessor.cpp:122]: (style, inconclusive) Function 'setDirectives' argument 1 names different: declaration 'tokens' definition 'tokens1'.
[lib/symboldatabase.h:860] -> [lib/symboldatabase.cpp:1801]: (style, inconclusive) Function 'argsMatch' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1171] -> [lib/symboldatabase.cpp:2048]: (style, inconclusive) Function 'addClassFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1174] -> [lib/symboldatabase.cpp:2208]: (style, inconclusive) Function 'addNewFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1090] -> [lib/symboldatabase.cpp:3648]: (style, inconclusive) Function 'findVariableType' argument 2 names different: declaration 'type' definition 'typeTok'.
[lib/symboldatabase.h:1101] -> [lib/symboldatabase.cpp:4308]: (style, inconclusive) Function 'findType' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1176] -> [lib/symboldatabase.cpp:4349]: (style, inconclusive) Function 'findTypeInNested' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1193] -> [lib/symboldatabase.cpp:4501]: (style, inconclusive) Function 'setValueType' argument 2 names different: declaration 'enumerators' definition 'enumerator'.
[lib/path.h:159] -> [lib/path.cpp:247]: (style, inconclusive) Function 'isCPP' argument 1 names different: declaration 'extensionInLowerCase' definition 'path'.
[lib/path.h:145] -> [lib/path.cpp:266]: (style, inconclusive) Function 'acceptFile' argument 1 names different: declaration 'filename' definition 'path'.
2017-04-03 00:06:46 +02:00
file0 ( file1 ) ,
2020-05-03 17:20:38 +02:00
incomplete ( false ) ,
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 ) ,
2020-07-14 22:30:42 +02:00
inconclusive ( inconclusive ) ,
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
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const std : : list < FileLocation > & callStack , const std : : string & file1 , Severity : : SeverityType severity , const std : : string & msg , const std : : string & id , const CWE & cwe , bool inconclusive ) :
2019-08-18 12:19:05 +02:00
callStack ( callStack ) , // locations for this error message
id ( id ) , // set the message id
lib: fix a bunch of warnings about differing function arguments in definition and declaration.
[lib/token.h:72] -> [lib/token.cpp:36]: (style, inconclusive) Function 'Token' argument 1 names different: declaration 'tokensBack' definition 't'.
[lib/token.h:445] -> [lib/token.cpp:497]: (style, inconclusive) Function 'multiCompare' argument 1 names different: declaration 'needle' definition 'tok'.
[lib/checkio.h:73] -> [lib/checkio.cpp:1385]: (style, inconclusive) Function 'ArgumentInfo' argument 3 names different: declaration 'isCPP' definition '_isCPP'.
[lib/checkother.h:216] -> [lib/checkother.cpp:2136]: (style, inconclusive) Function 'checkComparisonFunctionIsAlwaysTrueOrFalseError' argument 2 names different: declaration 'strFunctionName' definition 'functionName'.
[lib/errorlogger.h:214] -> [lib/errorlogger.cpp:51]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/errorlogger.h:215] -> [lib/errorlogger.cpp:65]: (style, inconclusive) Function 'ErrorMessage' argument 2 names different: declaration 'file0' definition 'file0_'.
[lib/library.h:327] -> [lib/library.cpp:1043]: (style, inconclusive) Function 'ignorefunction' argument 1 names different: declaration 'function' definition 'functionName'.
[lib/mathlib.h:112] -> [lib/mathlib.cpp:1275]: (style, inconclusive) Function 'isNullValue' argument 1 names different: declaration 'tok' definition 'str'.
[lib/preprocessor.h:91] -> [lib/preprocessor.cpp:122]: (style, inconclusive) Function 'setDirectives' argument 1 names different: declaration 'tokens' definition 'tokens1'.
[lib/symboldatabase.h:860] -> [lib/symboldatabase.cpp:1801]: (style, inconclusive) Function 'argsMatch' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1171] -> [lib/symboldatabase.cpp:2048]: (style, inconclusive) Function 'addClassFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1174] -> [lib/symboldatabase.cpp:2208]: (style, inconclusive) Function 'addNewFunction' argument 1 names different: declaration 'info' definition 'scope'.
[lib/symboldatabase.h:1090] -> [lib/symboldatabase.cpp:3648]: (style, inconclusive) Function 'findVariableType' argument 2 names different: declaration 'type' definition 'typeTok'.
[lib/symboldatabase.h:1101] -> [lib/symboldatabase.cpp:4308]: (style, inconclusive) Function 'findType' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1176] -> [lib/symboldatabase.cpp:4349]: (style, inconclusive) Function 'findTypeInNested' argument 1 names different: declaration 'tok' definition 'startTok'.
[lib/symboldatabase.h:1193] -> [lib/symboldatabase.cpp:4501]: (style, inconclusive) Function 'setValueType' argument 2 names different: declaration 'enumerators' definition 'enumerator'.
[lib/path.h:159] -> [lib/path.cpp:247]: (style, inconclusive) Function 'isCPP' argument 1 names different: declaration 'extensionInLowerCase' definition 'path'.
[lib/path.h:145] -> [lib/path.cpp:266]: (style, inconclusive) Function 'acceptFile' argument 1 names different: declaration 'filename' definition 'path'.
2017-04-03 00:06:46 +02:00
file0 ( file1 ) ,
2020-05-03 17:20:38 +02:00
incomplete ( false ) ,
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 ) ,
2020-07-14 22:30:42 +02:00
inconclusive ( inconclusive ) ,
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 ) ;
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const std : : list < const Token * > & callstack , const TokenList * list , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg , bool inconclusive )
2020-07-21 11:27:03 +02:00
: id ( id ) , incomplete ( false ) , severity ( severity ) , cwe ( 0U ) , inconclusive ( inconclusive ) , hash ( 0 )
2012-05-06 10:17:15 +02:00
{
// Format callstack
for ( std : : list < const Token * > : : const_iterator it = callstack . begin ( ) ; it ! = callstack . end ( ) ; + + it ) {
// --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 ) ;
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const std : : list < const Token * > & callstack , const TokenList * list , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg , const CWE & cwe , bool inconclusive )
2020-05-03 20:46:29 +02:00
: id ( id ) , incomplete ( false ) , severity ( severity ) , cwe ( cwe . id ) , inconclusive ( inconclusive )
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
2020-07-21 15:59:48 +02:00
std : : ostringstream hashWarning ;
for ( const Token * tok : callstack )
hashWarning < < std : : hex < < ( tok ? tok - > index ( ) : 0 ) < < " " ;
hashWarning < < mShortMessage ;
hash = calculateWarningHash ( list , hashWarning . str ( ) ) ;
2012-05-06 10:17:15 +02:00
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : ErrorMessage ( const ErrorPath & errorPath , const TokenList * tokenList , Severity : : SeverityType severity , const char id [ ] , const std : : string & msg , const CWE & cwe , bool inconclusive )
2020-05-03 20:46:29 +02:00
: id ( id ) , incomplete ( false ) , severity ( severity ) , cwe ( cwe . id ) , inconclusive ( inconclusive )
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 ;
const std : : string & info = e . second ;
2017-05-16 22:38:13 +02:00
// --errorlist can provide null values here
if ( tok )
2019-08-18 12:19:05 +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
2020-07-21 15:59:48 +02:00
std : : ostringstream hashWarning ;
for ( const ErrorPathItem & e : errorPath )
2020-07-21 17:43:12 +02:00
hashWarning < < std : : hex < < ( e . first ? e . first - > index ( ) : 0 ) < < " " ;
2020-07-21 15:59:48 +02:00
hashWarning < < mShortMessage ;
hash = 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 )
2020-05-03 20:46:29 +02:00
: incomplete ( false ) ,
severity ( Severity : : none ) ,
2019-08-18 12:19:05 +02:00
cwe ( 0U ) ,
inconclusive ( false )
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 " ) ;
2019-08-18 12:19:05 +02:00
std : : istringstream ( attr ? attr : " 0 " ) > > cwe . id ;
2017-08-16 16:53:04 +02:00
2016-10-29 12:18:11 +02:00
attr = errmsg - > Attribute ( " inconclusive " ) ;
2019-08-18 12:19:05 +02:00
inconclusive = attr & & ( std : : strcmp ( attr , " true " ) = = 0 ) ;
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 " ) ;
std : : istringstream ( attr ? attr : " 0 " ) > > hash ;
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 : " " ;
const int line = strline ? std : : atoi ( strline ) : 0 ;
2019-08-18 12:19:05 +02:00
const int column = strcolumn ? std : : atoi ( strcolumn ) : 0 ;
callStack . emplace_back ( file , info , line , column ) ;
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 ;
2018-04-09 06:43:48 +02:00
}
2019-08-18 12:19:05 +02:00
ret . inconclusive = inconclusive ;
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 ) ;
2019-08-18 12:19:05 +02:00
if ( 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
2020-05-23 07:16:49 +02:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator loc = callStack . begin ( ) ; loc ! = callStack . end ( ) ; + + 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 ( ) ;
}
2020-05-23 07:16:49 +02:00
bool ErrorMessage : : deserialize ( const std : : string & data )
2009-02-19 23:21:18 +01:00
{
2019-08-18 12:19:05 +02:00
inconclusive = false ;
callStack . clear ( ) ;
2009-02-19 23:21:18 +01:00
std : : istringstream iss ( data ) ;
2020-07-14 22:30:42 +02:00
std : : array < std : : string , 6 > results ;
2015-11-29 10:49:10 +01:00
std : : size_t elem = 0 ;
2020-07-14 22:30:42 +02:00
while ( iss . good ( ) & & elem < 6 ) {
2009-02-19 23:21:18 +01:00
unsigned int len = 0 ;
2010-04-02 07:30:58 +02:00
if ( ! ( iss > > len ) )
2009-02-19 23:21:18 +01:00
return false ;
iss . get ( ) ;
std : : string temp ;
2011-10-13 20:53:06 +02:00
for ( unsigned int i = 0 ; i < len & & iss . good ( ) ; + + i ) {
2018-05-29 13:24:48 +02:00
const char c = static_cast < char > ( iss . get ( ) ) ;
2009-03-08 19:50:19 +01:00
temp . append ( 1 , c ) ;
}
2009-02-19 23:21:18 +01:00
2011-10-13 20:53:06 +02:00
if ( temp = = " inconclusive " ) {
2019-08-18 12:19:05 +02:00
inconclusive = true ;
2011-04-16 13:42:48 +02:00
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
}
2020-07-14 22:30:42 +02:00
if ( elem ! = 6 )
2017-08-09 20:00:26 +02:00
throw InternalError ( nullptr , " Internal Error: Deserialization of error message failed " ) ;
2015-01-17 15:56:09 +01:00
2019-08-18 12:19:05 +02:00
id = results [ 0 ] ;
severity = Severity : : fromString ( results [ 1 ] ) ;
2020-07-14 22:30:42 +02:00
std : : istringstream ( results [ 2 ] ) > > cwe . id ;
2020-07-21 11:27:03 +02:00
std : : istringstream ( results [ 3 ] ) > > hash ;
2020-07-14 22:30:42 +02:00
mShortMessage = results [ 4 ] ;
mVerboseMessage = results [ 5 ] ;
2009-02-19 23:21:18 +01:00
unsigned int stackSize = 0 ;
2010-04-02 07:30:58 +02:00
if ( ! ( iss > > stackSize ) )
2009-02-19 23:21:18 +01:00
return false ;
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 ) )
2009-02-19 23:21:18 +01:00
return false ;
iss . get ( ) ;
std : : string temp ;
2011-10-13 20:53:06 +02:00
for ( unsigned int i = 0 ; i < len & & iss . good ( ) ; + + i ) {
2016-02-27 16:03:50 +01:00
const char c = static_cast < char > ( iss . get ( ) ) ;
2009-03-08 19:50:19 +01:00
temp . append ( 1 , c ) ;
}
2009-02-19 23:21:18 +01:00
2019-08-18 16:33:32 +02:00
std : : vector < std : : string > substrings ;
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 ;
pos = temp . find ( " \t " , pos ) ;
if ( pos = = std : : string : : npos ) {
substrings . push_back ( temp . substr ( start ) ) ;
break ;
}
substrings . push_back ( temp . substr ( start , pos - start ) ) ;
}
if ( substrings . size ( ) < 4 )
throw InternalError ( nullptr , " Internal Error: serializing/deserializing of error message failed! " ) ;
// (*loc).line << '\t' << (*loc).column << '\t' << (*loc).getfile(false) << '\t' << loc->getOrigFile(false) << '\t' << loc->getinfo();
2020-05-23 07:16:49 +02:00
ErrorMessage : : FileLocation loc ( substrings [ 3 ] , MathLib : : toLongNumber ( substrings [ 0 ] ) , MathLib : : toLongNumber ( substrings [ 1 ] ) ) ;
2019-08-18 16:33:32 +02:00
loc . setfile ( substrings [ 2 ] ) ;
if ( substrings . size ( ) = = 5 )
loc . setinfo ( substrings [ 4 ] ) ;
2009-02-19 23:21:18 +01:00
2019-08-18 12:19:05 +02:00
callStack . push_back ( 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 ;
}
return true ;
}
2020-05-23 07:16:49 +02:00
std : : string ErrorMessage : : getXMLHeader ( )
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 ) ;
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 ( ) ) ;
std : : string : : const_iterator from = raw . begin ( ) ;
while ( from ! = raw . end ( ) ) {
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 ( ) ) ;
2019-08-18 12:19:05 +02:00
if ( inconclusive )
2017-07-29 18:56:22 +02:00
printer . PushAttribute ( " inconclusive " , " true " ) ;
2019-08-18 12:19:05 +02:00
for ( std : : list < FileLocation > : : const_reverse_iterator it = callStack . rbegin ( ) ; it ! = callStack . rend ( ) ; + + it ) {
2017-07-29 18:56:22 +02:00
printer . OpenElement ( " location " , false ) ;
if ( ! file0 . empty ( ) & & ( * it ) . getfile ( ) ! = file0 )
printer . PushAttribute ( " file0 " , Path : : toNativeSeparators ( file0 ) . c_str ( ) ) ;
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
}
2020-05-23 07:16:49 +02:00
void ErrorMessage : : 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 ] = ' ' ;
2018-04-23 12:21:18 +02:00
return line + endl + std : : string ( ( column > 0 ? column - 1 : column ) , ' ' ) + ' ^ ' ;
2018-04-23 09:18:32 +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 ( ) ) {
2009-09-05 21:01:49 +02:00
std : : ostringstream text ;
2019-08-18 12:19:05 +02:00
if ( ! callStack . empty ( ) )
2020-05-23 07:16:49 +02:00
text < < ErrorLogger : : callStackToString ( callStack ) < < " : " ;
2019-08-18 12:19:05 +02:00
if ( severity ! = Severity : : none ) {
text < < ' ( ' < < Severity : : toString ( severity ) ;
if ( inconclusive )
2012-05-06 19:37:41 +02:00
text < < " , inconclusive " ;
text < < " ) " ;
}
2018-06-17 07:55:47 +02:00
text < < ( verbose ? mVerboseMessage : mShortMessage ) ;
2009-09-05 21:01:49 +02:00
return text . str ( ) ;
}
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 ;
// 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.
findAndReplace ( result , " \\ b " , " \b " ) ;
findAndReplace ( result , " \\ n " , " \n " ) ;
findAndReplace ( result , " \\ r " , " \r " ) ;
findAndReplace ( result , " \\ t " , " \t " ) ;
2019-08-18 12:19:05 +02:00
findAndReplace ( result , " {id} " , id ) ;
2018-04-23 12:21:18 +02:00
if ( result . find ( " {inconclusive: " ) ! = std : : string : : npos ) {
const std : : string : : size_type pos1 = result . find ( " {inconclusive: " ) ;
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 ) ;
2019-08-18 12:19:05 +02:00
const std : : string replaceWith = inconclusive ? result . substr ( pos1 + 14 , pos2 - pos1 - 14 ) : std : : string ( ) ;
2018-04-23 12:21:18 +02:00
findAndReplace ( result , replaceFrom , replaceWith ) ;
}
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 ) ;
2020-05-23 07:16:49 +02:00
findAndReplace ( result , " {callstack} " , callStack . empty ( ) ? emptyString : ErrorLogger : : callStackToString ( callStack ) ) ;
2019-08-18 12:19:05 +02:00
if ( ! callStack . empty ( ) ) {
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 {
findAndReplace ( result , " {file} " , " nofile " ) ;
findAndReplace ( result , " {line} " , " 0 " ) ;
findAndReplace ( result , " {column} " , " 0 " ) ;
findAndReplace ( result , " {code} " , emptyString ) ;
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 , " \\ b " , " \b " ) ;
findAndReplace ( text , " \\ n " , " \n " ) ;
findAndReplace ( text , " \\ r " , " \r " ) ;
findAndReplace ( text , " \\ t " , " \t " ) ;
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 ) ;
2020-05-23 07:16:49 +02:00
reportErr ( ErrorMessage ( callStack , emptyString , Severity : : information , " Unmatched suppression: " + s . errorId , " unmatchedSuppression " , false ) ) ;
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
{
std : : ostringstream ostr ;
2020-05-23 07:16:49 +02:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator tok = callStack . begin ( ) ; tok ! = callStack . end ( ) ; + + tok ) {
2012-05-06 10:17:15 +02:00
ostr < < ( tok = = callStack . begin ( ) ? " " : " -> " ) < < tok - > stringify ( ) ;
2011-02-16 02:12:15 +01:00
}
2009-02-09 21:51:04 +01:00
return ostr . 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 ) )
2012-05-06 10:17:15 +02:00
{
}
2020-05-23 07:16:49 +02:00
ErrorMessage : : FileLocation : : FileLocation ( const Token * tok , const std : : string & info , 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 ) ) , mInfo ( info )
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 ;
}
2020-05-23 07:16:49 +02:00
void ErrorMessage : : FileLocation : : setfile ( const std : : string & file )
2010-07-17 00:27:40 +02:00
{
2018-06-17 07:52:59 +02:00
mFileName = file ;
mFileName = Path : : fromNativeSeparators ( mFileName ) ;
mFileName = Path : : simplifyPath ( 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
{
std : : ostringstream oss ;
2018-06-17 07:52:59 +02:00
oss < < ' [ ' < < Path : : toNativeSeparators ( mFileName ) ;
2018-09-18 12:58:14 +02:00
if ( line ! = Suppressions : : Suppression : : NO_LINE )
2012-05-06 10:17:15 +02:00
oss < < ' : ' < < line ;
oss < < ' ] ' ;
return oss . str ( ) ;
}
2015-12-07 18:11:13 +01:00
std : : string ErrorLogger : : toxml ( const std : : string & str )
{
std : : ostringstream xml ;
2019-09-19 20:29:33 +02:00
for ( 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 ;
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 " ;
2017-05-16 14:07:23 +02:00
ostr < < " </array> \r \n "
< < " <key>diagnostics</key> \r \n "
< < " <array> \r \n " ;
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 " ;
2020-05-23 07:16:49 +02:00
std : : list < ErrorMessage : : FileLocation > : : const_iterator prev = msg . callStack . begin ( ) ;
2017-05-16 14:07:23 +02:00
2020-05-23 07:16:49 +02:00
for ( std : : list < ErrorMessage : : FileLocation > : : const_iterator it = msg . callStack . begin ( ) ; it ! = msg . callStack . end ( ) ; + + 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 ;
2019-08-18 12:19:05 +02:00
const std : : string message = ( it - > getinfo ( ) . empty ( ) & & next = = msg . callStack . end ( ) ? 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 ;
}
s = s . substr ( 0 , pos1 ) + to + s . substr ( pos2 ) ;
pos1 + = to . size ( ) ;
}
return s ;
}