diff --git a/Makefile b/Makefile index 0b8329b9d..b9ab3a721 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,18 @@ -SRCS=CheckBufferOverrun.cpp CheckClass.cpp CheckHeaders.cpp CheckMemoryLeak.cpp CheckOther.cpp CommonCheck.cpp FileLister.cpp preprocessor.cpp tokenize.cpp +SRCS=CheckBufferOverrun.cpp CheckClass.cpp CheckHeaders.cpp CheckMemoryLeak.cpp CheckOther.cpp CommonCheck.cpp FileLister.cpp preprocessor.cpp tokenize.cpp cppcheck.cpp settings.cpp OBJS=$(SRCS:%.cpp=%.o) -TESTS=testbufferoverrun.o testcharvar.o testconstructors.o testdivision.o testincompletestatement.o testmemleak.o testpreprocessor.o testtokenize.o testunusedprivfunc.o testunusedvar.o +TESTS=testbufferoverrun.o testcharvar.o testconstructors.o testdivision.o testincompletestatement.o testmemleak.o testpreprocessor.o testtokenize.o testunusedprivfunc.o testunusedvar.o settings.o cppcheck.o BIN = ${DESTDIR}/usr/bin all: ${OBJS} main.o g++ -Wall -g -o cppcheck $^ +test: ${OBJS} testrunner.o testsuite.o ${TESTS} + g++ -Wall -g -o testrunner $^ +cppcheck.o: cppcheck.cpp cppcheck.h preprocessor.h tokenize.h CommonCheck.h CheckMemoryLeak.h CheckBufferOverrun.h CheckClass.h CheckHeaders.h CheckOther.h FileLister.h settings.h + g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp +main.o: main.cpp cppcheck.h + g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp +settings.o: settings.cpp + g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp CheckBufferOverrun.o: CheckBufferOverrun.cpp CheckBufferOverrun.h tokenize.h CommonCheck.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp CheckClass.o: CheckClass.cpp CheckClass.h tokenize.h CommonCheck.h @@ -19,8 +27,6 @@ CommonCheck.o: CommonCheck.cpp CommonCheck.h tokenize.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp FileLister.o: FileLister.cpp FileLister.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp -main.o: main.cpp preprocessor.h tokenize.h CommonCheck.h CheckMemoryLeak.h CheckBufferOverrun.h CheckClass.h CheckHeaders.h CheckOther.h FileLister.h - g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp preprocessor.o: preprocessor.cpp preprocessor.h CommonCheck.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp testbufferoverrun.o: testbufferoverrun.cpp tokenize.h CommonCheck.h CheckBufferOverrun.h testsuite.h @@ -49,8 +55,6 @@ testunusedvar.o: testunusedvar.cpp testsuite.h tokenize.h CheckOther.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp tokenize.o: tokenize.cpp tokenize.h CommonCheck.h g++ -Wall -pedantic -g -I. -o $@ -c $*.cpp -test: ${OBJS} testrunner.o testsuite.o ${TESTS} - g++ -Wall -g -o testrunner $^ clean: rm -f *.o testrunner cppcheck install: cppcheck diff --git a/cppcheck.cpp b/cppcheck.cpp new file mode 100644 index 000000000..bf4317841 --- /dev/null +++ b/cppcheck.cpp @@ -0,0 +1,311 @@ +/* + * c++check - c/c++ syntax checking + * Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi + * + * 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 +#include +#include +#include +#include +#include + + +//--------------------------------------------------------------------------- +bool Debug = false; +bool ShowAll = false; +bool CheckCodingStyle = false; +bool ErrorsOnly = false; +//--------------------------------------------------------------------------- + +CppCheck::CppCheck() +{ + _settings._debug = false; + _settings._showAll = false; + _settings._checkCodingStyle = false; + _settings._errorsOnly = false; +} + +CppCheck::~CppCheck() +{ + +} + +void CppCheck::check(int argc, char* argv[]) +{ + std::vector pathnames; + bool Recursive = false; + + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i],"--debug") == 0) + _settings._debug = true; + + // Show all messages + else if (strcmp(argv[i],"--all") == 0) + _settings._showAll = true; + + // Checking coding style. + else if (strcmp(argv[i],"--style")==0) + _settings._checkCodingStyle = true; + + // Only print something when there are errors + else if (strcmp(argv[i],"--errorsonly")==0) + _settings._errorsOnly = true; + + else if (strcmp(argv[i],"--recursive")==0) + Recursive = true; + else + pathnames.push_back( argv[i] ); + } + + Debug = _settings._debug; + ShowAll = _settings._showAll; + CheckCodingStyle = _settings._checkCodingStyle; + ErrorsOnly = _settings._errorsOnly; + + std::vector filenames; + // --recursive was used + if ( Recursive ) + { + if( pathnames.size() == 0 ) + { + // Handle situation: cppcheck --recursive + FileLister::RecursiveAddFiles( filenames, "", true ); + } + else + { + // Handle situation: cppcheck --recursive path1 path2 + + // Execute RecursiveAddFiles() to each given file parameter + std::vector::const_iterator iter; + for(iter=pathnames.begin(); iter!=pathnames.end(); iter++) + FileLister::RecursiveAddFiles( filenames, iter->c_str(), true ); + } + } + else + { + std::vector::const_iterator iter; + for(iter=pathnames.begin(); iter!=pathnames.end(); iter++) + FileLister::RecursiveAddFiles( filenames, iter->c_str(), false ); + } + + + + if (filenames.empty()) + { + std::cout << "C/C++ code checking.\n" + "\n" + "Syntax:\n" + " cppcheck [--all] [--style] [--errorsonly] [--recursive] [filename1] [filename2]\n" + "\n" + "Options:\n" + " --all Normally a message is only shown if cppcheck is sure\n" + " it has found a bug.\n" + " When this option is given, all messages are shown.\n" + "\n" + " --style Check coding style.\n" + " --errorsonly Only print something when there is an error\n" + " --recursive Recursively check all *.cpp, *.cc and *.c files\n"; + return; + } + + std::sort( filenames.begin(), filenames.end() ); + + for (unsigned int c = 0; c < filenames.size(); c++) + { + errout.str(""); + std::string fname = filenames[c]; + + // If only errors are printed, print filename after the check + if (!_settings._errorsOnly) + std::cout << "Checking " << fname << "...\n"; + + std::ifstream fin( fname.c_str() ); + std::map code; + Preprocessor preprocessor; + preprocessor.preprocess(fin, code, fname); + for ( std::map::const_iterator it = code.begin(); it != code.end(); ++it ) + checkFile(it->second, filenames[c].c_str(), c); + + if (_settings._errorsOnly) + { + if ( !errout.str().empty() ) + { + std::cout << "Errors found in " << fname << ":\n"; + std::cerr << errout.str(); + } + } + else + { + if ( errout.str().empty() ) + std::cout << "No errors found\n"; + else + std::cerr << errout.str(); + } + } + + // This generates false positives - especially for libraries + if ( _settings._showAll && _settings._checkCodingStyle && filenames.size() > 1 ) + { + errout.str(""); + std::cout << "Checking usage of global functions (this may take several minutes)..\n"; + CheckGlobalFunctionUsage(filenames); + if ( ! errout.str().empty() ) + { + std::cerr << "\n"; + std::cerr << errout.str(); + } + } + +} + + +//--------------------------------------------------------------------------- +// CppCheck - A function that checks a specified file +//--------------------------------------------------------------------------- + +void CppCheck::checkFile(const std::string &code, const char FileName[], unsigned int FileId) +{ + Tokenizer tokenizer; + + OnlyReportUniqueErrors = true; + + // Tokenize the file + { + std::istringstream istr(code); + tokenizer.Tokenize(istr, FileName); + } + + FillFunctionList(FileId); + + // Check that the memsets are valid. + // The 'memset' function can do dangerous things if used wrong. + // Important: The checking doesn't work on simplified tokens list. + CheckClass checkClass( &tokenizer ); + checkClass.CheckMemset(); + + + // Check for unsigned divisions where one operand is signed + // Very important to run it before 'SimplifyTokenList' + CheckOther checkOther( &tokenizer ); + checkOther.CheckUnsignedDivision(); + + // Give warning when using char variable as array index + // Doesn't work on simplified token list ('unsigned') + if ( _settings._showAll ) + checkOther.CheckCharVariable(); + + + // Including header which is not needed (too many false positives) +// if ( CheckCodingStyle ) +// { +// CheckHeaders checkHeaders( &tokenizer ); +// checkHeaders.WarningIncludeHeader(); +// } + + + tokenizer.SimplifyTokenList(); + + // Memory leak + CheckMemoryLeakClass checkMemoryLeak( &tokenizer ); + checkMemoryLeak.CheckMemoryLeak(); + + // Buffer overruns.. + CheckBufferOverrunClass checkBufferOverrun( &tokenizer ); + checkBufferOverrun.CheckBufferOverrun(); + + // Check that all class constructors are ok. + checkClass.CheckConstructors(); + + if (_settings._showAll) + { + // Check for "if (a=b)" + checkOther.CheckIfAssignment(); + + // Check for case without break + // Disabled because it generates many false positives + // CheckCaseWithoutBreak(); + + // Dangerous usage of strtok + // Disabled because it generates false positives + //WarningStrTok(); + } + + + + // Dangerous functions, such as 'gets' and 'scanf' + checkBufferOverrun.WarningDangerousFunctions(); + + + // Invalid function usage.. + checkOther.InvalidFunctionUsage(); + + + if (_settings._checkCodingStyle) + { + // Check that all private functions are called. + checkClass.CheckUnusedPrivateFunctions(); + + // Warning upon c-style pointer casts + const char *ext = strrchr(FileName, '.'); + if (ext && strcmp(ext,".cpp")==0) + checkOther.WarningOldStylePointerCast(); + + // Use standard functions instead + checkOther.WarningIsDigit(); + checkOther.WarningIsAlpha(); + + checkClass.CheckOperatorEq1(); + + // if (a) delete a; + checkOther.WarningRedundantCode(); + + // if (condition); + checkOther.WarningIf(); + + // Variable scope (check if the scope could be limited) + //CheckVariableScope(); + + // Check if a constant function parameter is passed by value + checkOther.CheckConstantFunctionParameter(); + + // Unused struct members.. + checkOther.CheckStructMemberUsage(); + + // Check for various types of incomplete statements that could for example + // mean that an ';' has been added by accident + checkOther.CheckIncompleteStatement(); + } + + // Clean up tokens.. + tokenizer.DeallocateTokens(); + +} +//--------------------------------------------------------------------------- + + diff --git a/cppcheck.h b/cppcheck.h new file mode 100644 index 000000000..0478bdb04 --- /dev/null +++ b/cppcheck.h @@ -0,0 +1,42 @@ +/* + * c++check - c/c++ syntax checking + * Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi + * + * 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 +#include "settings.h" + +/** + * This is the base class which will use other classes to do + * static code analysis for C and C++ code to find possible + * errors or places that could be improved. + */ +class CppCheck +{ + public: + CppCheck(); + virtual ~CppCheck(); + void check(int argc, char* argv[]); + + private: + void checkFile(const std::string &code, const char FileName[], unsigned int FileId); + Settings _settings; +}; + +#endif // CPPCHECK_H diff --git a/main.cpp b/main.cpp index 3e8ab3a08..ea51c5cfa 100644 --- a/main.cpp +++ b/main.cpp @@ -17,32 +17,7 @@ */ -#include "preprocessor.h" // preprocessor. -#include "tokenize.h" // <- Tokenizer -#include "CommonCheck.h" -#include "CheckMemoryLeak.h" -#include "CheckBufferOverrun.h" -#include "CheckClass.h" -#include "CheckHeaders.h" -#include "CheckOther.h" -#include "FileLister.h" - -#include -#include -#include -#include -#include -#include - -//--------------------------------------------------------------------------- -bool Debug = false; -bool ShowAll = false; -bool CheckCodingStyle = false; -bool ErrorsOnly = false; -//--------------------------------------------------------------------------- - -static void CppCheck(const std::string &code, const char FileName[], unsigned int FileId); - +#include "cppcheck.h" //--------------------------------------------------------------------------- // Main function of cppcheck @@ -50,252 +25,9 @@ static void CppCheck(const std::string &code, const char FileName[], unsigned in int main(int argc, char* argv[]) { - std::vector pathnames; - bool Recursive = false; - - for (int i = 1; i < argc; i++) - { - if (strcmp(argv[i],"--debug") == 0) - Debug = true; - - // Show all messages - else if (strcmp(argv[i],"--all") == 0) - ShowAll = true; - - // Checking coding style. - else if (strcmp(argv[i],"--style")==0) - CheckCodingStyle = true; - - // Only print something when there are errors - else if (strcmp(argv[i],"--errorsonly")==0) - ErrorsOnly = true; - - else if (strcmp(argv[i],"--recursive")==0) - Recursive = true; - else - pathnames.push_back( argv[i] ); - } - - std::vector filenames; - // --recursive was used - if ( Recursive ) - { - if( pathnames.size() == 0 ) - { - // Handle situation: cppcheck --recursive - FileLister::RecursiveAddFiles( filenames, "", true ); - } - else - { - // Handle situation: cppcheck --recursive path1 path2 - - // Execute RecursiveAddFiles() to each given file parameter - std::vector::const_iterator iter; - for(iter=pathnames.begin(); iter!=pathnames.end(); iter++) - FileLister::RecursiveAddFiles( filenames, iter->c_str(), true ); - } - } - else - { - std::vector::const_iterator iter; - for(iter=pathnames.begin(); iter!=pathnames.end(); iter++) - FileLister::RecursiveAddFiles( filenames, iter->c_str(), false ); - } - - - - if (filenames.empty()) - { - std::cout << "C/C++ code checking.\n" - "\n" - "Syntax:\n" - " cppcheck [--all] [--style] [--errorsonly] [--recursive] [filename1] [filename2]\n" - "\n" - "Options:\n" - " --all Normally a message is only shown if cppcheck is sure\n" - " it has found a bug.\n" - " When this option is given, all messages are shown.\n" - "\n" - " --style Check coding style.\n" - " --errorsonly Only print something when there is an error\n" - " --recursive Recursively check all *.cpp, *.cc and *.c files\n"; - return 0; - } - - std::sort( filenames.begin(), filenames.end() ); - - for (unsigned int c = 0; c < filenames.size(); c++) - { - errout.str(""); - std::string fname = filenames[c]; - - // If only errors are printed, print filename after the check - if (!ErrorsOnly) - std::cout << "Checking " << fname << "...\n"; - - std::ifstream fin( fname.c_str() ); - std::map code; - Preprocessor preprocessor; - preprocessor.preprocess(fin, code, fname); - for ( std::map::const_iterator it = code.begin(); it != code.end(); ++it ) - CppCheck(it->second, filenames[c].c_str(), c); - - if (ErrorsOnly) - { - if ( !errout.str().empty() ) - { - std::cout << "Errors found in " << fname << ":\n"; - std::cerr << errout.str(); - } - } - else - { - if ( errout.str().empty() ) - std::cout << "No errors found\n"; - else - std::cerr << errout.str(); - } - } - - // This generates false positives - especially for libraries - if ( ShowAll && CheckCodingStyle && filenames.size() > 1 ) - { - errout.str(""); - std::cout << "Checking usage of global functions (this may take several minutes)..\n"; - CheckGlobalFunctionUsage(filenames); - if ( ! errout.str().empty() ) - { - std::cerr << "\n"; - std::cerr << errout.str(); - } - } - + CppCheck cppCheck; + cppCheck.check( argc, argv ); return 0; } -//--------------------------------------------------------------------------- -// CppCheck - A function that checks a specified file -//--------------------------------------------------------------------------- - -static void CppCheck(const std::string &code, const char FileName[], unsigned int FileId) -{ - Tokenizer tokenizer; - - OnlyReportUniqueErrors = true; - - // Tokenize the file - { - std::istringstream istr(code); - tokenizer.Tokenize(istr, FileName); - } - - FillFunctionList(FileId); - - // Check that the memsets are valid. - // The 'memset' function can do dangerous things if used wrong. - // Important: The checking doesn't work on simplified tokens list. - CheckClass checkClass( &tokenizer ); - checkClass.CheckMemset(); - - - // Check for unsigned divisions where one operand is signed - // Very important to run it before 'SimplifyTokenList' - CheckOther checkOther( &tokenizer ); - checkOther.CheckUnsignedDivision(); - - // Give warning when using char variable as array index - // Doesn't work on simplified token list ('unsigned') - if ( ShowAll ) - checkOther.CheckCharVariable(); - - - // Including header which is not needed (too many false positives) -// if ( CheckCodingStyle ) -// { -// CheckHeaders checkHeaders( &tokenizer ); -// checkHeaders.WarningIncludeHeader(); -// } - - - tokenizer.SimplifyTokenList(); - - // Memory leak - CheckMemoryLeakClass checkMemoryLeak( &tokenizer ); - checkMemoryLeak.CheckMemoryLeak(); - - // Buffer overruns.. - CheckBufferOverrunClass checkBufferOverrun( &tokenizer ); - checkBufferOverrun.CheckBufferOverrun(); - - // Check that all class constructors are ok. - checkClass.CheckConstructors(); - - if (ShowAll) - { - // Check for "if (a=b)" - checkOther.CheckIfAssignment(); - - // Check for case without break - // Disabled because it generates many false positives - // CheckCaseWithoutBreak(); - - // Dangerous usage of strtok - // Disabled because it generates false positives - //WarningStrTok(); - } - - - - // Dangerous functions, such as 'gets' and 'scanf' - checkBufferOverrun.WarningDangerousFunctions(); - - - // Invalid function usage.. - checkOther.InvalidFunctionUsage(); - - - if (CheckCodingStyle) - { - // Check that all private functions are called. - checkClass.CheckUnusedPrivateFunctions(); - - // Warning upon c-style pointer casts - const char *ext = strrchr(FileName, '.'); - if (ext && strcmp(ext,".cpp")==0) - checkOther.WarningOldStylePointerCast(); - - // Use standard functions instead - checkOther.WarningIsDigit(); - checkOther.WarningIsAlpha(); - - checkClass.CheckOperatorEq1(); - - // if (a) delete a; - checkOther.WarningRedundantCode(); - - // if (condition); - checkOther.WarningIf(); - - // Variable scope (check if the scope could be limited) - //CheckVariableScope(); - - // Check if a constant function parameter is passed by value - checkOther.CheckConstantFunctionParameter(); - - // Unused struct members.. - checkOther.CheckStructMemberUsage(); - - // Check for various types of incomplete statements that could for example - // mean that an ';' has been added by accident - checkOther.CheckIncompleteStatement(); - } - - // Clean up tokens.. - tokenizer.DeallocateTokens(); - -} -//--------------------------------------------------------------------------- - - - diff --git a/settings.cpp b/settings.cpp new file mode 100644 index 000000000..689502e9c --- /dev/null +++ b/settings.cpp @@ -0,0 +1,32 @@ +/* + * c++check - c/c++ syntax checking + * Copyright (C) 2007-2008 Daniel Marjamäki and Reijo Tomperi + * + * 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 #include - - -bool ShowAll = false; -bool CheckCodingStyle = true; + +extern bool ShowAll; +extern bool CheckCodingStyle; int main(int argc, const char *argv[]) -{ +{ + ShowAll = false; + CheckCodingStyle = true; TestFixture::runTests( (argc==2) ? argv[1] : NULL ); return 0; }