2011-10-28 22:39:46 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2016-01-01 14:34:45 +01:00
* Copyright ( C ) 2007 - 2016 Cppcheck team .
2011-10-28 22:39:46 +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/>.
*/
2014-05-18 19:48:43 +02:00
# ifdef CHECK_INTERNAL
2011-10-28 22:39:46 +02:00
# include "tokenize.h"
# include "checkinternal.h"
# include "testsuite.h"
class TestInternal : public TestFixture {
public :
2014-11-20 14:20:09 +01:00
TestInternal ( ) : TestFixture ( " TestInternal " ) {
2013-08-07 16:27:37 +02:00
}
2011-10-28 22:39:46 +02:00
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2014-11-20 14:20:09 +01:00
void run ( ) {
2015-10-07 18:33:57 +02:00
settings . addEnabled ( " internal " ) ;
2011-10-28 22:39:46 +02:00
TEST_CASE ( simplePatternInTokenMatch )
TEST_CASE ( complexPatternInTokenSimpleMatch )
TEST_CASE ( simplePatternSquareBrackets )
TEST_CASE ( simplePatternAlternatives )
2012-05-01 14:36:42 +02:00
TEST_CASE ( missingPercentCharacter )
2012-07-11 17:45:16 +02:00
TEST_CASE ( unknownPattern )
2012-09-07 12:36:40 +02:00
TEST_CASE ( redundantNextPrevious )
2015-01-31 12:56:54 +01:00
TEST_CASE ( internalError ) ;
2014-07-02 15:50:49 +02:00
TEST_CASE ( orInComplexPattern ) ;
2014-12-30 14:21:18 +01:00
TEST_CASE ( extraWhitespace ) ;
2017-05-18 15:21:29 +02:00
TEST_CASE ( checkRedundantTokCheck ) ;
2011-10-28 22:39:46 +02:00
}
2014-11-20 14:20:09 +01:00
void check ( const char code [ ] ) {
2011-10-28 22:39:46 +02:00
// Clear the error buffer..
errout . str ( " " ) ;
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
2012-07-16 13:17:14 +02:00
std : : istringstream istr ( code ) ;
2011-10-28 22:39:46 +02:00
tokenizer . tokenize ( istr , " test.cpp " ) ;
2013-12-30 17:45:28 +01:00
tokenizer . simplifyTokenList2 ( ) ;
2011-10-28 22:39:46 +02:00
// Check..
CheckInternal checkInternal ;
checkInternal . runSimplifiedChecks ( & tokenizer , & settings , this ) ;
}
2014-11-20 14:20:09 +01:00
void simplePatternInTokenMatch ( ) {
2011-10-28 22:39:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" ; \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found simple pattern inside Token::Match() call: \" ; \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %type% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-28 19:48:36 +01:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %or% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found simple pattern inside Token::Match() call: \" %or% \" \n " , errout . str ( ) ) ;
2011-10-28 22:39:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findmatch(tok, \" ; \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found simple pattern inside Token::findmatch() call: \" ; \" \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void complexPatternInTokenSimpleMatch ( ) {
2011-10-28 22:39:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" %type% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::simpleMatch() call: \" %type% \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findsimplematch(tok, \" %type% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::findsimplematch() call: \" %type% \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findsimplematch(tok, \" } !!else \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::findsimplematch() call: \" } !!else \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findsimplematch(tok, \" foobar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-18 20:39:52 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findsimplematch(tok, \" % \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-10-28 22:39:46 +02:00
}
2014-11-20 14:20:09 +01:00
void simplePatternSquareBrackets ( ) {
2011-10-28 22:39:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" [ \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" [ ] \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" [] \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::simpleMatch() call: \" [] \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" ] [ \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" ] [ [abc] \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::simpleMatch() call: \" ] [ [abc] \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" [.,;] \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::simpleMatch() call: \" [.,;] \" \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void simplePatternAlternatives ( ) {
2011-10-28 22:39:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" || \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" | \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" a|b \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Found complex pattern inside Token::simpleMatch() call: \" a|b \" \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" |= 0 \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" | 0 ) \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-10-29 12:13:46 +02:00
2014-11-20 14:20:09 +01:00
void missingPercentCharacter ( ) {
2011-10-29 12:13:46 +02:00
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %type% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo %type% bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Missing % at the end of string
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %type \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \" %type \" \n " , errout . str ( ) ) ;
// Missing % in the middle of a pattern
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo %type bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \" foo %type bar \" \n " , errout . str ( ) ) ;
// Bei quiet on single %
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo % %type% bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo % %type % bar \" ); \n "
" } " ) ;
2012-07-11 17:45:16 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \" foo % %type % bar \" \n "
2012-07-21 15:54:04 +02:00
" [test.cpp:3]: (error) Unknown pattern used: \" %type % \" \n " , errout . str ( ) ) ;
2011-10-29 12:13:46 +02:00
// Find missing % also in 'alternatives' pattern
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo|%type|bar \" ); \n "
" } " ) ;
2015-01-31 12:56:54 +01:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Missing percent end character in Token::Match() pattern: \" foo|%type|bar \" \n "
2014-01-05 21:15:41 +01:00
, errout . str ( ) ) ;
2011-10-29 12:13:46 +02:00
// Make sure we don't take %or% for a broken %oror%
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" foo|%oror%|bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2012-05-01 14:36:42 +02:00
2014-11-20 14:20:09 +01:00
void unknownPattern ( ) {
2012-07-11 17:45:16 +02:00
check ( " void f() { \n "
" Token::Match(tok, \" %typ% \" ); \n "
" } " ) ;
2012-07-21 15:54:04 +02:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Unknown pattern used: \" %typ% \" \n " , errout . str ( ) ) ;
2012-07-11 17:45:16 +02:00
// Make sure we don't take %or% for a broken %oror%
check ( " void f() { \n "
" Token::Match(tok, \" %type% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void redundantNextPrevious ( ) {
2012-09-07 12:36:40 +02:00
check ( " void f() { \n "
" return tok->next()->previous(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::next()' followed by 'Token::previous()' can be simplified. \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->tokAt(5)->previous(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::tokAt()' followed by 'Token::previous()' can be simplified. \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->previous()->linkAt(5); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::previous()' followed by 'Token::linkAt()' can be simplified. \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" tok->next()->previous(foo); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->next()->next(); \n " // Simplification won't make code much shorter/readable
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->previous()->previous(); \n " // Simplification won't make code much shorter/readable
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->tokAt(foo+bar)->tokAt(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::tokAt()' followed by 'Token::tokAt()' can be simplified. \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->tokAt(foo+bar)->link(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::tokAt()' followed by 'Token::link()' can be simplified. \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" tok->tokAt(foo+bar)->link(foo); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" return tok->next()->next()->str(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::next()' followed by 'Token::str()' can be simplified. \n " , errout . str ( ) ) ;
2016-08-25 16:09:06 +02:00
check ( " void f() { \n "
" return tok->previous()->next()->str(); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (style) Call to 'Token::previous()' followed by 'Token::next()' can be simplified. \n " , errout . str ( ) ) ;
2012-09-07 12:36:40 +02:00
}
2014-11-20 14:20:09 +01:00
void internalError ( ) {
2012-05-01 14:36:42 +02:00
// Make sure cppcheck does not raise an internal error of Token::Match ( Ticket #3727 )
check ( " class DELPHICLASS X; \n "
" class Y { \n "
" private: \n "
" X* x; \n "
" }; \n "
" class Z { \n "
" char z[1]; \n "
" Z(){ \n "
2012-09-05 19:46:44 +02:00
" z[0] = 0; \n "
2012-05-01 14:36:42 +02:00
" } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-05-01 14:36:42 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-01-05 21:15:41 +01:00
2014-11-20 14:20:09 +01:00
void orInComplexPattern ( ) {
2014-07-02 15:50:49 +02:00
check ( " void f() { \n "
" Token::Match(tok, \" || \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Token::Match() pattern \" || \" contains \" || \" or \" | \" . Replace it by \" %oror% \" or \" %or% \" . \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" Token::Match(tok, \" | \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Token::Match() pattern \" | \" contains \" || \" or \" | \" . Replace it by \" %oror% \" or \" %or% \" . \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" Token::Match(tok, \" [|+-] \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" Token::Match(tok, \" foo | bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Token::Match() pattern \" foo | bar \" contains \" || \" or \" | \" . Replace it by \" %oror% \" or \" %or% \" . \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" Token::Match(tok, \" foo | \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Token::Match() pattern \" foo | \" contains \" || \" or \" | \" . Replace it by \" %oror% \" or \" %or% \" . \n " , errout . str ( ) ) ;
check ( " void f() { \n "
" Token::Match(tok, \" bar foo| \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-12-30 14:21:18 +01:00
void extraWhitespace ( ) {
// whitespace at the end
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %str% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \" %str% \" \n " , errout . str ( ) ) ;
// whitespace at the begin
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %str% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \" %str% \" \n " , errout . str ( ) ) ;
// two whitespaces or more
check ( " void f() { \n "
" const Token *tok; \n "
" Token::Match(tok, \" %str% bar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::Match() call: \" %str% bar \" \n " , errout . str ( ) ) ;
// test simpleMatch
check ( " void f() { \n "
" const Token *tok; \n "
" Token::simpleMatch(tok, \" foobar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::simpleMatch() call: \" foobar \" \n " , errout . str ( ) ) ;
// test findmatch
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findmatch(tok, \" %str% \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::findmatch() call: \" %str% \" \n " , errout . str ( ) ) ;
// test findsimplematch
check ( " void f() { \n "
" const Token *tok; \n "
" Token::findsimplematch(tok, \" foobar \" ); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (warning) Found extra whitespace inside Token::findsimplematch() call: \" foobar \" \n " , errout . str ( ) ) ;
}
2017-05-18 15:21:29 +02:00
void checkRedundantTokCheck ( ) {
// findsimplematch
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok && Token::findsimplematch(tok, \" foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Unneccessary check of \" tok \" , match-function already checks if it is null. \n " , errout . str ( ) ) ;
// findmatch
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok && Token::findmatch(tok, \" %str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Unneccessary check of \" tok \" , match-function already checks if it is null. \n " , errout . str ( ) ) ;
// Match
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok && Token::Match(tok, \" 5str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Unneccessary check of \" tok \" , match-function already checks if it is null. \n " , errout . str ( ) ) ;
// simpleMatch
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok && Token::simpleMatch(tok, \" foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Unneccessary check of \" tok \" , match-function already checks if it is null. \n " , errout . str ( ) ) ;
// Match
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok->previous() && Token::Match(tok->previous(), \" 5str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (style) Unneccessary check of \" tok->previous() \" , match-function already checks if it is null. \n " , errout . str ( ) ) ;
// don't report:
// tok->previous() vs tok
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok->previous() && Token::Match(tok, \" 5str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// tok vs tok->previous())
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok && Token::Match(tok->previous(), \" 5str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// tok->previous() vs tok->previous()->previous())
check ( " void f() { \n "
" const Token *tok; \n "
" if(tok->previous() && Token::Match(tok->previous()->previous(), \" 5str% foobar \" )) {}; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-10-28 22:39:46 +02:00
} ;
REGISTER_TEST ( TestInternal )
2011-10-29 12:47:12 +02:00
2014-05-18 19:48:43 +02:00
# endif // #ifdef CHECK_INTERNAL