2011-05-03 12:18:05 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2020-05-10 11:16:32 +02:00
* Copyright ( C ) 2007 - 2020 Cppcheck team .
2011-05-03 12:18:05 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2017-05-27 04:33:47 +02:00
# include "config.h"
2011-05-03 12:18:05 +02:00
# include "cppcheck.h"
# include "settings.h"
2017-05-27 04:33:47 +02:00
# include "suppressions.h"
2011-05-03 12:18:05 +02:00
# include "testsuite.h"
# include "threadexecutor.h"
2017-05-27 04:33:47 +02:00
# include <cstddef>
# include <list>
2015-01-07 19:26:16 +01:00
# include <map>
2017-05-27 04:33:47 +02:00
# include <string>
# include <utility>
# include <vector>
2011-05-03 12:18:05 +02:00
2011-10-13 20:53:06 +02:00
class TestSuppressions : public TestFixture {
2011-05-03 12:18:05 +02:00
public :
2014-11-20 14:20:09 +01:00
TestSuppressions ( ) : TestFixture ( " TestSuppressions " ) {
2013-08-07 16:27:37 +02:00
}
2011-05-03 12:18:05 +02:00
private :
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2011-08-22 18:54:23 +02:00
TEST_CASE ( suppressionsBadId1 ) ;
TEST_CASE ( suppressionsDosFormat ) ; // Ticket #1836
TEST_CASE ( suppressionsFileNameWithColon ) ; // Ticket #1919 - filename includes colon
TEST_CASE ( suppressionsGlob ) ;
TEST_CASE ( suppressionsFileNameWithExtraPath ) ;
2011-05-03 12:18:05 +02:00
TEST_CASE ( suppressionsSettings ) ;
TEST_CASE ( suppressionsMultiFile ) ;
2013-03-12 15:53:18 +01:00
TEST_CASE ( suppressionsPathSeparator ) ;
2018-09-18 12:58:14 +02:00
TEST_CASE ( suppressionsLine0 ) ;
2019-01-12 15:21:47 +01:00
TEST_CASE ( suppressionsFileComment ) ;
2012-09-23 10:56:12 +02:00
2018-04-11 08:18:00 +02:00
TEST_CASE ( inlinesuppress ) ;
2018-04-09 11:50:59 +02:00
TEST_CASE ( inlinesuppress_symbolname ) ;
2018-06-09 22:50:51 +02:00
TEST_CASE ( inlinesuppress_comment ) ;
2018-04-09 11:50:59 +02:00
2020-02-23 18:04:24 +01:00
TEST_CASE ( multi_inlinesuppress ) ;
TEST_CASE ( multi_inlinesuppress_comment ) ;
2018-05-11 09:01:08 +02:00
TEST_CASE ( globalSuppressions ) ; // Testing that global suppressions work (#8515)
2012-09-23 10:56:12 +02:00
TEST_CASE ( inlinesuppress_unusedFunction ) ; // #4210 - unusedFunction
2014-09-01 10:13:03 +02:00
TEST_CASE ( globalsuppress_unusedFunction ) ; // #4946
2013-08-28 06:46:32 +02:00
TEST_CASE ( suppressionWithRelativePaths ) ; // #4733
2015-10-28 19:27:05 +01:00
TEST_CASE ( suppressingSyntaxErrors ) ; // #7076
TEST_CASE ( suppressingSyntaxErrorsInline ) ; // #5917
2020-04-21 17:27:51 +02:00
TEST_CASE ( suppressingSyntaxErrorsWhileFileRead ) ; // PR #1333
2018-04-09 06:43:48 +02:00
TEST_CASE ( symbol ) ;
2018-02-06 08:59:36 +01:00
TEST_CASE ( unusedFunction ) ;
2018-04-09 06:43:48 +02:00
2018-09-08 11:09:49 +02:00
TEST_CASE ( suppressingSyntaxErrorAndExitCode ) ;
2011-05-03 12:18:05 +02:00
}
2014-11-20 14:20:09 +01:00
void suppressionsBadId1 ( ) const {
2011-08-22 18:54:23 +02:00
Suppressions suppressions ;
2012-07-06 18:16:43 +02:00
std : : istringstream s1 ( " 123 " ) ;
ASSERT_EQUALS ( " Failed to add suppression. Invalid id \" 123 \" " , suppressions . parseFile ( s1 ) ) ;
std : : istringstream s2 ( " obsoleteFunctionsrand_r " ) ;
ASSERT_EQUALS ( " " , suppressions . parseFile ( s2 ) ) ;
2011-08-22 18:54:23 +02:00
}
2018-04-09 06:43:48 +02:00
Suppressions : : ErrorMessage errorMessage ( const std : : string & errorId ) const {
Suppressions : : ErrorMessage ret ;
ret . errorId = errorId ;
return ret ;
}
Suppressions : : ErrorMessage errorMessage ( const std : : string & errorId , const std : : string & file , int line ) const {
Suppressions : : ErrorMessage ret ;
ret . errorId = errorId ;
ret . setFileName ( file ) ;
ret . lineNumber = line ;
return ret ;
}
2014-11-20 14:20:09 +01:00
void suppressionsDosFormat ( ) const {
2011-08-22 18:54:23 +02:00
Suppressions suppressions ;
std : : istringstream s ( " abc \r \n def \r \n " ) ;
ASSERT_EQUALS ( " " , suppressions . parseFile ( s ) ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " abc " ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " def " ) ) ) ;
2011-08-22 18:54:23 +02:00
}
2014-11-20 14:20:09 +01:00
void suppressionsFileNameWithColon ( ) const {
2011-08-22 18:54:23 +02:00
Suppressions suppressions ;
std : : istringstream s ( " errorid:c: \\ foo.cpp \n errorid:c: \\ bar.cpp:12 " ) ;
ASSERT_EQUALS ( " " , suppressions . parseFile ( s ) ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " c:/foo.cpp " , 1111 ) ) ) ;
ASSERT_EQUALS ( false , suppressions . isSuppressed ( errorMessage ( " errorid " , " c:/bar.cpp " , 10 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " c:/bar.cpp " , 12 ) ) ) ;
2011-08-22 18:54:23 +02:00
}
2014-11-20 14:20:09 +01:00
void suppressionsGlob ( ) const {
2011-08-22 18:54:23 +02:00
// Check for syntax errors in glob
{
Suppressions suppressions ;
std : : istringstream s ( " errorid:**.cpp \n " ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( " Failed to add suppression. Invalid glob pattern '**.cpp'. " , suppressions . parseFile ( s ) ) ;
2011-08-22 18:54:23 +02:00
}
// Check that globbing works
{
Suppressions suppressions ;
std : : istringstream s ( " errorid:x*.cpp \n errorid:y?.cpp \n errorid:test.c* " ) ;
ASSERT_EQUALS ( " " , suppressions . parseFile ( s ) ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " xyz.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " xyz.cpp.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( false , suppressions . isSuppressed ( errorMessage ( " errorid " , " abc.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " ya.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( false , suppressions . isSuppressed ( errorMessage ( " errorid " , " y.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " test.c " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " test.cpp " , 1 ) ) ) ;
2011-08-22 18:54:23 +02:00
}
// Check that both a filename match and a glob match apply
{
Suppressions suppressions ;
std : : istringstream s ( " errorid:x*.cpp \n errorid:xyz.cpp:1 \n errorid:a*.cpp:1 \n errorid:abc.cpp:2 " ) ;
ASSERT_EQUALS ( " " , suppressions . parseFile ( s ) ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " xyz.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " xyz.cpp " , 2 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " abc.cpp " , 1 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " abc.cpp " , 2 ) ) ) ;
2011-08-22 18:54:23 +02:00
}
}
2014-11-20 14:20:09 +01:00
void suppressionsFileNameWithExtraPath ( ) const {
2011-08-22 18:54:23 +02:00
// Ticket #2797
Suppressions suppressions ;
2018-04-09 06:43:48 +02:00
suppressions . addSuppressionLine ( " errorid:./a.c:123 " ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " a.c " , 123 ) ) ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " errorid " , " x/../a.c " , 123 ) ) ) ;
2011-08-22 18:54:23 +02:00
}
2015-01-07 19:26:16 +01:00
void reportSuppressions ( const Settings & settings , const std : : map < std : : string , std : : string > & files ) {
// make it verbose that this check is disabled
const bool unusedFunctionCheck = false ;
if ( settings . jointSuppressionReport ) {
for ( std : : map < std : : string , std : : string > : : const_iterator i = files . begin ( ) ; i ! = files . end ( ) ; + + i ) {
reportUnmatchedSuppressions ( settings . nomsg . getUnmatchedLocalSuppressions ( i - > first , unusedFunctionCheck ) ) ;
}
}
reportUnmatchedSuppressions ( settings . nomsg . getUnmatchedGlobalSuppressions ( unusedFunctionCheck ) ) ;
}
2011-05-03 12:18:05 +02:00
// Check the suppression
2016-05-27 20:13:51 +02:00
unsigned int checkSuppression ( const char code [ ] , const std : : string & suppression = emptyString ) {
2015-01-07 19:26:16 +01:00
std : : map < std : : string , std : : string > files ;
files [ " test.cpp " ] = code ;
2016-05-27 20:13:51 +02:00
return checkSuppression ( files , suppression ) ;
2015-01-07 19:26:16 +01:00
}
// Check the suppression for multiple files
2016-05-27 20:13:51 +02:00
unsigned int checkSuppression ( std : : map < std : : string , std : : string > & files , const std : : string & suppression = emptyString ) {
2011-05-03 12:18:05 +02:00
// Clear the error log
errout . str ( " " ) ;
2012-04-06 14:19:26 +02:00
CppCheck cppCheck ( * this , true ) ;
Settings & settings = cppCheck . settings ( ) ;
2018-02-06 08:59:36 +01:00
settings . exitCode = 1 ;
2016-01-03 16:18:17 +01:00
settings . inlineSuppressions = true ;
2018-02-06 08:59:36 +01:00
if ( suppression = = " unusedFunction " )
settings . addEnabled ( " unusedFunction " ) ;
2013-05-31 15:20:58 +02:00
settings . addEnabled ( " information " ) ;
2015-01-07 19:26:16 +01:00
settings . jointSuppressionReport = true ;
2011-10-13 20:53:06 +02:00
if ( ! suppression . empty ( ) ) {
2011-05-03 12:18:05 +02:00
std : : string r = settings . nomsg . addSuppressionLine ( suppression ) ;
2019-09-16 06:34:45 +02:00
EXPECT_EQ ( " " , r ) ;
2011-05-03 12:18:05 +02:00
}
2016-05-27 20:13:51 +02:00
unsigned int exitCode = 0 ;
2015-01-07 19:26:16 +01:00
for ( std : : map < std : : string , std : : string > : : const_iterator file = files . begin ( ) ; file ! = files . end ( ) ; + + file ) {
2016-05-27 20:13:51 +02:00
exitCode | = cppCheck . check ( file - > first , file - > second ) ;
2015-01-07 19:26:16 +01:00
}
2018-01-12 08:24:01 +01:00
if ( cppCheck . analyseWholeProgram ( ) )
exitCode | = settings . exitCode ;
2011-05-03 12:18:05 +02:00
2015-01-07 19:26:16 +01:00
reportSuppressions ( settings , files ) ;
2016-05-27 20:13:51 +02:00
return exitCode ;
2011-05-03 12:18:05 +02:00
}
2016-05-27 20:13:51 +02:00
unsigned int checkSuppressionThreads ( const char code [ ] , const std : : string & suppression = emptyString ) {
2011-05-03 12:18:05 +02:00
errout . str ( " " ) ;
output . str ( " " ) ;
2012-07-08 23:39:46 +02:00
std : : map < std : : string , std : : size_t > files ;
2012-02-19 17:22:59 +01:00
files [ " test.cpp " ] = 1 ;
2011-05-03 12:18:05 +02:00
Settings settings ;
2016-01-03 16:18:17 +01:00
settings . jobs = 1 ;
settings . inlineSuppressions = true ;
2013-05-31 15:20:58 +02:00
settings . addEnabled ( " information " ) ;
2011-10-13 20:53:06 +02:00
if ( ! suppression . empty ( ) ) {
2019-09-16 06:34:45 +02:00
EXPECT_EQ ( " " , settings . nomsg . addSuppressionLine ( suppression ) ) ;
2011-05-03 12:18:05 +02:00
}
2012-02-19 17:22:59 +01:00
ThreadExecutor executor ( files , settings , * this ) ;
2012-07-08 23:39:46 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = files . begin ( ) ; i ! = files . end ( ) ; + + i )
2012-02-19 17:22:59 +01:00
executor . addFileContent ( i - > first , code ) ;
2011-05-03 12:18:05 +02:00
2018-09-24 15:08:16 +02:00
const unsigned int exitCode = executor . check ( ) ;
2011-05-03 12:18:05 +02:00
2015-01-07 19:26:16 +01:00
std : : map < std : : string , std : : string > files_for_report ;
for ( std : : map < std : : string , std : : size_t > : : const_iterator file = files . begin ( ) ; file ! = files . end ( ) ; + + file )
files_for_report [ file - > first ] = " " ;
2011-05-03 12:18:05 +02:00
2015-01-07 19:26:16 +01:00
reportSuppressions ( settings , files_for_report ) ;
2016-05-27 20:13:51 +02:00
return exitCode ;
2011-05-03 12:18:05 +02:00
}
2016-05-27 20:13:51 +02:00
void runChecks ( unsigned int ( TestSuppressions : : * check ) ( const char [ ] , const std : : string & ) ) {
2011-05-03 12:18:05 +02:00
// check to make sure the appropriate error is present
( this - > * check ) ( " void f() { \n "
2011-11-30 18:57:52 +01:00
" int a; \n "
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
2011-11-30 18:57:52 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Uninitialized variable: a \n " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar globally
( this - > * check ) ( " void f() { \n "
2011-11-30 18:57:52 +01:00
" int a; \n "
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar " ) ;
2011-05-03 12:18:05 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar globally, without error present
( this - > * check ) ( " void f() { \n "
" int a; \n "
" b++; \n "
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar " ) ;
2018-04-09 06:43:48 +02:00
ASSERT_EQUALS ( " (information) Unmatched suppression: uninitvar \n " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar for this file only
( this - > * check ) ( " void f() { \n "
2011-11-30 18:57:52 +01:00
" int a; \n "
2011-05-03 12:18:05 +02:00
" a++; \n "
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar:test.cpp " ) ;
2011-05-03 12:18:05 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar for this file only, without error present
( this - > * check ) ( " void f() { \n "
" int a; \n "
" b++; \n "
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar:test.cpp " ) ;
ASSERT_EQUALS ( " [test.cpp]: (information) Unmatched suppression: uninitvar \n " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress all for this file only
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" *:test.cpp " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress all for this file only, without error present
( this - > * check ) ( " void f() { \n "
" int a; \n "
" b++; \n "
" } \n " ,
" *:test.cpp " ) ;
ASSERT_EQUALS ( " [test.cpp]: (information) Unmatched suppression: * \n " , errout . str ( ) ) ;
// suppress uninitvar for this file and line
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar:test.cpp:3 " ) ;
2011-05-03 12:18:05 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar for this file and line, without error present
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" b++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
2011-11-30 18:57:52 +01:00
" uninitvar:test.cpp:3 " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (information) Unmatched suppression: uninitvar \n " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" // cppcheck-suppress uninitvar \n "
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" // cppcheck-suppress uninitvar \n "
2011-05-03 12:18:05 +02:00
" \n "
2011-11-30 18:57:52 +01:00
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-02-23 18:04:24 +01:00
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" a++;// cppcheck-suppress uninitvar \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" /* cppcheck-suppress uninitvar */ \n "
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" /* cppcheck-suppress uninitvar */ \n "
2011-05-03 12:18:05 +02:00
" \n "
2011-11-30 18:57:52 +01:00
" a++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2020-02-23 18:04:24 +01:00
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" a++;/* cppcheck-suppress uninitvar */ \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" // cppcheck-suppress[uninitvar] \n "
" a++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" // cppcheck-suppress[uninitvar] \n "
" a++; \n "
" \n "
" a++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" a++;// cppcheck-suppress[uninitvar] \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" /* cppcheck-suppress[uninitvar]*/ \n "
" a++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" /* cppcheck-suppress[uninitvar]*/ \n "
" \n "
" a++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// suppress uninitvar inline
( this - > * check ) ( " void f() { \n "
" int a; \n "
" a++;/* cppcheck-suppress[uninitvar]*/ \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-07-20 22:51:06 +02:00
// suppress uninitvar inline, with asm before (#6813)
( this - > * check ) ( " void f() { \n "
" __asm { \n "
" foo \n "
" } "
" int a; \n "
" // cppcheck-suppress uninitvar \n "
" a++; \n "
" } " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar inline, without error present
( this - > * check ) ( " void f() { \n "
" int a; \n "
2011-11-30 18:57:52 +01:00
" // cppcheck-suppress uninitvar \n "
" b++; \n "
2011-05-03 12:18:05 +02:00
" } \n " ,
" " ) ;
2011-11-30 18:57:52 +01:00
ASSERT_EQUALS ( " [test.cpp:4]: (information) Unmatched suppression: uninitvar \n " , errout . str ( ) ) ;
2016-05-27 20:13:51 +02:00
// #5746 - exitcode
ASSERT_EQUALS ( 1U ,
( this - > * check ) ( " int f() { \n "
" int a; return a; \n "
" } \n " ,
" " ) ) ;
ASSERT_EQUALS ( 0U ,
( this - > * check ) ( " int f() { \n "
" int a; return a; \n "
" } \n " ,
" uninitvar " ) ) ;
2011-05-03 12:18:05 +02:00
}
2014-11-20 14:20:09 +01:00
void suppressionsSettings ( ) {
2011-05-03 12:18:05 +02:00
runChecks ( & TestSuppressions : : checkSuppression ) ;
2011-05-03 12:41:52 +02:00
if ( ThreadExecutor : : isEnabled ( ) )
runChecks ( & TestSuppressions : : checkSuppressionThreads ) ;
2011-05-03 12:18:05 +02:00
}
2014-11-20 14:20:09 +01:00
void suppressionsMultiFile ( ) {
2015-01-07 19:26:16 +01:00
std : : map < std : : string , std : : string > files ;
files [ " abc.cpp " ] = " void f() { \n "
" } \n " ;
files [ " xyz.cpp " ] = " void f() { \n "
" int a; \n "
" a++; \n "
" } \n " ;
2011-05-03 12:18:05 +02:00
// suppress uninitvar for this file and line
2015-01-07 19:26:16 +01:00
checkSuppression ( files , " uninitvar:xyz.cpp:3 " ) ;
2011-05-03 12:18:05 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void suppressionsPathSeparator ( ) const {
2018-04-09 06:43:48 +02:00
const Suppressions : : Suppression s1 ( " * " , " test/foo/* " ) ;
ASSERT_EQUALS ( true , s1 . isSuppressed ( errorMessage ( " someid " , " test/foo/bar.cpp " , 142 ) ) ) ;
2016-05-23 15:38:47 +02:00
2018-04-09 06:43:48 +02:00
const Suppressions : : Suppression s2 ( " abc " , " include/1.h " ) ;
ASSERT_EQUALS ( true , s2 . isSuppressed ( errorMessage ( " abc " , " include/1.h " , 142 ) ) ) ;
2013-03-12 15:53:18 +01:00
}
2018-09-18 12:58:14 +02:00
void suppressionsLine0 ( ) {
Suppressions suppressions ;
suppressions . addSuppressionLine ( " syntaxError:*:0 " ) ;
ASSERT_EQUALS ( true , suppressions . isSuppressed ( errorMessage ( " syntaxError " , " test.cpp " , 0 ) ) ) ;
}
2019-01-12 15:21:47 +01:00
void suppressionsFileComment ( ) {
std : : istringstream file1 ( " # comment \n abc " ) ;
Suppressions suppressions1 ;
suppressions1 . parseFile ( file1 ) ;
ASSERT_EQUALS ( true , suppressions1 . isSuppressed ( errorMessage ( " abc " , " test.cpp " , 123 ) ) ) ;
std : : istringstream file2 ( " // comment \n abc " ) ;
Suppressions suppressions2 ;
suppressions2 . parseFile ( file2 ) ;
ASSERT_EQUALS ( true , suppressions2 . isSuppressed ( errorMessage ( " abc " , " test.cpp " , 123 ) ) ) ;
}
2018-04-11 08:18:00 +02:00
void inlinesuppress ( ) {
Suppressions : : Suppression s ;
2018-05-29 11:54:07 +02:00
std : : string msg ;
ASSERT_EQUALS ( false , s . parseComment ( " /* some text */ " , & msg ) ) ;
ASSERT_EQUALS ( false , s . parseComment ( " /* cppcheck-suppress */ " , & msg ) ) ;
2018-04-11 08:18:00 +02:00
2018-05-29 11:54:07 +02:00
msg . clear ( ) ;
ASSERT_EQUALS ( true , s . parseComment ( " /* cppcheck-suppress id */ " , & msg ) ) ;
ASSERT_EQUALS ( " " , msg ) ;
2018-04-11 08:18:00 +02:00
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( true , s . parseComment ( " /* cppcheck-suppress id some text */ " , & msg ) ) ;
ASSERT_EQUALS ( " Bad suppression attribute 'some'. You can write comments in the comment after a ; or //. Valid suppression attributes; symbolName=sym " , msg ) ;
2018-04-11 08:18:00 +02:00
}
2018-04-09 11:50:59 +02:00
void inlinesuppress_symbolname ( ) {
Suppressions suppressions ;
checkSuppression ( " void f() { \n "
" int a; \n "
" /* cppcheck-suppress uninitvar symbolName=a */ \n "
" a++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
checkSuppression ( " void f() { \n "
" int a,b; \n "
" /* cppcheck-suppress uninitvar symbolName=b */ \n "
" a++; b++; \n "
" } \n " ,
" " ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Uninitialized variable: a \n " , errout . str ( ) ) ;
}
2018-06-09 22:50:51 +02:00
void inlinesuppress_comment ( ) {
Suppressions : : Suppression s ;
2018-09-25 17:19:25 +02:00
std : : string errMsg ;
ASSERT_EQUALS ( true , s . parseComment ( " // cppcheck-suppress abc ; some comment " , & errMsg ) ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
ASSERT_EQUALS ( true , s . parseComment ( " // cppcheck-suppress abc // some comment " , & errMsg ) ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
ASSERT_EQUALS ( true , s . parseComment ( " // cppcheck-suppress abc -- some comment " , & errMsg ) ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
2018-06-09 22:50:51 +02:00
}
2020-02-23 18:04:24 +01:00
void multi_inlinesuppress ( ) {
Suppressions ss ;
std : : vector < Suppressions : : Suppression > suppressions ;
std : : string errMsg ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId] " , & errMsg ) ;
ASSERT_EQUALS ( 1 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( " errorId " , suppressions [ 0 ] . errorId ) ;
ASSERT_EQUALS ( " " , suppressions [ 0 ] . symbolName ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId symbolName=arr] " , & errMsg ) ;
ASSERT_EQUALS ( 1 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( " errorId " , suppressions [ 0 ] . errorId ) ;
ASSERT_EQUALS ( " arr " , suppressions [ 0 ] . symbolName ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId symbolName=] " , & errMsg ) ;
ASSERT_EQUALS ( 1 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( " errorId " , suppressions [ 0 ] . errorId ) ;
ASSERT_EQUALS ( " " , suppressions [ 0 ] . symbolName ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId1, errorId2 symbolName=arr] " , & errMsg ) ;
ASSERT_EQUALS ( 2 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( " errorId1 " , suppressions [ 0 ] . errorId ) ;
ASSERT_EQUALS ( " " , suppressions [ 0 ] . symbolName ) ;
ASSERT_EQUALS ( " errorId2 " , suppressions [ 1 ] . errorId ) ;
ASSERT_EQUALS ( " arr " , suppressions [ 1 ] . symbolName ) ;
ASSERT_EQUALS ( " " , errMsg ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[] " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
2020-02-23 19:49:53 +01:00
ASSERT_EQUALS ( true , errMsg . empty ( ) ) ;
2020-02-23 18:04:24 +01:00
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( false , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress errorId " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( false , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId1 errorId2 symbolName=arr] " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( false , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId1, errorId2 symbol=arr] " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( false , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " // cppcheck-suppress[errorId1, errorId2 symbolName] " , & errMsg ) ;
ASSERT_EQUALS ( 0 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( false , errMsg . empty ( ) ) ;
}
void multi_inlinesuppress_comment ( ) {
Suppressions ss ;
std : : vector < Suppressions : : Suppression > suppressions ;
std : : string errMsg ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " //cppcheck-suppress[errorId1, errorId2 symbolName=arr] " , & errMsg ) ;
ASSERT_EQUALS ( 2 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( true , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " //cppcheck-suppress[errorId1, errorId2 symbolName=arr] some text " , & errMsg ) ;
ASSERT_EQUALS ( 2 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( true , errMsg . empty ( ) ) ;
errMsg = " " ;
suppressions = ss . parseMultiSuppressComment ( " /*cppcheck-suppress[errorId1, errorId2 symbolName=arr]*/ " , & errMsg ) ;
ASSERT_EQUALS ( 2 , suppressions . size ( ) ) ;
ASSERT_EQUALS ( true , errMsg . empty ( ) ) ;
}
2018-05-11 09:01:08 +02:00
void globalSuppressions ( ) { // Testing that Cppcheck::useGlobalSuppressions works (#8515)
errout . str ( " " ) ;
CppCheck cppCheck ( * this , false ) ; // <- do not "use global suppressions". pretend this is a thread that just checks a file.
Settings & settings = cppCheck . settings ( ) ;
settings . nomsg . addSuppressionLine ( " uninitvar " ) ;
settings . exitCode = 1 ;
const char code [ ] = " int f() { int a; return a; } " ;
ASSERT_EQUALS ( 0 , cppCheck . check ( " test.c " , code ) ) ; // <- no unsuppressed error is seen
ASSERT_EQUALS ( " [test.c:1]: (error) Uninitialized variable: a \n " , errout . str ( ) ) ; // <- report error so ThreadExecutor can suppress it and make sure the global suppression is matched.
}
2014-11-20 14:20:09 +01:00
void inlinesuppress_unusedFunction ( ) const { // #4210, #4946 - wrong report of "unmatchedSuppression" for "unusedFunction"
2012-09-23 10:56:12 +02:00
Suppressions suppressions ;
2018-04-09 06:43:48 +02:00
suppressions . addSuppression ( Suppressions : : Suppression ( " unusedFunction " , " test.c " , 3 ) ) ;
2015-01-07 19:26:16 +01:00
ASSERT_EQUALS ( true , ! suppressions . getUnmatchedLocalSuppressions ( " test.c " , true ) . empty ( ) ) ;
2014-09-01 10:13:03 +02:00
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedGlobalSuppressions ( true ) . empty ( ) ) ;
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedLocalSuppressions ( " test.c " , false ) . empty ( ) ) ;
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedGlobalSuppressions ( false ) . empty ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void globalsuppress_unusedFunction ( ) const { // #4946 - wrong report of "unmatchedSuppression" for "unusedFunction"
2014-09-01 10:13:03 +02:00
Suppressions suppressions ;
suppressions . addSuppressionLine ( " unusedFunction:* " ) ;
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedLocalSuppressions ( " test.c " , true ) . empty ( ) ) ;
ASSERT_EQUALS ( true , ! suppressions . getUnmatchedGlobalSuppressions ( true ) . empty ( ) ) ;
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedLocalSuppressions ( " test.c " , false ) . empty ( ) ) ;
ASSERT_EQUALS ( false , ! suppressions . getUnmatchedGlobalSuppressions ( false ) . empty ( ) ) ;
2012-09-23 10:56:12 +02:00
}
2013-08-28 06:46:32 +02:00
2014-11-20 14:20:09 +01:00
void suppressionWithRelativePaths ( ) {
2013-08-28 06:46:32 +02:00
// Clear the error log
errout . str ( " " ) ;
CppCheck cppCheck ( * this , true ) ;
Settings & settings = cppCheck . settings ( ) ;
settings . addEnabled ( " style " ) ;
2016-01-03 16:18:17 +01:00
settings . inlineSuppressions = true ;
settings . relativePaths = true ;
2019-09-25 15:25:19 +02:00
settings . basePaths . emplace_back ( " /somewhere " ) ;
2013-08-28 06:46:32 +02:00
const char code [ ] =
" struct Point \n "
" { \n "
" // cppcheck-suppress unusedStructMember \n "
" int x; \n "
" // cppcheck-suppress unusedStructMember \n "
" int y; \n "
" }; " ;
cppCheck . check ( " /somewhere/test.cpp " , code ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2015-10-28 19:27:05 +01:00
2019-09-11 19:21:38 +02:00
void suppressingSyntaxErrors ( ) { // syntaxErrors should be suppressible (#7076)
2015-10-28 19:27:05 +01:00
std : : map < std : : string , std : : string > files ;
files [ " test.cpp " ] = " if if \n " ;
checkSuppression ( files , " syntaxError:test.cpp:1 " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-09-11 19:21:38 +02:00
void suppressingSyntaxErrorsInline ( ) { // syntaxErrors should be suppressible (#5917)
2015-10-28 19:27:05 +01:00
std : : map < std : : string , std : : string > files ;
files [ " test.cpp " ] = " double result(0.0); \n "
" _asm \n "
" { \n "
" // cppcheck-suppress syntaxError \n "
" push EAX ; save EAX for callers \n "
" mov EAX,Real10 ; get the address pointed to by Real10 \n "
" fld TBYTE PTR [EAX] ; load an extended real (10 bytes) \n "
" fstp QWORD PTR result ; store a double (8 bytes) \n "
" pop EAX ; restore EAX \n "
" } " ;
checkSuppression ( files , " " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-02-06 08:59:36 +01:00
2019-09-11 19:21:38 +02:00
void suppressingSyntaxErrorsWhileFileRead ( ) { // syntaxError while file read should be suppressible (PR #1333)
2018-08-17 10:05:25 +02:00
std : : map < std : : string , std : : string > files ;
files [ " test.cpp " ] = " CONST (genType, KS_CONST) genService[KS_CFG_NR_OF_NVM_BLOCKS] = \n "
" { \n "
" [!VAR \" BC \" = \" $BC + 1 \" !][!// \n "
" [!IF \" (as:modconf('Ks')[1]/KsGeneral/KsType = 'KS_CFG_TYPE_KS_MASTER') and \n "
" (as:modconf('Ks')[1]/KsGeneral/KsUseShe = 'true') \" !][!// \n "
" { \n "
" &varNB_GetErrorStatus, \n "
" &varNB_WriteBlock, \n "
" &varNB_ReadBlock \n "
" }, \n "
" [!VAR \" BC \" = \" $BC + 1 \" !][!// \n "
" [!ENDIF!][!// \n "
" }; " ;
checkSuppression ( files , " syntaxError:test.cpp:4 " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-04-09 06:43:48 +02:00
void symbol ( ) {
Suppressions : : Suppression s ;
s . errorId = " foo " ;
s . symbolName = " array* " ;
2018-05-29 11:54:07 +02:00
Suppressions : : ErrorMessage errorMsg ;
2018-05-29 16:30:33 +02:00
errorMsg . errorId = " foo " ;
errorMsg . setFileName ( " test.cpp " ) ;
errorMsg . lineNumber = 123 ;
errorMsg . symbolNames = " " ;
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( false , s . isSuppressed ( errorMsg ) ) ;
2018-05-29 16:30:33 +02:00
errorMsg . symbolNames = " x \n " ;
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( false , s . isSuppressed ( errorMsg ) ) ;
2018-05-29 16:30:33 +02:00
errorMsg . symbolNames = " array1 \n " ;
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( true , s . isSuppressed ( errorMsg ) ) ;
2018-05-29 16:30:33 +02:00
errorMsg . symbolNames = " x \n array2 \n " ;
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( true , s . isSuppressed ( errorMsg ) ) ;
2018-05-29 16:30:33 +02:00
errorMsg . symbolNames = " array3 \n x \n " ;
2018-05-29 11:54:07 +02:00
ASSERT_EQUALS ( true , s . isSuppressed ( errorMsg ) ) ;
2018-04-09 06:43:48 +02:00
}
2018-02-06 08:59:36 +01:00
void unusedFunction ( ) {
ASSERT_EQUALS ( 0 , checkSuppression ( " void f() {} " , " unusedFunction " ) ) ;
}
2018-04-09 06:43:48 +02:00
2018-09-08 11:09:49 +02:00
void suppressingSyntaxErrorAndExitCode ( ) {
std : : map < std : : string , std : : string > files ;
files [ " test.cpp " ] = " fi if; " ;
ASSERT_EQUALS ( 0 , checkSuppression ( files , " *:test.cpp " ) ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// multi files, but only suppression one
std : : map < std : : string , std : : string > mfiles ;
mfiles [ " test.cpp " ] = " fi if; " ;
mfiles [ " test2.cpp " ] = " fi if " ;
ASSERT_EQUALS ( 1 , checkSuppression ( mfiles , " *:test.cpp " ) ) ;
ASSERT_EQUALS ( " [test2.cpp:1]: (error) syntax error \n " , errout . str ( ) ) ;
// multi error in file, but only suppression one error
std : : map < std : : string , std : : string > file2 ;
file2 [ " test.cpp " ] = " fi fi \n "
" if if; " ;
ASSERT_EQUALS ( 1 , checkSuppression ( file2 , " *:test.cpp:1 " ) ) ; // suppress all error at line 1 of test.cpp
ASSERT_EQUALS ( " [test.cpp:2]: (error) syntax error \n " , errout . str ( ) ) ;
// multi error in file, but only suppression one error (2)
std : : map < std : : string , std : : string > file3 ;
file3 [ " test.cpp " ] = " void f(int x, int y){ \n "
" int a = x/0; \n "
" int b = y/0; \n "
" } \n "
" f(0, 1); \n " ;
ASSERT_EQUALS ( 1 , checkSuppression ( file3 , " zerodiv:test.cpp:3 " ) ) ; // suppress 'errordiv' at line 3 of test.cpp
2018-09-08 15:19:32 +02:00
}
2018-09-08 11:09:49 +02:00
2011-05-03 12:18:05 +02:00
} ;
REGISTER_TEST ( TestSuppressions )