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
2014-02-15 07:45:39 +01:00
* Copyright ( C ) 2007 - 2014 Daniel Marjamäki and 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"
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>
2009-02-01 16:47:36 +01:00
# include <sstream>
2010-07-31 08:52:28 +02:00
# include <vector>
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 ( )
2012-02-18 14:44:04 +01:00
: _severity ( Severity : : none ) , _inconclusive ( false )
2009-02-19 23:21:18 +01:00
{
}
2010-07-27 09:32:20 +02:00
2012-04-06 18:16:59 +02:00
ErrorLogger : : ErrorMessage : : ErrorMessage ( const std : : list < FileLocation > & callStack , Severity : : SeverityType severity , const std : : string & msg , const std : : string & id , bool inconclusive ) :
_callStack ( callStack ) , // locations for this error message
_id ( id ) , // set the message id
2012-05-14 20:46:23 +02:00
_severity ( severity ) , // severity for this error message
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
}
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 )
2012-05-14 20:46:23 +02:00
: _id ( id ) , _severity ( severity ) , _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 ) ) ;
}
if ( list & & ! list - > getFiles ( ) . empty ( ) )
file0 = list - > getFiles ( ) [ 0 ] ;
setmsg ( msg ) ;
}
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.
assert ( ! ( msg [ msg . size ( ) - 1 ] = = ' \n ' ) ) ;
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
2010-11-11 19:54:43 +01: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 ) ;
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 ;
}
2010-11-11 19:54:43 +01:00
oss < < _shortMessage . length ( ) < < " " < < _shortMessage ;
2010-12-24 11:13:57 +01:00
oss < < _verboseMessage . length ( ) < < " " < < _verboseMessage ;
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 ) ;
std : : vector < std : : string > results ;
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
}
2009-02-19 23:21:18 +01:00
results . push_back ( temp ) ;
2010-12-24 11:13:57 +01:00
if ( results . size ( ) = = 4 )
2009-02-19 23:21:18 +01:00
break ;
}
_id = results [ 0 ] ;
2010-07-14 18:36:34 +02:00
_severity = Severity : : fromString ( results [ 1 ] ) ;
2010-11-11 19:54:43 +01:00
_shortMessage = results [ 2 ] ;
2010-12-24 11:13:57 +01:00
_verboseMessage = results [ 3 ] ;
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 ) {
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
ErrorLogger : : ErrorMessage : : FileLocation loc ;
2010-07-17 00:27:40 +02:00
loc . setfile ( temp . substr ( temp . find ( ' : ' ) + 1 ) ) ;
2009-02-19 23:21:18 +01:00
temp = temp . substr ( 0 , temp . find ( ' : ' ) ) ;
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
}
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 " ) ) ;
printer . PushAttribute ( " msg " , ( 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 ( ) ) ;
printer . PushAttribute ( " msg " , _shortMessage . c_str ( ) ) ;
printer . PushAttribute ( " verbose " , _verboseMessage . c_str ( ) ) ;
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 ) ;
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 ) ;
index + = replaceWith . length ( ) - searchFor . length ( ) + 1 ;
}
}
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 ) ;
2013-07-08 06:44:25 +02:00
findAndReplace ( result , " {callstack} " , _callStack . empty ( ) ? " " : 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 {
2009-09-05 21:01:49 +02:00
findAndReplace ( result , " {file} " , " " ) ;
findAndReplace ( result , " {line} " , " " ) ;
}
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 ) & &
( i2 - > line = = 0 | | i2 - > line = = i - > line ) )
suppressed = true ;
}
}
if ( suppressed )
continue ;
2011-02-16 02:12:15 +01:00
std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callStack ;
callStack . push_back ( ErrorLogger : : ErrorMessage : : FileLocation ( i - > file , i - > line ) ) ;
2011-04-14 18:02:01 +02:00
reportErr ( ErrorLogger : : ErrorMessage ( callStack , 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 ) ;
2012-02-18 14:44:04 +01:00
_file = Path : : simplifyPath ( _file . c_str ( ) ) ;
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 ( ) ;
}