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
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 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"
2010-07-17 16:38:36 +02:00
# include "path.h"
2010-12-22 10:29:23 +01:00
# include "cppcheck.h"
2012-05-06 10:17:15 +02:00
# include "tokenlist.h"
2013-05-07 18:18:15 +02:00
# include "token.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>
2011-12-30 00:22:16 +01:00
# include <cassert>
2014-04-13 09:50:57 +02:00
# include <iomanip>
2009-02-01 16:47:36 +01:00
# include <sstream>
2015-11-29 10:49:10 +01:00
# include <array>
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 ) :
2012-01-08 21:19:44 +01:00
token ( tok ) , errorMessage ( errorMsg )
{
2014-03-27 13:15:21 +01:00
switch ( type ) {
case SYNTAX :
id = " syntaxError " ;
break ;
case INTERNAL :
id = " cppcheckError " ;
break ;
}
2012-01-08 21:19:44 +01:00
}
2009-02-19 23:21:18 +01:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( )
2015-04-25 17:48:11 +02:00
: _severity ( Severity : : none ) , _cwe ( 0U ) , _inconclusive ( false )
2009-02-19 23:21:18 +01:00
{
}
2010-07-27 09:32:20 +02:00
2016-07-26 16:27:55 +02:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( const std : : list < FileLocation > & callStack , const std : : string & file0_ , Severity : : SeverityType severity , const std : : string & msg , const std : : string & id , bool inconclusive ) :
2012-04-06 18:16:59 +02:00
_callStack ( callStack ) , // locations for this error message
_id ( id ) , // set the message id
2016-07-26 16:27:55 +02:00
file0 ( file0_ ) ,
2012-05-14 20:46:23 +02:00
_severity ( severity ) , // severity for this error message
2015-04-25 17:48:11 +02:00
_cwe ( 0U ) ,
2012-04-06 18:16:59 +02:00
_inconclusive ( inconclusive )
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
2016-07-26 16:27:55 +02:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( const std : : list < FileLocation > & callStack , const std : : string & file0_ , Severity : : SeverityType severity , const std : : string & msg , const std : : string & id , const CWE & cwe , bool 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
_callStack ( callStack ) , // locations for this error message
_id ( id ) , // set the message id
2016-07-26 16:27:55 +02:00
file0 ( file0_ ) ,
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
_severity ( severity ) , // severity for this error message
_cwe ( cwe . id ) ,
_inconclusive ( inconclusive )
{
// set the summary and verbose messages
setmsg ( msg ) ;
}
2012-05-06 10:17:15 +02:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( const std : : list < const Token * > & callstack , const TokenList * list , Severity : : SeverityType severity , const std : : string & id , const std : : string & msg , bool inconclusive )
2015-04-25 17:48:11 +02:00
: _id ( id ) , _severity ( severity ) , _cwe ( 0U ) , _inconclusive ( inconclusive )
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 ;
_callStack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( * 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 ) ;
}
ErrorLogger : : 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 )
: _id ( id ) , _severity ( severity ) , _cwe ( cwe . id ) , _inconclusive ( inconclusive )
{
// 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 ;
_callStack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( * it , list ) ) ;
2012-05-06 10:17:15 +02:00
}
if ( list & & ! list - > getFiles ( ) . empty ( ) )
file0 = list - > getFiles ( ) [ 0 ] ;
setmsg ( msg ) ;
}
2016-10-29 15:50:08 +02:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( const tinyxml2 : : XMLElement * const errmsg )
: _id ( errmsg - > Attribute ( " id " ) ) ,
_severity ( Severity : : fromString ( errmsg - > Attribute ( " severity " ) ) ) ,
_cwe ( 0U ) ,
_inconclusive ( false ) ,
_shortMessage ( errmsg - > Attribute ( " msg " ) ) ,
_verboseMessage ( errmsg - > Attribute ( " verbose " ) )
2016-10-29 12:18:11 +02:00
{
const char * attr = errmsg - > Attribute ( " cwe " ) ;
std : : istringstream ( attr ? attr : " 0 " ) > > _cwe . id ;
attr = errmsg - > Attribute ( " inconclusive " ) ;
_inconclusive = attr & & ( std : : strcmp ( attr , " true " ) = = 0 ) ;
for ( const tinyxml2 : : XMLElement * e = errmsg - > FirstChildElement ( ) ; e ; e = e - > NextSiblingElement ( ) ) {
if ( std : : strcmp ( e - > Name ( ) , " location " ) = = 0 ) {
_callStack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( e - > Attribute ( " file " ) , std : : atoi ( e - > Attribute ( " line " ) ) ) ) ;
}
}
}
2010-11-11 19:54:43 +01:00
void ErrorLogger : : ErrorMessage : : setmsg ( const std : : string & msg )
{
2011-12-30 00:22:16 +01:00
// If a message ends to a '\n' and contains only a one '\n'
// it will cause the _verboseMessage to be empty which will show
// as an empty message to the user if --verbose is used.
// Even this doesn't cause problems with messages that have multiple
// lines, none of the 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 ' ) ;
2011-10-13 20:53:06 +02:00
if ( pos = = std : : string : : npos ) {
2010-11-11 19:54:43 +01:00
_shortMessage = msg ;
_verboseMessage = msg ;
2011-10-13 20:53:06 +02:00
} else {
2010-11-12 15:43:16 +01:00
_shortMessage = msg . substr ( 0 , pos ) ;
2010-11-11 19:54:43 +01:00
_verboseMessage = msg . substr ( pos + 1 ) ;
}
}
2009-02-19 23:21:18 +01:00
std : : string ErrorLogger : : ErrorMessage : : serialize ( ) const
{
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 ;
oss < < _id . length ( ) < < " " < < _id ;
2010-07-14 18:36:34 +02:00
oss < < Severity : : toString ( _severity ) . length ( ) < < " " < < Severity : : toString ( _severity ) ;
2016-02-27 16:03:50 +01:00
oss < < MathLib : : toString ( _cwe . id ) . length ( ) < < " " < < MathLib : : toString ( _cwe . id ) ;
2011-10-13 20:53:06 +02:00
if ( _inconclusive ) {
2011-04-16 13:42:48 +02:00
const std : : string inconclusive ( " inconclusive " ) ;
oss < < inconclusive . length ( ) < < " " < < inconclusive ;
}
2015-01-17 15:58:36 +01:00
const std : : string saneShortMessage = fixInvalidChars ( _shortMessage ) ;
const std : : string saneVerboseMessage = fixInvalidChars ( _verboseMessage ) ;
oss < < saneShortMessage . length ( ) < < " " < < saneShortMessage ;
oss < < saneVerboseMessage . length ( ) < < " " < < saneVerboseMessage ;
2009-02-19 23:21:18 +01:00
oss < < _callStack . size ( ) < < " " ;
2011-10-13 20:53:06 +02:00
for ( std : : list < ErrorLogger : : ErrorMessage : : FileLocation > : : const_iterator tok = _callStack . begin ( ) ; tok ! = _callStack . end ( ) ; + + tok ) {
2009-02-19 23:21:18 +01:00
std : : ostringstream smallStream ;
2009-05-31 10:12:19 +02:00
smallStream < < ( * tok ) . line < < " : " < < ( * tok ) . getfile ( ) ;
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 ( ) ;
}
bool ErrorLogger : : ErrorMessage : : deserialize ( const std : : string & data )
{
2011-04-14 18:02:01 +02:00
_inconclusive = false ;
2009-02-19 23:21:18 +01:00
_callStack . clear ( ) ;
std : : istringstream iss ( data ) ;
2015-11-29 10:49:10 +01:00
std : : array < std : : string , 5 > results ;
std : : size_t elem = 0 ;
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 ) {
2009-07-20 22:24:23 +02:00
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 " ) {
2011-04-14 18:02:01 +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 ;
if ( elem = = 5 )
2009-02-19 23:21:18 +01:00
break ;
}
2015-11-29 10:49:10 +01:00
if ( elem ! = 5 )
2015-01-17 15:56:09 +01:00
throw InternalError ( 0 , " Internal Error: Deserialization of error message failed " ) ;
2009-02-19 23:21:18 +01:00
_id = results [ 0 ] ;
2010-07-14 18:36:34 +02:00
_severity = Severity : : fromString ( results [ 1 ] ) ;
2015-07-25 13:23:48 +02:00
std : : istringstream scwe ( results [ 2 ] ) ;
2016-02-27 16:03:50 +01:00
scwe > > _cwe . id ;
2015-04-25 17:48:11 +02:00
_shortMessage = results [ 3 ] ;
_verboseMessage = results [ 4 ] ;
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
2016-01-20 14:46:15 +01:00
const std : : string : : size_type colonPos = temp . find ( ' : ' ) ;
if ( colonPos = = std : : string : : npos )
throw InternalError ( 0 , " Internal Error: No colon found in <filename:line> pattern " ) ;
2009-02-19 23:21:18 +01:00
ErrorLogger : : ErrorMessage : : FileLocation loc ;
2016-01-20 14:46:15 +01:00
loc . setfile ( temp . substr ( colonPos + 1 ) ) ;
temp = temp . substr ( 0 , colonPos ) ;
2009-02-19 23:21:18 +01:00
std : : istringstream fiss ( temp ) ;
fiss > > loc . line ;
_callStack . push_back ( loc ) ;
2010-04-02 07:30:58 +02:00
if ( _callStack . size ( ) > = stackSize )
2009-02-19 23:21:18 +01:00
break ;
}
return true ;
}
2010-12-22 10:29:23 +01:00
std : : string ErrorLogger : : ErrorMessage : : getXMLHeader ( int xml_version )
2009-06-15 20:36:39 +02:00
{
2010-12-30 22:07:27 +01:00
// xml_version 1 is the default xml format
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 ) ;
2010-12-30 22:07:27 +01:00
// version 2 header
2013-08-07 16:30:55 +02:00
if ( xml_version = = 2 ) {
printer . PushAttribute ( " version " , xml_version ) ;
2014-03-01 11:15:08 +01:00
printer . OpenElement ( " cppcheck " , false ) ;
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " version " , CppCheck : : version ( ) ) ;
2014-03-01 11:15:08 +01:00
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
}
2011-02-02 18:46:07 +01:00
std : : string ErrorLogger : : ErrorMessage : : getXMLFooter ( int xml_version )
2009-06-15 20:36:39 +02:00
{
2013-08-07 16:30:55 +02:00
return ( xml_version < = 1 ) ? " </results> " : " </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 "
std : : string ErrorLogger : : 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 ;
}
2010-12-02 17:32:51 +01:00
std : : string ErrorLogger : : ErrorMessage : : toXML ( bool verbose , int version ) const
2009-02-10 22:51:52 +01:00
{
2010-12-30 22:07:27 +01:00
// The default xml format
2011-10-13 20:53:06 +02:00
if ( version = = 1 ) {
2011-04-10 21:51:27 +02:00
// No inconclusive messages in the xml version 1
2011-04-14 18:02:01 +02:00
if ( _inconclusive )
2011-04-10 21:51:27 +02:00
return " " ;
2013-08-07 16:30:55 +02:00
tinyxml2 : : XMLPrinter printer ( 0 , false , 1 ) ;
2014-03-01 11:15:08 +01:00
printer . OpenElement ( " error " , false ) ;
2011-10-13 20:53:06 +02:00
if ( ! _callStack . empty ( ) ) {
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " file " , _callStack . back ( ) . getfile ( ) . c_str ( ) ) ;
printer . PushAttribute ( " line " , _callStack . back ( ) . line ) ;
2010-12-01 21:24:17 +01:00
}
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " id " , _id . c_str ( ) ) ;
printer . PushAttribute ( " severity " , ( _severity = = Severity : : error ? " error " : " style " ) ) ;
2016-02-01 18:53:46 +01:00
printer . PushAttribute ( " msg " , fixInvalidChars ( verbose ? _verboseMessage : _shortMessage ) . c_str ( ) ) ;
2014-03-01 11:15:08 +01:00
printer . CloseElement ( false ) ;
2013-08-07 16:30:55 +02:00
return printer . CStr ( ) ;
2010-12-01 21:24:17 +01:00
}
2010-12-30 22:07:27 +01:00
// The xml format you get when you use --xml-version=2
2011-10-13 20:53:06 +02:00
else if ( version = = 2 ) {
2013-08-07 16:30:55 +02:00
tinyxml2 : : XMLPrinter printer ( 0 , false , 2 ) ;
2014-03-01 11:15:08 +01:00
printer . OpenElement ( " error " , false ) ;
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " id " , _id . c_str ( ) ) ;
printer . PushAttribute ( " severity " , Severity : : toString ( _severity ) . c_str ( ) ) ;
2015-06-18 21:16:25 +02:00
printer . PushAttribute ( " msg " , fixInvalidChars ( _shortMessage ) . c_str ( ) ) ;
2014-04-13 09:50:57 +02:00
printer . PushAttribute ( " verbose " , fixInvalidChars ( _verboseMessage ) . c_str ( ) ) ;
2016-02-27 16:03:50 +01:00
if ( _cwe . id )
printer . PushAttribute ( " cwe " , _cwe . id ) ;
2012-03-25 11:59:30 +02:00
if ( _inconclusive )
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " inconclusive " , " true " ) ;
2010-12-01 21:24:17 +01:00
2011-10-13 20:53:06 +02:00
for ( std : : list < FileLocation > : : const_reverse_iterator it = _callStack . rbegin ( ) ; it ! = _callStack . rend ( ) ; + + it ) {
2014-03-01 11:15:08 +01:00
printer . OpenElement ( " location " , false ) ;
2016-01-19 07:01:21 +01:00
if ( ! file0 . empty ( ) & & ( * it ) . getfile ( ) ! = file0 )
2016-01-15 16:52:22 +01:00
printer . PushAttribute ( " file0 " , Path : : toNativeSeparators ( file0 ) . c_str ( ) ) ;
2013-08-07 16:30:55 +02:00
printer . PushAttribute ( " file " , ( * it ) . getfile ( ) . c_str ( ) ) ;
printer . PushAttribute ( " line " , ( * it ) . line ) ;
2014-03-01 11:15:08 +01:00
printer . CloseElement ( false ) ;
2010-12-01 21:24:17 +01:00
}
2014-03-01 11:15:08 +01:00
printer . CloseElement ( false ) ;
2013-08-07 16:30:55 +02:00
return printer . CStr ( ) ;
2009-04-23 21:59:26 +02:00
}
2010-12-01 21:24:17 +01:00
2013-08-07 16:30:55 +02:00
return " " ;
2009-02-10 22:51:52 +01:00
}
2009-09-05 21:01:49 +02:00
void ErrorLogger : : 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
}
}
2010-11-11 19:54:43 +01:00
std : : string ErrorLogger : : ErrorMessage : : toString ( bool verbose , const std : : string & outputFormat ) 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
2011-10-13 20:53:06 +02:00
if ( outputFormat . length ( ) = = 0 ) {
2009-09-05 21:01:49 +02:00
std : : ostringstream text ;
2010-04-02 07:30:58 +02:00
if ( ! _callStack . empty ( ) )
2009-09-05 21:01:49 +02:00
text < < callStackToString ( _callStack ) < < " : " ;
2012-05-06 19:37:41 +02:00
if ( _severity ! = Severity : : none ) {
text < < ' ( ' < < Severity : : toString ( _severity ) ;
if ( _inconclusive )
text < < " , inconclusive " ;
text < < " ) " ;
}
2010-11-11 19:54:43 +01:00
text < < ( verbose ? _verboseMessage : _shortMessage ) ;
2009-09-05 21:01:49 +02:00
return text . str ( ) ;
}
2010-12-30 22:07:27 +01:00
// template is given. Reformat the output according to it
2011-10-13 20:53:06 +02:00
else {
2009-09-05 21:01:49 +02:00
std : : string result = outputFormat ;
2013-03-02 15:48:22 +01:00
// 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 " ) ;
2013-03-02 15:16:18 +01:00
2009-09-05 21:01:49 +02:00
findAndReplace ( result , " {id} " , _id ) ;
2010-07-14 18:36:34 +02:00
findAndReplace ( result , " {severity} " , Severity : : toString ( _severity ) ) ;
2010-11-11 19:54:43 +01:00
findAndReplace ( result , " {message} " , verbose ? _verboseMessage : _shortMessage ) ;
2017-03-01 10:50:50 +01:00
findAndReplace ( result , " {callstack} " , _callStack . empty ( ) ? emptyString : callStackToString ( _callStack ) ) ;
2011-10-13 20:53:06 +02:00
if ( ! _callStack . empty ( ) ) {
2009-09-05 21:01:49 +02:00
std : : ostringstream oss ;
oss < < _callStack . back ( ) . line ;
findAndReplace ( result , " {line} " , oss . str ( ) ) ;
findAndReplace ( result , " {file} " , _callStack . back ( ) . getfile ( ) ) ;
2011-10-13 20:53:06 +02:00
} else {
2017-03-01 10:50:50 +01:00
findAndReplace ( result , " {file} " , emptyString ) ;
findAndReplace ( result , " {line} " , emptyString ) ;
2009-09-05 21:01:49 +02:00
}
return result ;
}
2009-02-10 22:51:52 +01:00
}
2011-08-22 18:54:23 +02:00
void ErrorLogger : : reportUnmatchedSuppressions ( const std : : list < Suppressions : : SuppressionEntry > & unmatched )
2011-02-16 02:12:15 +01:00
{
2012-07-13 08:29:49 +02:00
// Report unmatched suppressions
2011-10-13 20:53:06 +02:00
for ( std : : list < Suppressions : : SuppressionEntry > : : const_iterator i = unmatched . begin ( ) ; i ! = unmatched . end ( ) ; + + i ) {
2012-07-13 08:29:49 +02:00
// don't report "unmatchedSuppression" as unmatched
if ( i - > id = = " unmatchedSuppression " )
continue ;
// check if this unmatched suppression is suppressed
bool suppressed = false ;
for ( std : : list < Suppressions : : SuppressionEntry > : : const_iterator i2 = unmatched . begin ( ) ; i2 ! = unmatched . end ( ) ; + + i2 ) {
if ( i2 - > id = = " unmatchedSuppression " ) {
if ( ( i2 - > file = = " * " | | i2 - > file = = i - > file ) & &
2015-08-06 16:10:43 +02:00
( i2 - > line = = 0 | | i2 - > line = = i - > line ) ) {
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 ;
2016-02-27 16:03:50 +01:00
const std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callStack = make_container < std : : list < ErrorLogger : : ErrorMessage : : FileLocation > > ( )
< < ErrorLogger : : ErrorMessage : : FileLocation ( i - > file , i - > line ) ;
2016-07-26 16:27:55 +02:00
reportErr ( ErrorLogger : : ErrorMessage ( callStack , emptyString , Severity : : information , " Unmatched suppression: " + i - > id , " unmatchedSuppression " , false ) ) ;
2011-02-16 02:12:15 +01:00
}
}
2009-07-10 22:38:26 +02:00
std : : string ErrorLogger : : callStackToString ( const std : : list < ErrorLogger : : ErrorMessage : : FileLocation > & callStack )
2009-02-09 21:51:04 +01:00
{
std : : ostringstream ostr ;
2011-10-13 20:53:06 +02:00
for ( std : : list < ErrorLogger : : 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
2012-05-06 10:17:15 +02:00
ErrorLogger : : ErrorMessage : : FileLocation : : FileLocation ( const Token * tok , const TokenList * list )
: line ( tok - > linenr ( ) ) , _file ( list - > file ( tok ) )
{
}
2010-07-18 10:20:10 +02:00
std : : string ErrorLogger : : ErrorMessage : : FileLocation : : getfile ( bool convert ) const
2009-05-31 10:12:19 +02:00
{
2010-07-18 10:20:10 +02:00
if ( convert )
2012-02-18 14:44:04 +01:00
return Path : : toNativeSeparators ( _file ) ;
return _file ;
2009-05-31 10:12:19 +02:00
}
2010-07-17 00:27:40 +02:00
void ErrorLogger : : ErrorMessage : : FileLocation : : setfile ( const std : : string & file )
{
_file = file ;
2010-07-17 16:38:36 +02:00
_file = Path : : fromNativeSeparators ( _file ) ;
2014-04-02 13:56:34 +02:00
_file = Path : : simplifyPath ( _file ) ;
2010-07-17 00:27:40 +02:00
}
2012-05-06 10:17:15 +02:00
std : : string ErrorLogger : : ErrorMessage : : FileLocation : : stringify ( ) const
{
std : : ostringstream oss ;
oss < < ' [ ' < < Path : : toNativeSeparators ( _file ) ;
if ( line ! = 0 )
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 ;
const bool isstring ( str [ 0 ] = = ' \" ' ) ;
for ( std : : size_t i = 0U ; i < str . length ( ) ; i + + ) {
char c = str [ i ] ;
switch ( c ) {
case ' < ' :
xml < < " < " ;
break ;
case ' > ' :
xml < < " > " ;
break ;
case ' & ' :
xml < < " & " ;
break ;
case ' \" ' :
xml < < " " " ;
break ;
case ' \0 ' :
xml < < " \\ 0 " ;
break ;
default :
if ( ! isstring | | ( c > = ' ' & & c < = ' z ' ) )
xml < < c ;
else
xml < < ' x ' ;
break ;
}
}
return xml . str ( ) ;
}